C++程序  |  2071行  |  81.34 KB

/*-------------------------------------------------------------------------
 * 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"



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)
{
	// \note Shader compilation must be supported.

	ctx.beginSection("GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL.");
	ctx.glShaderSource(1, 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)
{
	// \note Shader compilation must be supported.

	ctx.beginSection("GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL.");
	ctx.glCompileShader(9);
	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)
{
	ctx.beginSection("GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL.");
	ctx.glDeleteShader(9);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();
}

void shader_binary (NegativeTestContext& ctx)
{
	std::vector<deInt32> binaryFormats;

	{
		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]);
		}
	}

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

	GLuint shaders[2];
	shaders[0]		= ctx.glCreateShader(GL_VERTEX_SHADER);
	shaders[1]		= ctx.glCreateShader(GL_VERTEX_SHADER);

	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.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();

	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, -1);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.glAttachShader(-1, shader1);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.glAttachShader(-1, -1);
	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();

	ctx.beginSection("GL_INVALID_VALUE is generated if either program or shader is not a value generated by OpenGL.");
	ctx.glDetachShader(-1, shader);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.glDetachShader(program, -1);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.glDetachShader(-1, -1);
	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);

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not a value generated by OpenGL.");
	ctx.glLinkProgram(-1);
	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);

	ctx.beginSection("GL_INVALID_VALUE is generated if program is neither 0 nor a value generated by OpenGL.");
	ctx.glUseProgram(-1);
	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)
{
	ctx.beginSection("GL_INVALID_VALUE is generated if program is not a value generated by OpenGL.");
	ctx.glDeleteProgram(-1);
	ctx.expectError(GL_INVALID_VALUE);
	ctx.endSection();
}

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

	ctx.beginSection("GL_INVALID_VALUE is generated if program is not a value generated by OpenGL.");
	ctx.glValidateProgram(-1);
	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);
	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();

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

	ctx.beginSection("GL_INVALID_ENUM is generated if pname is not GL_PROGRAM_BINARY_RETRIEVABLE_HINT.");
	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);
}

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;
	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 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();

	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();

	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);
}

// 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));

	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			(-2, "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));

	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(-2, "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)
{
	glu::ShaderProgram program(ctx.getRenderContext(), glu::makeVtxFragSources(uniformBlockVertSource, uniformTestFragSource));

	ctx.glUseProgram	(program.getProgram());

	GLint			maxUniformBufferBindings	= -1;
	GLint			numActiveUniforms			= -1;
	GLint			numActiveBlocks				= -1;
	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.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);
}

void delete_transform_feedbacks (NegativeTestContext& ctx)
{
	GLuint id = 0;
	ctx.glGenTransformFeedbacks(1, &id);

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

	ctx.glDeleteTransformFeedbacks(1, &id);
}

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];

	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		(-1, 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;
	glu::ShaderProgram		program(ctx.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
	const char* tfVarying	= "gl_Position";
	GLint					maxTransformFeedbackSeparateAttribs = 0;

	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			(0, 1, &tfVarying, GL_INTERLEAVED_ATTRIBS);
	ctx.expectError						(GL_INVALID_VALUE);
	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);
}

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"	   },
		{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"		   },
		{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"  },
	};

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

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