/*-------------------------------------------------------------------------
 * 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 Negative Shader API tests.
 *//*--------------------------------------------------------------------*/

#include "es31fNegativeShaderApiTests.hpp"

#include "deUniquePtr.hpp"

#include "glwDefs.hpp"
#include "glwEnums.hpp"

#include "gluShaderProgram.hpp"
#include "gluCallLogWrapper.hpp"

#include "gluContextInfo.hpp"
#include "gluRenderContext.hpp"


namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace NegativeTestShared
{
using tcu::TestLog;
using glu::CallLogWrapper;
using namespace glw;

static const char* vertexShaderSource		=	"#version 300 es\n"
												"void main (void)\n"
												"{\n"
												"	gl_Position = vec4(0.0);\n"
												"}\n\0";

static const char* fragmentShaderSource		=	"#version 300 es\n"
												"layout(location = 0) out mediump vec4 fragColor;"
												"void main (void)\n"
												"{\n"
												"	fragColor = vec4(0.0);\n"
												"}\n\0";

static const char* uniformTestVertSource	=	"#version 300 es\n"
												"uniform mediump vec4 vec4_v;\n"
												"uniform mediump mat4 mat4_v;\n"
												"void main (void)\n"
												"{\n"
												"	gl_Position = mat4_v * vec4_v;\n"
												"}\n\0";

static const char* uniformTestFragSource	=	"#version 300 es\n"
												"uniform mediump ivec4 ivec4_f;\n"
												"uniform mediump uvec4 uvec4_f;\n"
												"uniform sampler2D sampler_f;\n"
												"layout(location = 0) out mediump vec4 fragColor;"
												"void main (void)\n"
												"{\n"
												"	fragColor.xy = (vec4(uvec4_f) + vec4(ivec4_f)).xy;\n"
												"	fragColor.zw = texture(sampler_f, vec2(0.0, 0.0)).zw;\n"
												"}\n\0";

static const char* uniformBlockVertSource	=	"#version 300 es\n"
												"layout(shared) uniform Block { lowp float var; };\n"
												"void main (void)\n"
												"{\n"
												"	gl_Position = vec4(var);\n"
												"}\n\0";


// Shader control commands
void create_shader (NegativeTestContext& ctx)
{
	ctx.beginSection("GL_INVALID_ENUM is generated if shaderType is not an accepted value.");
	ctx.glCreateShader(-1);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();
}

void shader_source (NegativeTestContext& ctx)
{
	// make notAShader not a shader id
	const GLuint notAShader = ctx.glCreateShader(GL_VERTEX_SHADER);
	ctx.glDeleteShader(notAShader);

	ctx.beginSection("GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL.");
	ctx.glShaderSource(notAShader, 0, 0, 0);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if count is less than 0.");
	GLuint shader = ctx.glCreateShader(GL_VERTEX_SHADER);
	ctx.glShaderSource(shader, -1, 0, 0);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if shader is not a shader object.");
	GLuint program = ctx.glCreateProgram();
	ctx.glShaderSource(program, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glDeleteProgram(program);
	ctx.glDeleteShader(shader);
}

void compile_shader (NegativeTestContext& ctx)
{
	const GLuint notAShader = ctx.glCreateShader(GL_VERTEX_SHADER);
	ctx.glDeleteShader(notAShader);

	ctx.beginSection("GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL.");
	ctx.glCompileShader(notAShader);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if shader is not a shader object.");
	GLuint program = ctx.glCreateProgram();
	ctx.glCompileShader(program);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glDeleteProgram(program);
}

void delete_shader (NegativeTestContext& ctx)
{
	const GLuint notAShader = ctx.glCreateShader(GL_VERTEX_SHADER);
	ctx.glDeleteShader(notAShader);

	ctx.beginSection("GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL.");
	ctx.glDeleteShader(notAShader);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();
}

void shader_binary (NegativeTestContext& ctx)
{
	std::vector<deInt32> binaryFormats;
	deBool shaderBinarySupported = !binaryFormats.empty();
	GLuint shaders[2];
	GLuint shaderPair[2];
	GLuint nonProgram[2];
	GLuint shaderProgram[2];

	{
		deInt32 numFormats = 0x1234;
		ctx.glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &numFormats);

		if (numFormats == 0)
			ctx.getLog() << TestLog::Message << "// No supported extensions available." << TestLog::EndMessage;
		else
		{
			binaryFormats.resize(numFormats);
			ctx.glGetIntegerv(GL_SHADER_BINARY_FORMATS, &binaryFormats[0]);
		}
	}

	if (!shaderBinarySupported)
		ctx.getLog() << TestLog::Message << "// Shader binaries not supported." << TestLog::EndMessage;
	else
		ctx.getLog() << TestLog::Message << "// Shader binaries supported" << TestLog::EndMessage;

	shaders[0]			= ctx.glCreateShader(GL_VERTEX_SHADER);
	shaders[1]			= ctx.glCreateShader(GL_VERTEX_SHADER);
	shaderPair[0]		= ctx.glCreateShader(GL_VERTEX_SHADER);
	shaderPair[1]		= ctx.glCreateShader(GL_FRAGMENT_SHADER);
	nonProgram[0]		= -1;
	nonProgram[1]		= -1;
	shaderProgram[0]	= ctx.glCreateShader(GL_VERTEX_SHADER);
	shaderProgram[1]	= ctx.glCreateProgram();

	ctx.beginSection("GL_INVALID_ENUM is generated if binaryFormat is not an accepted value.");
	ctx.glShaderBinary(1, &shaders[0], -1, 0, 0);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();

	if (shaderBinarySupported)
	{
		ctx.beginSection("GL_INVALID_VALUE is generated if the data pointed to by binary does not match the format specified by binaryFormat.");
		const GLbyte data = 0x005F;
		ctx.glShaderBinary(1, &shaders[0], binaryFormats[0], &data, 1);
		ctx.expectError(GL_INVALID_VALUE);
		ctx.endSection();

		ctx.beginSection("GL_INVALID_OPERATION is generated if more than one of the handles in shaders refers to the same type of shader, or GL_INVALID_VALUE due to invalid data pointer.");
		ctx.glShaderBinary(2, &shaders[0], binaryFormats[0], 0, 0);
		ctx.expectError(GL_INVALID_OPERATION, GL_INVALID_VALUE);
		ctx.endSection();

		ctx.beginSection("GL_INVALID_VALUE is generated if count or length is negative.");
		ctx.glShaderBinary(2, &shaderPair[0], binaryFormats[0], 0, -1);
		ctx.expectError(GL_INVALID_VALUE);
		ctx.glShaderBinary(-1, &shaderPair[0], binaryFormats[0], 0, 0);
		ctx.expectError(GL_INVALID_VALUE);
		ctx.endSection();

		ctx.beginSection("GL_INVALID_VALUE is generated if shaders contains anything other than shader or program objects.");
		ctx.glShaderBinary(2, &nonProgram[0], binaryFormats[0], 0, 0);
		ctx.expectError(GL_INVALID_VALUE);
		ctx.endSection();

		ctx.beginSection("GL_INVALID_OPERATION is generated if shaders refers to a program object.");
		ctx.glShaderBinary(2, &shaderProgram[0], binaryFormats[0], 0, 0);
		ctx.expectError(GL_INVALID_OPERATION);
		ctx.endSection();
	}

	ctx.glDeleteShader(shaders[0]);
	ctx.glDeleteShader(shaders[1]);
}

void attach_shader (NegativeTestContext& ctx)
{
	GLuint shader1 = ctx.glCreateShader(GL_VERTEX_SHADER);
	GLuint shader2 = ctx.glCreateShader(GL_VERTEX_SHADER);
	GLuint program = ctx.glCreateProgram();

	const GLuint notAShader = ctx.glCreateShader(GL_VERTEX_SHADER);
	const GLuint notAProgram = ctx.glCreateProgram();

	ctx.glDeleteShader(notAShader);
	ctx.glDeleteProgram(notAProgram);

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is not a program object.");
	ctx.glAttachShader(shader1, shader1);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if shader is not a shader object.");
	ctx.glAttachShader(program, program);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glAttachShader(shader1, program);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if either program or shader is not a value generated by OpenGL.");
	ctx.glAttachShader(program, notAShader);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.glAttachShader(notAProgram, shader1);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.glAttachShader(notAProgram, notAShader);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if shader is already attached to program.");
	ctx.glAttachShader(program, shader1);
	ctx.expectError(GL_NO_ERROR);
	ctx.glAttachShader(program, shader1);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if a shader of the same type as shader is already attached to program.");
	ctx.glAttachShader(program, shader2);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glDeleteProgram(program);
	ctx.glDeleteShader(shader1);
	ctx.glDeleteShader(shader2);
}

void detach_shader (NegativeTestContext& ctx)
{
	GLuint shader = ctx.glCreateShader(GL_VERTEX_SHADER);
	GLuint program = ctx.glCreateProgram();

	const GLuint notAShader = ctx.glCreateShader(GL_VERTEX_SHADER);
	const GLuint notAProgram = ctx.glCreateProgram();

	ctx.glDeleteShader(notAShader);
	ctx.glDeleteProgram(notAProgram);

	ctx.beginSection("GL_INVALID_VALUE is generated if either program or shader is not a value generated by OpenGL.");
	ctx.glDetachShader(notAProgram, shader);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.glDetachShader(program, notAShader);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.glDetachShader(notAProgram, notAShader);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is not a program object.");
	ctx.glDetachShader(shader, shader);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if shader is not a shader object.");
	ctx.glDetachShader(program, program);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glDetachShader(shader, program);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if shader is not attached to program.");
	ctx.glDetachShader(program, shader);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glDeleteProgram(program);
	ctx.glDeleteShader(shader);
}

void link_program (NegativeTestContext& ctx)
{
	GLuint shader = ctx.glCreateShader(GL_VERTEX_SHADER);

	const GLuint notAProgram = ctx.glCreateProgram();
	ctx.glDeleteProgram(notAProgram);

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not a value generated by OpenGL.");
	ctx.glLinkProgram(notAProgram);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is not a program object.");
	ctx.glLinkProgram(shader);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glDeleteShader(shader);

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is the currently active program object and transform feedback mode is active.");
	glu::ShaderProgram			program(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	deUint32					buf = 0x1234;
	deUint32					tfID = 0x1234;
	const char* tfVarying		= "gl_Position";

	ctx.glGenTransformFeedbacks		(1, &tfID);
	ctx.glGenBuffers				(1, &buf);

	ctx.glUseProgram				(program.getProgram());
	ctx.glTransformFeedbackVaryings	(program.getProgram(), 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.glLinkProgram				(program.getProgram());
	ctx.glBindTransformFeedback		(GL_TRANSFORM_FEEDBACK, tfID);
	ctx.glBindBuffer				(GL_TRANSFORM_FEEDBACK_BUFFER, buf);
	ctx.glBufferData				(GL_TRANSFORM_FEEDBACK_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
	ctx.glBindBufferBase			(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.expectError					(GL_NO_ERROR);

	ctx.glLinkProgram				(program.getProgram());
	ctx.expectError				(GL_INVALID_OPERATION);

	ctx.glEndTransformFeedback		();
	ctx.glDeleteTransformFeedbacks	(1, &tfID);
	ctx.glDeleteBuffers				(1, &buf);
	ctx.expectError				(GL_NO_ERROR);
	ctx.endSection();
}

void use_program (NegativeTestContext& ctx)
{
	GLuint shader = ctx.glCreateShader(GL_VERTEX_SHADER);

	const GLuint notAProgram = ctx.glCreateProgram();
	ctx.glDeleteProgram(notAProgram);

	ctx.beginSection("GL_INVALID_VALUE is generated if program is neither 0 nor a value generated by OpenGL.");
	ctx.glUseProgram(notAProgram);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is not a program object.");
	ctx.glUseProgram(shader);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if transform feedback mode is active and not paused.");
	glu::ShaderProgram			program1(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	glu::ShaderProgram			program2(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	deUint32					buf = 0x1234;
	deUint32					tfID = 0x1234;
	const char* tfVarying		= "gl_Position";

	ctx.glGenTransformFeedbacks		(1, &tfID);
	ctx.glGenBuffers				(1, &buf);

	ctx.glUseProgram				(program1.getProgram());
	ctx.glTransformFeedbackVaryings	(program1.getProgram(), 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.glLinkProgram				(program1.getProgram());
	ctx.glBindTransformFeedback		(GL_TRANSFORM_FEEDBACK, tfID);
	ctx.glBindBuffer				(GL_TRANSFORM_FEEDBACK_BUFFER, buf);
	ctx.glBufferData				(GL_TRANSFORM_FEEDBACK_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
	ctx.glBindBufferBase			(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.expectError					(GL_NO_ERROR);

	ctx.glUseProgram				(program2.getProgram());
	ctx.expectError				(GL_INVALID_OPERATION);

	ctx.glPauseTransformFeedback	();
	ctx.glUseProgram				(program2.getProgram());
	ctx.expectError				(GL_NO_ERROR);

	ctx.glEndTransformFeedback		();
	ctx.glDeleteTransformFeedbacks	(1, &tfID);
	ctx.glDeleteBuffers				(1, &buf);
	ctx.expectError				(GL_NO_ERROR);
	ctx.endSection();

	ctx.glUseProgram(0);
	ctx.glDeleteShader(shader);
}

void delete_program (NegativeTestContext& ctx)
{
	GLuint shader = ctx.glCreateShader(GL_VERTEX_SHADER);

	const GLuint notAProgram = ctx.glCreateProgram();
	ctx.glDeleteProgram(notAProgram);

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not a value generated by OpenGL.");
	ctx.glDeleteProgram(notAProgram);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is not zero and is the name of a shader object.");
	ctx.glDeleteProgram(shader);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glDeleteShader(shader);
}

void validate_program (NegativeTestContext& ctx)
{
	GLuint shader = ctx.glCreateShader(GL_VERTEX_SHADER);

	const GLuint notAProgram = ctx.glCreateProgram();
	ctx.glDeleteProgram(notAProgram);

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not a value generated by OpenGL.");
	ctx.glValidateProgram(notAProgram);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is not a program object.");
	ctx.glValidateProgram(shader);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glDeleteShader(shader);
}

void get_program_binary (NegativeTestContext& ctx)
{
	glu::ShaderProgram				program			(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	glu::ShaderProgram				programInvalid	(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, ""));
	GLenum							binaryFormat	= -1;
	GLsizei							binaryLength	= -1;
	GLint							binaryPtr		= -1;
	GLint							bufSize			= -1;
	GLint							linkStatus		= -1;

	ctx.beginSection("GL_INVALID_OPERATION is generated if bufSize is less than the size of GL_PROGRAM_BINARY_LENGTH for program.");
	ctx.glGetProgramiv		(program.getProgram(), GL_PROGRAM_BINARY_LENGTH,	&bufSize);
	ctx.expectError		(GL_NO_ERROR);
	ctx.glGetProgramiv		(program.getProgram(), GL_LINK_STATUS,				&linkStatus);
	ctx.getLog() << TestLog::Message << "// GL_PROGRAM_BINARY_LENGTH = " << bufSize << TestLog::EndMessage;
	ctx.getLog() << TestLog::Message << "// GL_LINK_STATUS = " << linkStatus << TestLog::EndMessage;
	ctx.expectError		(GL_NO_ERROR);

	ctx.glGetProgramBinary	(program.getProgram(), 0, &binaryLength, &binaryFormat, &binaryPtr);
	ctx.expectError		(GL_INVALID_OPERATION);
	if (bufSize > 0)
	{
		ctx.glGetProgramBinary	(program.getProgram(), bufSize-1, &binaryLength, &binaryFormat, &binaryPtr);
		ctx.expectError		(GL_INVALID_OPERATION);
	}
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if GL_LINK_STATUS for the program object is false.");
	ctx.glGetProgramiv		(programInvalid.getProgram(), GL_PROGRAM_BINARY_LENGTH,	&bufSize);
	ctx.expectError		(GL_NO_ERROR);
	ctx.glGetProgramiv		(programInvalid.getProgram(), GL_LINK_STATUS,			&linkStatus);
	ctx.getLog() << TestLog::Message << "// GL_PROGRAM_BINARY_LENGTH = " << bufSize << TestLog::EndMessage;
	ctx.getLog() << TestLog::Message << "// GL_LINK_STATUS = " << linkStatus << TestLog::EndMessage;
	ctx.expectError		(GL_NO_ERROR);

	ctx.glGetProgramBinary	(programInvalid.getProgram(), bufSize, &binaryLength, &binaryFormat, &binaryPtr);
	ctx.expectError		(GL_INVALID_OPERATION);
	ctx.endSection();
}

void program_binary (NegativeTestContext& ctx)
{
	glu::ShaderProgram		srcProgram		(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	GLuint					dstProgram		= ctx.glCreateProgram();
	GLuint					dummyShader		= ctx.glCreateShader(GL_VERTEX_SHADER);
	GLenum					binaryFormat	= -1;
	GLsizei					binaryLength	= -1;
	std::vector<deUint8>	binaryBuf;
	GLint					bufSize			= -1;
	GLint					linkStatus		= -1;

	ctx.glGetProgramiv		(srcProgram.getProgram(), GL_PROGRAM_BINARY_LENGTH,	&bufSize);
	ctx.glGetProgramiv		(srcProgram.getProgram(), GL_LINK_STATUS,			&linkStatus);
	ctx.getLog() << TestLog::Message << "// GL_PROGRAM_BINARY_LENGTH = " << bufSize << TestLog::EndMessage;
	ctx.getLog() << TestLog::Message << "// GL_LINK_STATUS = " << linkStatus << TestLog::EndMessage;

	TCU_CHECK(bufSize >= 0);
	if (bufSize > 0)
	{
		binaryBuf.resize(bufSize);
		ctx.glGetProgramBinary	(srcProgram.getProgram(), bufSize, &binaryLength, &binaryFormat, &binaryBuf[0]);
		ctx.expectError			(GL_NO_ERROR);

		ctx.beginSection("GL_INVALID_OPERATION is generated if program is not the name of an existing program object.");
		ctx.glProgramBinary		(dummyShader, binaryFormat, &binaryBuf[0], binaryLength);
		ctx.expectError			(GL_INVALID_OPERATION);
		ctx.endSection();

		ctx.beginSection("GL_INVALID_ENUM is generated if binaryFormat is not a value recognized by the implementation.");
		ctx.glProgramBinary		(dstProgram, -1, &binaryBuf[0], binaryLength);
		ctx.expectError			(GL_INVALID_ENUM);
		ctx.endSection();
	}

	ctx.glDeleteShader(dummyShader);
	ctx.glDeleteProgram(dstProgram);
}

void program_parameteri (NegativeTestContext& ctx)
{
	GLuint program	= ctx.glCreateProgram();
	GLuint shader	= ctx.glCreateShader(GL_VERTEX_SHADER);

	const GLuint notAProgram = ctx.glCreateProgram();
	ctx.glDeleteProgram(notAProgram);

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not the name of an existing program object.");
	ctx.glProgramParameteri(notAProgram, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is the name of a shader object.");
	ctx.glProgramParameteri(shader, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if pname is not GL_PROGRAM_BINARY_RETRIEVABLE_HINT or PROGRAM_SEPARABLE.");
	ctx.glProgramParameteri(program, -1, GL_TRUE);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if value is not GL_FALSE or GL_TRUE.");
	ctx.glProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, 2);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.glDeleteProgram(program);
	ctx.glDeleteShader(shader);
}

void gen_samplers (NegativeTestContext& ctx)
{
	ctx.beginSection("GL_INVALID_VALUE is generated if n is negative.");
	GLuint sampler = 0;
	ctx.glGenSamplers	(-1, &sampler);
	ctx.expectError	(GL_INVALID_VALUE);
	ctx.endSection();
}

void bind_sampler (NegativeTestContext& ctx)
{
	int				maxTexImageUnits = 0x1234;
	GLuint			sampler = 0;
	ctx.glGetIntegerv	(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTexImageUnits);
	ctx.glGenSamplers	(1, &sampler);

	ctx.beginSection("GL_INVALID_VALUE is generated if unit is greater than or equal to the value of GL_MAX_COMBIED_TEXTURE_IMAGE_UNITS.");
	ctx.glBindSampler	(maxTexImageUnits, sampler);
	ctx.expectError	(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not zero or a name previously returned from a call to ctx.glGenSamplers.");
	ctx.glBindSampler	(1, -1);
	ctx.expectError	(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler has been deleted by a call to ctx.glDeleteSamplers.");
	ctx.glDeleteSamplers(1, &sampler);
	ctx.glBindSampler	(1, sampler);
	ctx.expectError	(GL_INVALID_OPERATION);
	ctx.endSection();
}

void delete_samplers (NegativeTestContext& ctx)
{
	ctx.beginSection("GL_INVALID_VALUE is generated if n is negative.");
	ctx.glDeleteSamplers(-1, 0);
	ctx.expectError	(GL_INVALID_VALUE);
	ctx.endSection();
}

void get_sampler_parameteriv (NegativeTestContext& ctx)
{
	int				params = 0x1234;
	GLuint			sampler = 0;
	ctx.glGenSamplers	(1, &sampler);

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object returned from a previous call to ctx.glGenSamplers.");
	ctx.glGetSamplerParameteriv	(-1, GL_TEXTURE_MAG_FILTER, &params);
	ctx.expectError			(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if pname is not an accepted value.");
	ctx.glGetSamplerParameteriv	(sampler, -1, &params);
	ctx.expectError			(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.glDeleteSamplers(1, &sampler);
}

void get_sampler_parameterfv (NegativeTestContext& ctx)
{
	float				params	= 0.0f;
	GLuint				sampler = 0;
	ctx.glGenSamplers	(1, &sampler);

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object returned from a previous call to ctx.glGenSamplers.");
	ctx.glGetSamplerParameterfv	(-1, GL_TEXTURE_MAG_FILTER, &params);
	ctx.expectError			(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if pname is not an accepted value.");
	ctx.glGetSamplerParameterfv	(sampler, -1, &params);
	ctx.expectError			(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.glDeleteSamplers(1, &sampler);
}

void get_sampler_parameterIiv (NegativeTestContext& ctx)
{
	if (!contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)))
		throw tcu::NotSupportedError("glGetSamplerParameterIiv is not supported.", DE_NULL, __FILE__, __LINE__);

	GLuint	sampler		= 0x1234;
	GLint	borderColor	= 0x1234;

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object returned from a previous call to ctx.glGenSamplers.");
	ctx.glGetSamplerParameterIiv(sampler, GL_TEXTURE_BORDER_COLOR, &borderColor);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glGenSamplers(1, &sampler);

	ctx.beginSection("GL_INVALID_ENUM is generated if pname is not an accepted value.");
	ctx.glGetSamplerParameterIiv(sampler, -1, &borderColor);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.glDeleteSamplers(1, &sampler);
}

void get_sampler_parameterIuiv (NegativeTestContext& ctx)
{
	if (!contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)))
		throw tcu::NotSupportedError("glGetSamplerParameterIuiv is not supported.", DE_NULL, __FILE__, __LINE__);

	GLuint	sampler		= 0x1234;
	GLuint	borderColor	= 0x1234;

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object returned from a previous call to ctx.glGenSamplers.");
	ctx.glGetSamplerParameterIuiv(sampler, GL_TEXTURE_BORDER_COLOR, &borderColor);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glGenSamplers(1, &sampler);

	ctx.beginSection("GL_INVALID_ENUM is generated if pname is not an accepted value.");
	ctx.glGetSamplerParameterIuiv(sampler, -1, &borderColor);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.glDeleteSamplers(1, &sampler);
}

void sampler_parameteri (NegativeTestContext& ctx)
{
	GLuint sampler = 0;

	ctx.glGenSamplers(1, &sampler);

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object previously returned from a call to ctx.glGenSamplers.");
	ctx.glSamplerParameteri(-1, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if params should have a defined constant value (based on the value of pname) and does not.");
	ctx.glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, -1);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();

	if (contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)))
	{
		ctx.beginSection("GL_INVALID_ENUM is generated if glSamplerParameteri is called for a non-scalar parameter.");
		ctx.glSamplerParameteri(sampler, GL_TEXTURE_BORDER_COLOR, 0);
		ctx.expectError(GL_INVALID_ENUM);
		ctx.endSection();
	}

	ctx.glDeleteSamplers(1, &sampler);
}

void sampler_parameteriv (NegativeTestContext& ctx)
{
	int				params = 0x1234;
	GLuint			sampler = 0;
	ctx.glGenSamplers	(1, &sampler);

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object previously returned from a call to ctx.glGenSamplers.");
	params = GL_CLAMP_TO_EDGE;
	ctx.glSamplerParameteriv	(-1, GL_TEXTURE_WRAP_S, &params);
	ctx.expectError			(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if params should have a defined constant value (based on the value of pname) and does not.");
	params = -1;
	ctx.glSamplerParameteriv	(sampler, GL_TEXTURE_WRAP_S, &params);
	ctx.expectError			(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.glDeleteSamplers(1, &sampler);
}

void sampler_parameterf (NegativeTestContext& ctx)
{
	GLuint sampler = 0;

	ctx.glGenSamplers(1, &sampler);

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object previously returned from a call to ctx.glGenSamplers.");
	ctx.glSamplerParameterf(-1, GL_TEXTURE_MIN_LOD, -1000.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if params should have a defined constant value (based on the value of pname) and does not.");
	ctx.glSamplerParameterf(sampler, GL_TEXTURE_WRAP_S, -1.0f);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();

	if (contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)))
	{
		ctx.beginSection("GL_INVALID_ENUM is generated if glSamplerParameterf is called for a non-scalar parameter.");
		ctx.glSamplerParameteri(sampler, GL_TEXTURE_BORDER_COLOR, 0);
		ctx.expectError(GL_INVALID_ENUM);
		ctx.endSection();
	}

	ctx.glDeleteSamplers(1, &sampler);
}

void sampler_parameterfv (NegativeTestContext& ctx)
{
	float			params;
	GLuint			sampler = 0;
	ctx.glGenSamplers	(1, &sampler);

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object previously returned from a call to ctx.glGenSamplers.");
	params = -1000.0f;
	ctx.glSamplerParameterfv	(-1, GL_TEXTURE_WRAP_S, &params);
	ctx.expectError			(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if params should have a defined constant value (based on the value of pname) and does not.");
	params = -1.0f;
	ctx.glSamplerParameterfv	(sampler, GL_TEXTURE_WRAP_S, &params);
	ctx.expectError			(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.glDeleteSamplers(1, &sampler);
}

void sampler_parameterIiv (NegativeTestContext& ctx)
{
	if (!contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)))
		throw tcu::NotSupportedError("glSamplerParameterIiv is not supported.", DE_NULL, __FILE__, __LINE__);

	GLuint	sampler;
	GLint	color[]	= {0, 0, 0, 0};

	ctx.glGenSamplers(1, &sampler);

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object previously returned from a call to ctx.glGenSamplers.");
	ctx.glSamplerParameterIiv(-1, GL_TEXTURE_BORDER_COLOR, color);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if pname is not an accepted sampler state name.");
	ctx.glSamplerParameterIiv(sampler, -1, color);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();
}

void sampler_parameterIuiv (NegativeTestContext& ctx)
{
	if (!contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)))
		throw tcu::NotSupportedError("glSamplerParameterIuiv is not supported.", DE_NULL, __FILE__, __LINE__);

	GLuint	sampler;
	GLuint	color[]	= {0, 0, 0, 0};

	ctx.glGenSamplers(1, &sampler);

	ctx.beginSection("GL_INVALID_OPERATION is generated if sampler is not the name of a sampler object previously returned from a call to ctx.glGenSamplers.");
	ctx.glSamplerParameterIuiv(-1, GL_TEXTURE_BORDER_COLOR, color);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if pname is not an accepted sampler state name.");
	ctx.glSamplerParameterIuiv(sampler, -1, color);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();
}

// Shader data commands

void get_attrib_location (NegativeTestContext& ctx)
{
	GLuint programEmpty		= ctx.glCreateProgram();
	GLuint shader			= ctx.glCreateShader(GL_VERTEX_SHADER);

	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));

	const GLuint notAProgram = ctx.glCreateProgram();
	ctx.glDeleteProgram(notAProgram);

	ctx.beginSection("GL_INVALID_OPERATION is generated if program has not been successfully linked.");
	ctx.glBindAttribLocation		(programEmpty, 0, "test");
	ctx.glGetAttribLocation			(programEmpty, "test");
	ctx.expectError				(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not a program or shader object.");
	ctx.glUseProgram				(program.getProgram());
	ctx.glBindAttribLocation		(program.getProgram(), 0, "test");
	ctx.expectError				(GL_NO_ERROR);
	ctx.glGetAttribLocation			(program.getProgram(), "test");
	ctx.expectError				(GL_NO_ERROR);
	ctx.glGetAttribLocation			(notAProgram, "test");
	ctx.expectError				(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is not a program object.");
	ctx.glGetAttribLocation			(shader, "test");
	ctx.expectError				(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram				(0);
	ctx.glDeleteShader				(shader);
	ctx.glDeleteProgram				(programEmpty);
}

void get_uniform_location (NegativeTestContext& ctx)
{
	GLuint programEmpty = ctx.glCreateProgram();
	GLuint shader = ctx.glCreateShader(GL_VERTEX_SHADER);

	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));

	const GLuint notAProgram = ctx.glCreateProgram();
	ctx.glDeleteProgram(notAProgram);

	ctx.beginSection("GL_INVALID_OPERATION is generated if program has not been successfully linked.");
	ctx.glGetUniformLocation(programEmpty, "test");
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not a value generated by OpenGL.");
	ctx.glUseProgram(program.getProgram());
	ctx.glGetUniformLocation(notAProgram, "test");
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is not a program object.");
	ctx.glGetAttribLocation(shader, "test");
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
	ctx.glDeleteProgram(programEmpty);
	ctx.glDeleteShader(shader);
}

void bind_attrib_location (NegativeTestContext& ctx)
{
	GLuint program = ctx.glCreateProgram();
	GLuint maxIndex = ctx.getInteger(GL_MAX_VERTEX_ATTRIBS);
	GLuint shader = ctx.glCreateShader(GL_VERTEX_SHADER);

	ctx.beginSection("GL_INVALID_VALUE is generated if index is greater than or equal to GL_MAX_VERTEX_ATTRIBS.");
	ctx.glBindAttribLocation(program, maxIndex, "test");
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if name starts with the reserved prefix \"gl_\".");
	ctx.glBindAttribLocation(program, maxIndex-1, "gl_test");
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not a value generated by OpenGL.");
	ctx.glBindAttribLocation(-1, maxIndex-1, "test");
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is not a program object.");
	ctx.glBindAttribLocation(shader, maxIndex-1, "test");
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glDeleteProgram(program);
	ctx.glDeleteShader(shader);
}

void uniform_block_binding (NegativeTestContext& ctx)
{
	GLint				maxUniformBufferBindings	= -1;
	GLint				numActiveUniforms			= -1;
	GLint				numActiveBlocks				= -1;
	GLuint				shader						= -1;
	glu::ShaderProgram	program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformBlockVertSource, uniformTestFragSource));

	shader = ctx.glCreateShader(GL_VERTEX_SHADER);
	ctx.glUseProgram(program.getProgram());

	ctx.glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings);
	ctx.glGetProgramiv(program.getProgram(), GL_ACTIVE_UNIFORMS, &numActiveUniforms);
	ctx.glGetProgramiv(program.getProgram(), GL_ACTIVE_UNIFORM_BLOCKS, &numActiveBlocks);
	ctx.getLog() << TestLog::Message << "// GL_MAX_UNIFORM_BUFFER_BINDINGS = " << maxUniformBufferBindings << TestLog::EndMessage;
	ctx.getLog() << TestLog::Message << "// GL_ACTIVE_UNIFORMS = "				<< numActiveUniforms		<< TestLog::EndMessage;
	ctx.getLog() << TestLog::Message << "// GL_ACTIVE_UNIFORM_BLOCKS = "		<< numActiveBlocks			<< TestLog::EndMessage;
	ctx.expectError	(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_VALUE is generated if uniformBlockIndex is not an active uniform block index of program.");
	ctx.glUniformBlockBinding(program.getProgram(), -1, 0);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.glUniformBlockBinding(program.getProgram(), 5, 0);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if uniformBlockBinding is greater than or equal to the value of GL_MAX_UNIFORM_BUFFER_BINDINGS.");
	ctx.glUniformBlockBinding(program.getProgram(), maxUniformBufferBindings, 0);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not the name of a program object generated by the GL.");
	ctx.glUniformBlockBinding(-1, 0, 0);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is the name of a shader object.");
	ctx.glUniformBlockBinding(shader, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glDeleteShader(shader);
}

// ctx.glUniform*f

void uniformf_invalid_program (NegativeTestContext& ctx)
{
	ctx.beginSection("GL_INVALID_OPERATION is generated if there is no current program object.");
	ctx.glUseProgram(0);
	ctx.glUniform1f(-1, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2f(-1, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3f(-1, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4f(-1, 0.0f, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();
}

void uniformf_incompatible_type (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	GLint vec4_v	= ctx.glGetUniformLocation(program.getProgram(), "vec4_v");	// vec4
	GLint ivec4_f	= ctx.glGetUniformLocation(program.getProgram(), "ivec4_f");	// ivec4
	GLint uvec4_f	= ctx.glGetUniformLocation(program.getProgram(), "uvec4_f");	// uvec4
	GLint sampler_f	= ctx.glGetUniformLocation(program.getProgram(), "sampler_f");	// sampler2D
	ctx.expectError(GL_NO_ERROR);

	if (vec4_v == -1 || ivec4_f == -1 || uvec4_f == -1 || sampler_f == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	ctx.beginSection("GL_INVALID_OPERATION is generated if the size of the uniform variable declared in the shader does not match the size indicated by the ctx.glUniform command.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1f(vec4_v, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2f(vec4_v, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3f(vec4_v, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4f(vec4_v, 0.0f, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}f is used to load a uniform variable of type int, ivec2, ivec3, ivec4, unsigned int, uvec2, uvec3, uvec4.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform4f(ivec4_f, 0.0f, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4f(uvec4_f, 0.0f, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if a sampler is loaded using a command other than ctx.glUniform1i and ctx.glUniform1iv.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1f(sampler_f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniformf_invalid_location (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	ctx.expectError(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_OPERATION is generated if location is an invalid uniform location for the current program object and location is not equal to -1.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1f(-2, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2f(-2, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3f(-2, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4f(-2, 0.0f, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1f(-1, 0.0f);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform2f(-1, 0.0f, 0.0f);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform3f(-1, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform4f(-1, 0.0f, 0.0f, 0.0f, 0.0f);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.glUseProgram(0);
}

// ctx.glUniform*fv

void uniformfv_invalid_program (NegativeTestContext& ctx)
{
	std::vector<GLfloat> data(4);

	ctx.beginSection("GL_INVALID_OPERATION is generated if there is no current program object.");
	ctx.glUseProgram(0);
	ctx.glUniform1fv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2fv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3fv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4fv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();
}

void uniformfv_incompatible_type (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	GLint vec4_v	= ctx.glGetUniformLocation(program.getProgram(), "vec4_v");	// vec4
	GLint ivec4_f	= ctx.glGetUniformLocation(program.getProgram(), "ivec4_f");	// ivec4
	GLint uvec4_f	= ctx.glGetUniformLocation(program.getProgram(), "uvec4_f");	// uvec4
	GLint sampler_f	= ctx.glGetUniformLocation(program.getProgram(), "sampler_f");	// sampler2D
	ctx.expectError(GL_NO_ERROR);

	if (vec4_v == -1 || ivec4_f == -1 || uvec4_f == -1 || sampler_f == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	std::vector<GLfloat> data(4);

	ctx.beginSection("GL_INVALID_OPERATION is generated if the size of the uniform variable declared in the shader does not match the size indicated by the ctx.glUniform command.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1fv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2fv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3fv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4fv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}fv is used to load a uniform variable of type int, ivec2, ivec3, ivec4, unsigned int, uvec2, uvec3, uvec4.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform4fv(ivec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4fv(uvec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if a sampler is loaded using a command other than ctx.glUniform1i and ctx.glUniform1iv.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1fv(sampler_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniformfv_invalid_location (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	ctx.expectError(GL_NO_ERROR);

	std::vector<GLfloat> data(4);

	ctx.beginSection("GL_INVALID_OPERATION is generated if location is an invalid uniform location for the current program object and location is not equal to -1.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1fv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2fv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3fv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4fv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1fv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform2fv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform3fv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform4fv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniformfv_invalid_count (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram	(program.getProgram());
	GLint vec4_v			= ctx.glGetUniformLocation(program.getProgram(), "vec4_v");	// vec4
	ctx.expectError(GL_NO_ERROR);

	if (vec4_v == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	std::vector<GLfloat> data(8);

	ctx.beginSection("GL_INVALID_OPERATION is generated if count is greater than 1 and the indicated uniform variable is not an array variable.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1fv(vec4_v, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2fv(vec4_v, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3fv(vec4_v, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4fv(vec4_v, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

// ctx.glUniform*i

void uniformi_invalid_program (NegativeTestContext& ctx)
{
	ctx.beginSection("GL_INVALID_OPERATION is generated if there is no current program object.");
	ctx.glUseProgram(0);
	ctx.glUniform1i(-1, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2i(-1, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3i(-1, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4i(-1, 0, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();
}

void uniformi_incompatible_type (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	GLint vec4_v	= ctx.glGetUniformLocation(program.getProgram(), "vec4_v");	// vec4
	GLint ivec4_f	= ctx.glGetUniformLocation(program.getProgram(), "ivec4_f");	// ivec4
	GLint uvec4_f	= ctx.glGetUniformLocation(program.getProgram(), "uvec4_f");	// uvec4
	GLint sampler_f	= ctx.glGetUniformLocation(program.getProgram(), "sampler_f");	// sampler2D
	ctx.expectError(GL_NO_ERROR);

	if (vec4_v == -1 || ivec4_f == -1 || uvec4_f == -1 || sampler_f == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	ctx.beginSection("GL_INVALID_OPERATION is generated if the size of the uniform variable declared in the shader does not match the size indicated by the ctx.glUniform command.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1i(ivec4_f, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2i(ivec4_f, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3i(ivec4_f, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4i(ivec4_f, 0, 0, 0, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}i is used to load a uniform variable of type unsigned int, uvec2, uvec3, uvec4, or an array of these.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1i(uvec4_f, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2i(uvec4_f, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3i(uvec4_f, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4i(uvec4_f, 0, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}i is used to load a uniform variable of type float, vec2, vec3, or vec4.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1i(vec4_v, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2i(vec4_v, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3i(vec4_v, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4i(vec4_v, 0, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniformi_invalid_location (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	ctx.expectError(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_OPERATION is generated if location is an invalid uniform location for the current program object and location is not equal to -1.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1i(-2, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2i(-2, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3i(-2, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4i(-2, 0, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1i(-1, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform2i(-1, 0, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform3i(-1, 0, 0, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform4i(-1, 0, 0, 0, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.glUseProgram(0);
}

// ctx.glUniform*iv

void uniformiv_invalid_program (NegativeTestContext& ctx)
{
	std::vector<GLint> data(4);

	ctx.beginSection("GL_INVALID_OPERATION is generated if there is no current program object.");
	ctx.glUseProgram(0);
	ctx.glUniform1iv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2iv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3iv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4iv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();
}

void uniformiv_incompatible_type (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	GLint vec4_v	= ctx.glGetUniformLocation(program.getProgram(), "vec4_v");	// vec4
	GLint ivec4_f	= ctx.glGetUniformLocation(program.getProgram(), "ivec4_f");	// ivec4
	GLint uvec4_f	= ctx.glGetUniformLocation(program.getProgram(), "uvec4_f");	// uvec4
	GLint sampler_f	= ctx.glGetUniformLocation(program.getProgram(), "sampler_f");	// sampler2D
	ctx.expectError(GL_NO_ERROR);

	if (vec4_v == -1 || ivec4_f == -1 || uvec4_f == -1 || sampler_f == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	std::vector<GLint> data(4);

	ctx.beginSection("GL_INVALID_OPERATION is generated if the size of the uniform variable declared in the shader does not match the size indicated by the ctx.glUniform command.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1iv(ivec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2iv(ivec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3iv(ivec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4iv(ivec4_f, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}iv is used to load a uniform variable of type float, vec2, vec3, or vec4.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1iv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2iv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3iv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4iv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}iv is used to load a uniform variable of type unsigned int, uvec2, uvec3 or uvec4.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1iv(uvec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2iv(uvec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3iv(uvec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4iv(uvec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniformiv_invalid_location (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	ctx.expectError(GL_NO_ERROR);

	std::vector<GLint> data(4);

	ctx.beginSection("GL_INVALID_OPERATION is generated if location is an invalid uniform location for the current program object and location is not equal to -1.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1iv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2iv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3iv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4iv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1iv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform2iv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform3iv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform4iv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniformiv_invalid_count (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram			(program.getProgram());
	GLint ivec4_f			= ctx.glGetUniformLocation(program.getProgram(), "ivec4_f"); // ivec4
	ctx.expectError(GL_NO_ERROR);

	if (ivec4_f == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	std::vector<GLint> data(8);

	ctx.beginSection("GL_INVALID_OPERATION is generated if count is greater than 1 and the indicated uniform variable is not an array variable.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1iv(ivec4_f, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2iv(ivec4_f, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3iv(ivec4_f, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4iv(ivec4_f, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

// ctx.glUniform{1234}ui

void uniformui_invalid_program (NegativeTestContext& ctx)
{
	ctx.beginSection("GL_INVALID_OPERATION is generated if there is no current program object.");
	ctx.glUseProgram(0);
	ctx.glUniform1ui(-1, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2ui(-1, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3ui(-1, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4ui(-1, 0, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();
}

void uniformui_incompatible_type (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	GLint vec4_v	= ctx.glGetUniformLocation(program.getProgram(), "vec4_v");	// vec4
	GLint ivec4_f	= ctx.glGetUniformLocation(program.getProgram(), "ivec4_f");	// ivec4
	GLint uvec4_f	= ctx.glGetUniformLocation(program.getProgram(), "uvec4_f");	// uvec4
	GLint sampler_f	= ctx.glGetUniformLocation(program.getProgram(), "sampler_f");	// sampler2D
	ctx.expectError(GL_NO_ERROR);

	if (vec4_v == -1 || ivec4_f == -1 || uvec4_f == -1 || sampler_f == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	ctx.beginSection("GL_INVALID_OPERATION is generated if the size of the uniform variable declared in the shader does not match the size indicated by the ctx.glUniform command.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1ui(uvec4_f, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2ui(uvec4_f, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3ui(uvec4_f, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4ui(uvec4_f, 0, 0, 0, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}i is used to load a uniform variable of type int, ivec2, ivec3, ivec4, or an array of these.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1ui(ivec4_f, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2ui(ivec4_f, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3ui(ivec4_f, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4ui(ivec4_f, 0, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}i is used to load a uniform variable of type float, vec2, vec3, or vec4.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1ui(vec4_v, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2ui(vec4_v, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3ui(vec4_v, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4ui(vec4_v, 0, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if a sampler is loaded using a command other than ctx.glUniform1i and ctx.glUniform1iv.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1ui(sampler_f, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniformui_invalid_location (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	ctx.expectError(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_OPERATION is generated if location is an invalid uniform location for the current program object and location is not equal to -1.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1i(-2, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2i(-2, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3i(-2, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4i(-2, 0, 0, 0, 0);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1i(-1, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform2i(-1, 0, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform3i(-1, 0, 0, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform4i(-1, 0, 0, 0, 0);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.glUseProgram(0);
}

// ctx.glUniform{1234}uiv

void uniformuiv_invalid_program (NegativeTestContext& ctx)
{
	std::vector<GLuint> data(4);

	ctx.beginSection("GL_INVALID_OPERATION is generated if there is no current program object.");
	ctx.glUseProgram(0);
	ctx.glUniform1uiv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2uiv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3uiv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4uiv(-1, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();
}

void uniformuiv_incompatible_type (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	GLint vec4_v	= ctx.glGetUniformLocation(program.getProgram(), "vec4_v");	// vec4
	GLint ivec4_f	= ctx.glGetUniformLocation(program.getProgram(), "ivec4_f");	// ivec4
	GLint uvec4_f	= ctx.glGetUniformLocation(program.getProgram(), "uvec4_f");	// uvec4
	GLint sampler_f	= ctx.glGetUniformLocation(program.getProgram(), "sampler_f");	// sampler2D
	ctx.expectError(GL_NO_ERROR);

	if (vec4_v == -1 || ivec4_f == -1 || uvec4_f == -1 || sampler_f == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	std::vector<GLuint> data(4);

	ctx.beginSection("GL_INVALID_OPERATION is generated if the size of the uniform variable declared in the shader does not match the size indicated by the ctx.glUniform command.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1uiv(uvec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2uiv(uvec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3uiv(uvec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4uiv(uvec4_f, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}uiv is used to load a uniform variable of type float, vec2, vec3, or vec4.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1uiv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2uiv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3uiv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4uiv(vec4_v, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if ctx.glUniform{1234}uiv is used to load a uniform variable of type int, ivec2, ivec3 or ivec4.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1uiv(ivec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2uiv(ivec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3uiv(ivec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4uiv(ivec4_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if a sampler is loaded using a command other than ctx.glUniform1i and ctx.glUniform1iv.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1uiv(sampler_f, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniformuiv_invalid_location (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	ctx.expectError(GL_NO_ERROR);

	std::vector<GLuint> data(4);

	ctx.beginSection("GL_INVALID_OPERATION is generated if location is an invalid uniform location for the current program object and location is not equal to -1.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1uiv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2uiv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3uiv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4uiv(-2, 1, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1uiv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform2uiv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform3uiv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniform4uiv(-1, 1, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniformuiv_invalid_count (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram			(program.getProgram());
	int uvec4_f				= ctx.glGetUniformLocation(program.getProgram(), "uvec4_f"); // uvec4
	ctx.expectError(GL_NO_ERROR);

	if (uvec4_f == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	std::vector<GLuint> data(8);

	ctx.beginSection("GL_INVALID_OPERATION is generated if count is greater than 1 and the indicated uniform variable is not an array variable.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniform1uiv(uvec4_f, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform2uiv(uvec4_f, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform3uiv(uvec4_f, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniform4uiv(uvec4_f, 2, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}


// ctx.glUniformMatrix*fv

void uniform_matrixfv_invalid_program (NegativeTestContext& ctx)
{
	std::vector<GLfloat> data(16);

	ctx.beginSection("GL_INVALID_OPERATION is generated if there is no current program object.");
	ctx.glUseProgram(0);
	ctx.glUniformMatrix2fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUniformMatrix2x3fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x2fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix2x4fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x2fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x4fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x3fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();
}

void uniform_matrixfv_incompatible_type (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram			(program.getProgram());
	GLint mat4_v			= ctx.glGetUniformLocation(program.getProgram(), "mat4_v");	// mat4
	GLint sampler_f			= ctx.glGetUniformLocation(program.getProgram(), "sampler_f");	// sampler2D
	ctx.expectError(GL_NO_ERROR);

	if (mat4_v == -1 || sampler_f == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	std::vector<GLfloat> data(16);

	ctx.beginSection("GL_INVALID_OPERATION is generated if the size of the uniform variable declared in the shader does not match the size indicated by the ctx.glUniform command.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniformMatrix2fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);

	ctx.glUniformMatrix2x3fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x2fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix2x4fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x2fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x4fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x3fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if a sampler is loaded using a command other than ctx.glUniform1i and ctx.glUniform1iv.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniformMatrix2fv(sampler_f, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3fv(sampler_f, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4fv(sampler_f, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUniformMatrix2x3fv(sampler_f, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x2fv(sampler_f, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix2x4fv(sampler_f, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x2fv(sampler_f, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x4fv(sampler_f, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x3fv(sampler_f, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniform_matrixfv_invalid_location (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram(program.getProgram());
	ctx.expectError(GL_NO_ERROR);

	std::vector<GLfloat> data(16);

	ctx.beginSection("GL_INVALID_OPERATION is generated if location is an invalid uniform location for the current program object and location is not equal to -1.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniformMatrix2fv(-2, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3fv(-2, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4fv(-2, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUniformMatrix2x3fv(-2, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x2fv(-2, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix2x4fv(-2, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x2fv(-2, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x4fv(-2, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x3fv(-2, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUseProgram(program.getProgram());
	ctx.glUniformMatrix2fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniformMatrix3fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniformMatrix4fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);

	ctx.glUniformMatrix2x3fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniformMatrix3x2fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniformMatrix2x4fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniformMatrix4x2fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniformMatrix3x4fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.glUniformMatrix4x3fv(-1, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();

	ctx.glUseProgram(0);
}

void uniform_matrixfv_invalid_count (NegativeTestContext& ctx)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformTestVertSource, uniformTestFragSource));

	ctx.glUseProgram			(program.getProgram());
	GLint mat4_v			= ctx.glGetUniformLocation(program.getProgram(), "mat4_v"); // mat4
	ctx.expectError(GL_NO_ERROR);

	if (mat4_v == -1)
	{
		ctx.getLog() << TestLog::Message << "// ERROR: Failed to retrieve uniform location" << TestLog::EndMessage;
		ctx.fail("Failed to retrieve uniform location");
	}

	std::vector<GLfloat> data(32);

	ctx.beginSection("GL_INVALID_OPERATION is generated if count is greater than 1 and the indicated uniform variable is not an array variable.");
	ctx.glUseProgram(program.getProgram());
	ctx.glUniformMatrix2fv(mat4_v, 2, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3fv(mat4_v, 2, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4fv(mat4_v, 2, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glUniformMatrix2x3fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x2fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix2x4fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x2fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix3x4fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glUniformMatrix4x3fv(mat4_v, 1, GL_FALSE, &data[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glUseProgram(0);
}

// Transform feedback
void gen_transform_feedbacks (NegativeTestContext& ctx)
{
	ctx.beginSection("GL_INVALID_VALUE is generated if n is negative.");
	GLuint id = 0;
	ctx.glGenTransformFeedbacks(-1, &id);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();
}

void bind_transform_feedback (NegativeTestContext& ctx)
{
	GLuint						tfID[2];
	glu::ShaderProgram			program(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	deUint32					buf = 0x1234;
	const char* tfVarying		= "gl_Position";

	ctx.glGenBuffers				(1, &buf);
	ctx.glGenTransformFeedbacks		(2, tfID);

	ctx.beginSection("GL_INVALID_ENUM is generated if target is not GL_TRANSFORM_FEEDBACK.");
	ctx.glBindTransformFeedback(-1, tfID[0]);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if the transform feedback operation is active on the currently bound transform feedback object, and is not paused.");
	ctx.glUseProgram				(program.getProgram());
	ctx.glTransformFeedbackVaryings	(program.getProgram(), 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.glLinkProgram				(program.getProgram());
	ctx.glBindTransformFeedback		(GL_TRANSFORM_FEEDBACK, tfID[0]);
	ctx.glBindBuffer				(GL_TRANSFORM_FEEDBACK_BUFFER, buf);
	ctx.glBufferData				(GL_TRANSFORM_FEEDBACK_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
	ctx.glBindBufferBase			(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.expectError				(GL_NO_ERROR);

	ctx.glBindTransformFeedback		(GL_TRANSFORM_FEEDBACK, tfID[1]);
	ctx.expectError				(GL_INVALID_OPERATION);

	ctx.glEndTransformFeedback		();
	ctx.expectError				(GL_NO_ERROR);
	ctx.endSection();

	ctx.glUseProgram				(0);
	ctx.glDeleteBuffers				(1, &buf);
	ctx.glDeleteTransformFeedbacks	(2, tfID);
	ctx.expectError				(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_OPERATION is generated if id has been deleted with glDeleteTransformFeedback().");
	ctx.glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfID[0]);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if id is not 0 or a value returned from glGenTransformFeedbacks().");
	ctx.glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, -1);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.endSection();
}

void delete_transform_feedbacks (NegativeTestContext& ctx)
{
	GLuint				id			= 0;
	GLuint				tfID[2];
	deUint32			buf			= 0x1234;
	const char*			tfVarying	= "gl_Position";
	glu::ShaderProgram	program		(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));

	ctx.glGenBuffers(1, &buf);
	ctx.glGenTransformFeedbacks(1, &id);
	ctx.glGenTransformFeedbacks(2, tfID);

	ctx.beginSection("GL_INVALID_VALUE is generated if n is negative.");
	ctx.glDeleteTransformFeedbacks(-1, &id);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if the transform feedback operation for any object named by ids is currently active.");
	ctx.glUseProgram(program.getProgram());
	ctx.glTransformFeedbackVaryings(program.getProgram(), 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.glLinkProgram(program.getProgram());
	ctx.glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfID[0]);
	ctx.glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buf);
	ctx.glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
	ctx.glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
	ctx.glBeginTransformFeedback(GL_TRIANGLES);
	ctx.expectError(GL_NO_ERROR);

	ctx.glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfID[1]);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glDeleteTransformFeedbacks(2, tfID);
	ctx.expectError(GL_INVALID_OPERATION);

	ctx.glEndTransformFeedback();
	ctx.expectError(GL_NO_ERROR);
	ctx.endSection();


	ctx.glDeleteTransformFeedbacks(1, &id);
	ctx.glDeleteTransformFeedbacks(2, tfID);
	ctx.glDeleteBuffers(1, &buf);

}

void begin_transform_feedback (NegativeTestContext& ctx)
{
	GLuint						tfID[2];
	glu::ShaderProgram			program(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	deUint32					buf = 0x1234;
	const char* tfVarying		= "gl_Position";

	ctx.glGenBuffers				(1, &buf);
	ctx.glGenTransformFeedbacks		(2, tfID);

	ctx.glUseProgram				(program.getProgram());
	ctx.glTransformFeedbackVaryings	(program.getProgram(), 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.glLinkProgram				(program.getProgram());
	ctx.glBindTransformFeedback		(GL_TRANSFORM_FEEDBACK, tfID[0]);
	ctx.glBindBuffer				(GL_TRANSFORM_FEEDBACK_BUFFER, buf);
	ctx.glBufferData				(GL_TRANSFORM_FEEDBACK_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
	ctx.glBindBufferBase			(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
	ctx.expectError					(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_ENUM is generated if primitiveMode is not one of GL_POINTS, GL_LINES, or GL_TRIANGLES.");
	ctx.glBeginTransformFeedback	(-1);
	ctx.expectError					(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if transform feedback is already active.");
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.expectError					(GL_NO_ERROR);
	ctx.glBeginTransformFeedback	(GL_POINTS);
	ctx.expectError					(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if any binding point used in transform feedback mode does not have a buffer object bound.");
	ctx.glBindBufferBase			(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.expectError					(GL_INVALID_OPERATION);
	ctx.glBindBufferBase			(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if no binding points would be used because no program object is active.");
	ctx.glUseProgram				(0);
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.expectError					(GL_INVALID_OPERATION);
	ctx.glUseProgram				(program.getProgram());
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if no binding points would be used because the active program object has specified no varying variables to record.");
	ctx.glTransformFeedbackVaryings	(program.getProgram(), 0, 0, GL_INTERLEAVED_ATTRIBS);
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.expectError					(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glEndTransformFeedback		();
	ctx.glDeleteBuffers				(1, &buf);
	ctx.glDeleteTransformFeedbacks	(2, tfID);
	ctx.expectError					(GL_NO_ERROR);
}

void pause_transform_feedback (NegativeTestContext& ctx)
{
	GLuint						tfID[2];
	glu::ShaderProgram			program(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	deUint32					buf = 0x1234;
	const char* tfVarying		= "gl_Position";

	ctx.glGenBuffers				(1, &buf);
	ctx.glGenTransformFeedbacks		(2, tfID);

	ctx.glUseProgram				(program.getProgram());
	ctx.glTransformFeedbackVaryings	(program.getProgram(), 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.glLinkProgram				(program.getProgram());
	ctx.glBindTransformFeedback		(GL_TRANSFORM_FEEDBACK, tfID[0]);
	ctx.glBindBuffer				(GL_TRANSFORM_FEEDBACK_BUFFER, buf);
	ctx.glBufferData				(GL_TRANSFORM_FEEDBACK_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
	ctx.glBindBufferBase			(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
	ctx.expectError					(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_OPERATION is generated if the currently bound transform feedback object is not active or is paused.");
	ctx.glPauseTransformFeedback	();
	ctx.expectError					(GL_INVALID_OPERATION);
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.glPauseTransformFeedback	();
	ctx.expectError					(GL_NO_ERROR);
	ctx.glPauseTransformFeedback	();
	ctx.expectError					(GL_INVALID_OPERATION);
	ctx.endSection();

	ctx.glEndTransformFeedback		();
	ctx.glDeleteBuffers				(1, &buf);
	ctx.glDeleteTransformFeedbacks	(2, tfID);
	ctx.expectError					(GL_NO_ERROR);
}

void resume_transform_feedback (NegativeTestContext& ctx)
{
	GLuint						tfID[2];
	glu::ShaderProgram			program(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	deUint32					buf = 0x1234;
	const char* tfVarying		= "gl_Position";

	ctx.glGenBuffers				(1, &buf);
	ctx.glGenTransformFeedbacks		(2, tfID);

	ctx.glUseProgram				(program.getProgram());
	ctx.glTransformFeedbackVaryings	(program.getProgram(), 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.glLinkProgram				(program.getProgram());
	ctx.glBindTransformFeedback		(GL_TRANSFORM_FEEDBACK, tfID[0]);
	ctx.glBindBuffer				(GL_TRANSFORM_FEEDBACK_BUFFER, buf);
	ctx.glBufferData				(GL_TRANSFORM_FEEDBACK_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
	ctx.glBindBufferBase			(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
	ctx.expectError					(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_OPERATION is generated if the currently bound transform feedback object is not active or is not paused.");
	ctx.glResumeTransformFeedback	();
	ctx.expectError					(GL_INVALID_OPERATION);
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.glResumeTransformFeedback	();
	ctx.expectError					(GL_INVALID_OPERATION);
	ctx.glPauseTransformFeedback	();
	ctx.glResumeTransformFeedback	();
	ctx.expectError					(GL_NO_ERROR);
	ctx.endSection();

	ctx.glEndTransformFeedback		();
	ctx.glDeleteBuffers				(1, &buf);
	ctx.glDeleteTransformFeedbacks	(2, tfID);
	ctx.expectError					(GL_NO_ERROR);
}

void end_transform_feedback (NegativeTestContext& ctx)
{
	GLuint						tfID = 0;
	glu::ShaderProgram			program(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	deUint32					buf = 0x1234;
	const char* tfVarying		= "gl_Position";

	ctx.glGenBuffers				(1, &buf);
	ctx.glGenTransformFeedbacks		(1, &tfID);

	ctx.glUseProgram				(program.getProgram());
	ctx.glTransformFeedbackVaryings	(program.getProgram(), 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.glLinkProgram				(program.getProgram());
	ctx.glBindTransformFeedback		(GL_TRANSFORM_FEEDBACK, tfID);
	ctx.glBindBuffer				(GL_TRANSFORM_FEEDBACK_BUFFER, buf);
	ctx.glBufferData				(GL_TRANSFORM_FEEDBACK_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
	ctx.glBindBufferBase			(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
	ctx.expectError					(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_OPERATION is generated if transform feedback is not active.");
	ctx.glEndTransformFeedback		();
	ctx.expectError					(GL_INVALID_OPERATION);
	ctx.glBeginTransformFeedback	(GL_TRIANGLES);
	ctx.glEndTransformFeedback		();
	ctx.expectError					(GL_NO_ERROR);
	ctx.endSection();

	ctx.glDeleteBuffers				(1, &buf);
	ctx.glDeleteTransformFeedbacks	(1, &tfID);
	ctx.expectError					(GL_NO_ERROR);
}

void get_transform_feedback_varying (NegativeTestContext& ctx)
{
	GLuint					tfID = 0;
	glu::ShaderProgram		program			(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	glu::ShaderProgram		programInvalid	(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, ""));
	const char* tfVarying	= "gl_Position";
	int						maxTransformFeedbackVaryings = 0;

	GLsizei					length;
	GLsizei					size;
	GLenum					type;
	char					name[32];

	const GLuint notAProgram = ctx.glCreateProgram();
	ctx.glDeleteProgram(notAProgram);

	ctx.glGenTransformFeedbacks				(1, &tfID);

	ctx.glTransformFeedbackVaryings			(program.getProgram(), 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.expectError						(GL_NO_ERROR);
	ctx.glLinkProgram						(program.getProgram());
	ctx.expectError						(GL_NO_ERROR);

	ctx.glBindTransformFeedback				(GL_TRANSFORM_FEEDBACK, tfID);
	ctx.expectError						(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not the name of a program object.");
	ctx.glGetTransformFeedbackVarying		(notAProgram, 0, 32, &length, &size, &type, &name[0]);
	ctx.expectError						(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if index is greater or equal to the value of GL_TRANSFORM_FEEDBACK_VARYINGS.");
	ctx.glGetProgramiv						(program.getProgram(), GL_TRANSFORM_FEEDBACK_VARYINGS, &maxTransformFeedbackVaryings);
	ctx.glGetTransformFeedbackVarying		(program.getProgram(), maxTransformFeedbackVaryings, 32, &length, &size, &type, &name[0]);
	ctx.expectError						(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION or GL_INVALID_VALUE is generated program has not been linked.");
	ctx.glGetTransformFeedbackVarying		(programInvalid.getProgram(), 0, 32, &length, &size, &type, &name[0]);
	ctx.expectError						(GL_INVALID_OPERATION, GL_INVALID_VALUE);
	ctx.endSection();

	ctx.glDeleteTransformFeedbacks			(1, &tfID);
	ctx.expectError						(GL_NO_ERROR);
}

void transform_feedback_varyings (NegativeTestContext& ctx)
{
	GLuint										tfID = 0;
	GLuint shader								= ctx.glCreateShader(GL_VERTEX_SHADER);
	glu::ShaderProgram program					(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	const char* tfVarying						= "gl_Position";
	GLint maxTransformFeedbackSeparateAttribs	= 0;

	const GLuint notAProgram = ctx.glCreateProgram();
	ctx.glDeleteProgram(notAProgram);

	ctx.glGenTransformFeedbacks				(1, &tfID);
	ctx.expectError						(GL_NO_ERROR);

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not the name of a program object.");
	ctx.glTransformFeedbackVaryings			(notAProgram, 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.expectError						(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_OPERATION is generated if program is the name of a shader object.");
	ctx.glTransformFeedbackVaryings(shader, 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.expectError(GL_INVALID_OPERATION);
	ctx.glDeleteShader(shader);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if count is negative.");
	ctx.glTransformFeedbackVaryings(program.getProgram(), -1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_ENUM is generated if bufferMode is not SEPARATE_ATTRIBS or INTERLEAVED_ATTRIBS.");
	ctx.glTransformFeedbackVaryings(program.getProgram(), 1, &tfVarying, 0);
	ctx.expectError(GL_INVALID_ENUM);
	ctx.endSection();

	ctx.beginSection("GL_INVALID_VALUE is generated if bufferMode is GL_SEPARATE_ATTRIBS and count is greater than GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS.");
	ctx.glGetIntegerv						(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &maxTransformFeedbackSeparateAttribs);
	ctx.glTransformFeedbackVaryings			(program.getProgram(), maxTransformFeedbackSeparateAttribs+1, &tfVarying, GL_SEPARATE_ATTRIBS);
	ctx.expectError						(GL_INVALID_VALUE);
	ctx.endSection();

	ctx.glDeleteTransformFeedbacks			(1, &tfID);
	ctx.expectError						(GL_NO_ERROR);

}

void link_compute_shader (NegativeTestContext& ctx)
{
	const char* computeShaderSource		=	"#version 320 es\n"
											"void main (void)\n"
											"{\n"
											"}\n\0";
	{
		const GLenum shaderTypes[]			=	{
													GL_VERTEX_SHADER,
													GL_FRAGMENT_SHADER,
													GL_GEOMETRY_SHADER,
													GL_TESS_CONTROL_SHADER,
													GL_TESS_EVALUATION_SHADER
												};

		ctx.beginSection("Compute Shader linked with shader of other kind.");
		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(shaderTypes); ndx++)
		{
			GLint linkStatus				=	-1;
			GLuint program					=	ctx.glCreateProgram();
			GLuint computeShader			=	ctx.glCreateShader(GL_COMPUTE_SHADER);
			GLuint otherShader				=	ctx.glCreateShader(shaderTypes[ndx]);
			const char* otherShaderSource	=	(shaderTypes[ndx] != GL_GEOMETRY_SHADER)	?
												computeShaderSource							:
												"#version 320 es\n"
												"layout(max_vertices = 3) out;\n"
												"void main(void){}\n\0";

			ctx.glShaderSource(computeShader, 1, &computeShaderSource, DE_NULL);
			ctx.glShaderSource(otherShader, 1, &otherShaderSource, DE_NULL);
			ctx.glCompileShader(computeShader);
			ctx.glCompileShader(otherShader);
			ctx.glAttachShader(program, computeShader);
			ctx.glAttachShader(program, otherShader);
			ctx.glLinkProgram(program);
			ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
			ctx.glDeleteShader(otherShader);
			ctx.glDeleteShader(computeShader);
			ctx.glDeleteProgram(program);
			if (linkStatus != GL_FALSE)
				ctx.fail("Program should not have linked");
		}
		ctx.endSection();
	}
	{
		const char* computeShaderSource310	=	"#version 310 es\n"
												"void main (void)\n"
												"{\n"
												"}\n\0";
		GLint linkStatus					=	-1;
		GLuint program						=	ctx.glCreateProgram();
		GLuint computeShader				=	ctx.glCreateShader(GL_COMPUTE_SHADER);
		GLuint computeShader310				=	ctx.glCreateShader(GL_FRAGMENT_SHADER);

		ctx.glShaderSource(computeShader, 1, &computeShaderSource, DE_NULL);
		ctx.glShaderSource(computeShader310, 1, &computeShaderSource310, DE_NULL);
		ctx.beginSection("Compute Shader should not be linked with shaders of different version.");
		ctx.glCompileShader(computeShader);
		ctx.glCompileShader(computeShader310);
		ctx.glAttachShader(program, computeShader);
		ctx.glAttachShader(program, computeShader310);
		ctx.glLinkProgram(program);
		ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
		ctx.glDeleteShader(computeShader310);
		ctx.glDeleteShader(computeShader);
		ctx.glDeleteProgram(program);
		if (linkStatus != GL_FALSE)
			ctx.fail("Program should not have linked");
		ctx.endSection();
	}
}

void compile_compute_shader_helper (NegativeTestContext& ctx, const char* const* computeShaderSource, GLint* compileStatus)
{
	GLuint shader = ctx.glCreateShader(GL_COMPUTE_SHADER);

	*compileStatus = -1;
	ctx.glShaderSource(shader, 1, computeShaderSource, DE_NULL);
	ctx.glCompileShader(shader);
	ctx.glGetShaderiv(shader, GL_COMPILE_STATUS, compileStatus);
	ctx.glDeleteShader(shader);
}

void compile_compute_shader (NegativeTestContext& ctx)
{
	GLint compileStatus;
	ctx.beginSection("Compile Computer Shader");

	{
		const char* const computeShaderSource		=	"#version 300 es\n"
														"void main (void)\n"
														"{\n"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled with #version 300 es.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"buffer SSBO { vec4 data }"
														"void main (void)\n"
														"{\n"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: incorrect SSBO syntax.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"buffer SSBO { vec4 data;};"
														"uniform mat4 data;"
														"void main (void)\n"
														"{\n"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: buffer variable redefinition.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"buffer SSBO { vec4 data[]; vec4 moreData;};"
														"void main (void)\n"
														"{\n"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: unspecified length buffer member not at the end.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"in vec4 data;"
														"void main (void)\n"
														"{\n"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: input qualifier used.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"shared uint data = 0;";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: shared-qualified variable initialized.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"buffer SSBO { vec4 data; vec4 moreData[];} ssbo;"
														"void test (vec4 data[10]) {}"
														"void main (void)\n"
														"{\n"
														"    test(ssbo.moreData);"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: unspecified length buffer member passed as argument to function.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"buffer SSBO { vec4 data; vec4 moreData[];} ssbo;"
														"void main (void)\n"
														"{\n"
														"    vec4 var = ssbo.moreData[-1];"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: unspecified length buffer member indexed with negative constant expression.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"layout(binding=-1) buffer SSBO { vec4 data;};"
														"void main (void)\n"
														"{\n"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: binding point less than zero.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"layout(binding=1) buffer;"
														"layout(binding=2) buffer SSBO { vec4 data;};"
														"void main (void)\n"
														"{\n"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: binding point specified for global scope.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"buffer SSBO {"
														"	layout(binding=1) vec4 data;"
														"	layout(binding=2) vec4 moreData[];"
														"} ssbo;"
														"void main (void)\n"
														"{\n"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: binding point specified for block member declarations.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"readonly buffer SSBO {vec4 data;} ssbo;"
														"void main (void)\n"
														"{\n"
															"ssbo.data = vec4(1, 1, 1, 1);"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: writing to buffer block qualified with readonly.");
	}
	{
		const char* const computeShaderSource		=	"#version 310 es\n"
														"writeonly buffer SSBO {vec4 data;} ssbo;"
														"void main (void)\n"
														"{\n"
															"vec4 var = ssbo.data;"
														"}\n";

		compile_compute_shader_helper(ctx, &computeShaderSource, &compileStatus);
		if (compileStatus != GL_FALSE)
			ctx.fail("Compute Shader should not have compiled: reading from buffer block qualified with writeonly.");
	}

	ctx.endSection();
}

std::vector<FunctionContainer> getNegativeShaderApiTestFunctions ()
{
	FunctionContainer funcs[] =
	{
		{create_shader,							"create_shader",						"Invalid glCreateShader() usage"			   },
		{shader_source,							"shader_source",						"Invalid glShaderSource() usage"			   },
		{compile_shader,						"compile_shader",						"Invalid glCompileShader() usage"			   },
		{delete_shader,							"delete_shader",						"Invalid glDeleteShader() usage"			   },
		{shader_binary,							"shader_binary",						"Invalid glShaderBinary() usage"			   },
		{attach_shader,							"attach_shader",						"Invalid glAttachShader() usage"			   },
		{detach_shader,							"detach_shader",						"Invalid glDetachShader() usage"			   },
		{link_program,							"link_program",							"Invalid glLinkProgram() usage"				   },
		{use_program,							"use_program",							"Invalid glUseProgram() usage"				   },
		{delete_program,						"delete_program",						"Invalid glDeleteProgram() usage"			   },
		{validate_program,						"validate_program",						"Invalid glValidateProgram() usage"			   },
		{get_program_binary,					"get_program_binary",					"Invalid glGetProgramBinary() usage"		   },
		{program_binary,						"program_binary",						"Invalid glProgramBinary() usage"			   },
		{program_parameteri,					"program_parameteri",					"Invalid glProgramParameteri() usage"		   },
		{gen_samplers,							"gen_samplers",							"Invalid glGenSamplers() usage"				   },
		{bind_sampler,							"bind_sampler",							"Invalid glBindSampler() usage"				   },
		{delete_samplers,						"delete_samplers",						"Invalid glDeleteSamplers() usage"			   },
		{get_sampler_parameteriv,				"get_sampler_parameteriv",				"Invalid glGetSamplerParameteriv() usage"	   },
		{get_sampler_parameterfv,				"get_sampler_parameterfv",				"Invalid glGetSamplerParameterfv() usage"	   },
		{get_sampler_parameterIiv,				"get_sampler_parameterIiv",				"Invalid glGetSamplerParameterIiv() usage"	   },
		{get_sampler_parameterIuiv,				"get_sampler_parameterIuiv",			"Invalid glGetSamplerParameterIuiv() usage"	   },
		{sampler_parameteri,					"sampler_parameteri",					"Invalid glSamplerParameteri() usage"		   },
		{sampler_parameteriv,					"sampler_parameteriv",					"Invalid glSamplerParameteriv() usage"		   },
		{sampler_parameterf,					"sampler_parameterf",					"Invalid glSamplerParameterf() usage"		   },
		{sampler_parameterfv,					"sampler_parameterfv",					"Invalid glSamplerParameterfv() usage"		   },
		{sampler_parameterIiv,					"sampler_parameterIiv",					"Invalid glSamplerParameterIiv() usage"		   },
		{sampler_parameterIuiv,					"sampler_parameterIuiv",				"Invalid glSamplerParameterIuiv() usage"		   },
		{get_attrib_location,					"get_attrib_location",					"Invalid glGetAttribLocation() usage"		   },
		{get_uniform_location,					"get_uniform_location",					"Invalid glGetUniformLocation() usage"		   },
		{bind_attrib_location,					"bind_attrib_location",					"Invalid glBindAttribLocation() usage"		   },
		{uniform_block_binding,					"uniform_block_binding",				"Invalid glUniformBlockBinding() usage"		   },
		{uniformf_invalid_program,				"uniformf_invalid_program",				"Invalid glUniform{1234}f() usage"			   },
		{uniformf_incompatible_type,			"uniformf_incompatible_type",			"Invalid glUniform{1234}f() usage"			   },
		{uniformf_invalid_location,				"uniformf_invalid_location",			"Invalid glUniform{1234}f() usage"			   },
		{uniformfv_invalid_program,				"uniformfv_invalid_program",			"Invalid glUniform{1234}fv() usage"			   },
		{uniformfv_incompatible_type,			"uniformfv_incompatible_type",			"Invalid glUniform{1234}fv() usage"			   },
		{uniformfv_invalid_location,			"uniformfv_invalid_location",			"Invalid glUniform{1234}fv() usage"			   },
		{uniformfv_invalid_count,				"uniformfv_invalid_count",				"Invalid glUniform{1234}fv() usage"			   },
		{uniformi_invalid_program,				"uniformi_invalid_program",				"Invalid glUniform{1234}i() usage"			   },
		{uniformi_incompatible_type,			"uniformi_incompatible_type",			"Invalid glUniform{1234}i() usage"			   },
		{uniformi_invalid_location,				"uniformi_invalid_location",			"Invalid glUniform{1234}i() usage"			   },
		{uniformiv_invalid_program,				"uniformiv_invalid_program",			"Invalid glUniform{1234}iv() usage"			   },
		{uniformiv_incompatible_type,			"uniformiv_incompatible_type",			"Invalid glUniform{1234}iv() usage"			   },
		{uniformiv_invalid_location,			"uniformiv_invalid_location",			"Invalid glUniform{1234}iv() usage"			   },
		{uniformiv_invalid_count,				"uniformiv_invalid_count",				"Invalid glUniform{1234}iv() usage"			   },
		{uniformui_invalid_program,				"uniformui_invalid_program",			"Invalid glUniform{234}ui() usage"			   },
		{uniformui_incompatible_type,			"uniformui_incompatible_type",			"Invalid glUniform{1234}ui() usage"			   },
		{uniformui_invalid_location,			"uniformui_invalid_location",			"Invalid glUniform{1234}ui() usage"			   },
		{uniformuiv_invalid_program,			"uniformuiv_invalid_program",			"Invalid glUniform{234}uiv() usage"			   },
		{uniformuiv_incompatible_type,			"uniformuiv_incompatible_type",			"Invalid glUniform{1234}uiv() usage"		   },
		{uniformuiv_invalid_location,			"uniformuiv_invalid_location",			"Invalid glUniform{1234}uiv() usage"		   },
		{uniformuiv_invalid_count,				"uniformuiv_invalid_count",				"Invalid glUniform{1234}uiv() usage"		   },
		{uniform_matrixfv_invalid_program,		"uniform_matrixfv_invalid_program",		"Invalid glUniformMatrix{234}fv() usage"	   },
		{uniform_matrixfv_incompatible_type,	"uniform_matrixfv_incompatible_type",	"Invalid glUniformMatrix{234}fv() usage"	   },
		{uniform_matrixfv_invalid_location,		"uniform_matrixfv_invalid_location",	"Invalid glUniformMatrix{234}fv() usage"	   },
		{uniform_matrixfv_invalid_count,		"uniform_matrixfv_invalid_count",		"Invalid glUniformMatrix{234}fv() usage"	   },
		{gen_transform_feedbacks,				"gen_transform_feedbacks",				"Invalid glGenTransformFeedbacks() usage"	   },
		{bind_transform_feedback,				"bind_transform_feedback",				"Invalid glBindTransformFeedback() usage"	   },
		{delete_transform_feedbacks,			"delete_transform_feedbacks",			"Invalid glDeleteTransformFeedbacks() usage"   },
		{begin_transform_feedback,				"begin_transform_feedback",				"Invalid glBeginTransformFeedback() usage"	   },
		{pause_transform_feedback,				"pause_transform_feedback",				"Invalid glPauseTransformFeedback() usage"	   },
		{resume_transform_feedback,				"resume_transform_feedback",			"Invalid glResumeTransformFeedback() usage"	   },
		{end_transform_feedback,				"end_transform_feedback",				"Invalid glEndTransformFeedback() usage"	   },
		{get_transform_feedback_varying,		"get_transform_feedback_varying",		"Invalid glGetTransformFeedbackVarying() usage"},
		{transform_feedback_varyings,			"transform_feedback_varyings",			"Invalid glTransformFeedbackVaryings() usage"  },
		{compile_compute_shader,				"compile_compute_shader",				"Invalid Compute Shader compilation"		   },
		{link_compute_shader,					"link_compute_shader",					"Invalid Compute Shader linkage"			   },
	};

	return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
}

} // NegativeTestShared
} // Functional
} // gles31
} // deqp