Home | History | Annotate | Download | only in stress
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.0 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Special float stress tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3sSpecialFloatTests.hpp"
     25 #include "gluRenderContext.hpp"
     26 #include "gluShaderProgram.hpp"
     27 #include "gluPixelTransfer.hpp"
     28 #include "gluStrUtil.hpp"
     29 #include "gluContextInfo.hpp"
     30 #include "glwEnums.hpp"
     31 #include "glwFunctions.hpp"
     32 #include "tcuRenderTarget.hpp"
     33 #include "tcuSurface.hpp"
     34 #include "tcuTestLog.hpp"
     35 #include "tcuVectorUtil.hpp"
     36 #include "deStringUtil.hpp"
     37 #include "deMath.h"
     38 #include "deRandom.hpp"
     39 
     40 #include <limits>
     41 #include <sstream>
     42 
     43 using namespace glw;
     44 
     45 namespace deqp
     46 {
     47 namespace gles3
     48 {
     49 namespace Stress
     50 {
     51 namespace
     52 {
     53 
     54 static const int		TEST_CANVAS_SIZE		= 256;
     55 static const int		TEST_TEXTURE_SIZE		= 128;
     56 static const int		TEST_TEXTURE_CUBE_SIZE	= 32;
     57 static const deUint32	s_specialFloats[]		=
     58 {
     59 	0x00000000,	//          zero
     60 	0x80000000,	// negative zero
     61 	0x3F800000,	//          one
     62 	0xBF800000,	// negative one
     63 	0x00800000,	// minimum positive normalized value
     64 	0x80800000,	// maximum negative normalized value
     65 	0x00000001,	// minimum positive denorm value
     66 	0x80000001,	// maximum negative denorm value
     67 	0x7F7FFFFF,	// maximum finite value.
     68 	0xFF7FFFFF,	// minimum finite value.
     69 	0x7F800000,	//  inf
     70 	0xFF800000,	// -inf
     71 	0x34000000,	//          epsilon
     72 	0xB4000000,	// negative epsilon
     73 	0x7FC00000,	//          quiet_NaN
     74 	0xFFC00000,	// negative quiet_NaN
     75 	0x7FC00001,	//          signaling_NaN
     76 	0xFFC00001,	// negative signaling_NaN
     77 	0x7FEAAAAA,	//          quiet payloaded NaN		(payload of repeated pattern of 101010...)
     78 	0xFFEAAAAA,	// negative quiet payloaded NaN		( .. )
     79 	0x7FAAAAAA,	//          signaling payloaded NaN	( .. )
     80 	0xFFAAAAAA,	// negative signaling payloaded NaN	( .. )
     81 };
     82 
     83 static const char* const s_colorPassthroughFragmentShaderSource	=	"#version 300 es\n"
     84 																	"layout(location = 0) out mediump vec4 fragColor;\n"
     85 																	"in mediump vec4 v_out;\n"
     86 																	"void main ()\n"
     87 																	"{\n"
     88 																	"	fragColor = v_out;\n"
     89 																	"}\n";
     90 static const char* const s_attrPassthroughVertexShaderSource	=	"#version 300 es\n"
     91 																	"in highp vec4 a_pos;\n"
     92 																	"in highp vec4 a_attr;\n"
     93 																	"out highp vec4 v_attr;\n"
     94 																	"void main ()\n"
     95 																	"{\n"
     96 																	"	v_attr = a_attr;\n"
     97 																	"	gl_Position = a_pos;\n"
     98 																	"}\n";
     99 
    100 class RenderCase : public TestCase
    101 {
    102 public:
    103 	enum RenderTargetType
    104 	{
    105 		RENDERTARGETTYPE_SCREEN,
    106 		RENDERTARGETTYPE_FBO
    107 	};
    108 
    109 								RenderCase			(Context& context, const char* name, const char* desc, RenderTargetType renderTargetType = RENDERTARGETTYPE_SCREEN);
    110 	virtual						~RenderCase			(void);
    111 
    112 	virtual void				init				(void);
    113 	virtual void				deinit				(void);
    114 
    115 protected:
    116 	bool						checkResultImage	(const tcu::Surface& result);
    117 	bool						drawTestPattern		(bool useTexture);
    118 
    119 	virtual std::string			genVertexSource		(void) const = 0;
    120 	virtual std::string			genFragmentSource	(void) const = 0;
    121 
    122 	const glu::ShaderProgram*	m_program;
    123 	const RenderTargetType		m_renderTargetType;
    124 };
    125 
    126 RenderCase::RenderCase (Context& context, const char* name, const char* desc, RenderTargetType renderTargetType)
    127 	: TestCase				(context, name, desc)
    128 	, m_program				(DE_NULL)
    129 	, m_renderTargetType	(renderTargetType)
    130 {
    131 }
    132 
    133 RenderCase::~RenderCase (void)
    134 {
    135 	deinit();
    136 }
    137 
    138 void RenderCase::init (void)
    139 {
    140 	const int width	 = m_context.getRenderTarget().getWidth();
    141 	const int height = m_context.getRenderTarget().getHeight();
    142 
    143 	// check target size
    144 	if (m_renderTargetType == RENDERTARGETTYPE_SCREEN)
    145 	{
    146 		if (width < TEST_CANVAS_SIZE || height < TEST_CANVAS_SIZE)
    147 			throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(TEST_CANVAS_SIZE) + "x" + de::toString(TEST_CANVAS_SIZE));
    148 	}
    149 	else if (m_renderTargetType == RENDERTARGETTYPE_FBO)
    150 	{
    151 		GLint maxTexSize = 0;
    152 		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
    153 
    154 		if (maxTexSize < TEST_CANVAS_SIZE)
    155 			throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_CANVAS_SIZE));
    156 	}
    157 	else
    158 		DE_ASSERT(false);
    159 
    160 	// gen shader
    161 
    162 	m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shader." << tcu::TestLog::EndMessage;
    163 
    164 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(genFragmentSource()));
    165 	m_testCtx.getLog() << *m_program;
    166 
    167 	if (!m_program->isOk())
    168 		throw tcu::TestError("shader compile failed");
    169 }
    170 
    171 void RenderCase::deinit (void)
    172 {
    173 	if (m_program)
    174 	{
    175 		delete m_program;
    176 		m_program = DE_NULL;
    177 	}
    178 }
    179 
    180 bool RenderCase::checkResultImage (const tcu::Surface& result)
    181 {
    182 	tcu::Surface	errorMask	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    183 	bool			error		= false;
    184 
    185 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output image." << tcu::TestLog::EndMessage;
    186 
    187 	for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
    188 	for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
    189 	{
    190 		const tcu::RGBA col = result.getPixel(x, y);
    191 
    192 		if (col.getGreen() == 255)
    193 			errorMask.setPixel(x, y, tcu::RGBA::green);
    194 		else
    195 		{
    196 			errorMask.setPixel(x, y, tcu::RGBA::red);
    197 			error = true;
    198 		}
    199 	}
    200 
    201 	if (error)
    202 	{
    203 		m_testCtx.getLog() << tcu::TestLog::Message << "Result image has missing or invalid pixels" << tcu::TestLog::EndMessage;
    204 		m_testCtx.getLog()
    205 			<< tcu::TestLog::ImageSet("Results", "Result verification")
    206 			<< tcu::TestLog::Image("Result",		"Result",		result)
    207 			<< tcu::TestLog::Image("Error mask",	"Error mask",	errorMask)
    208 			<< tcu::TestLog::EndImageSet;
    209 	}
    210 	else
    211 	{
    212 		m_testCtx.getLog()
    213 			<< tcu::TestLog::ImageSet("Results", "Result verification")
    214 			<< tcu::TestLog::Image("Result", "Result", result)
    215 			<< tcu::TestLog::EndImageSet;
    216 	}
    217 
    218 	return !error;
    219 }
    220 
    221 bool RenderCase::drawTestPattern (bool useTexture)
    222 {
    223 	static const tcu::Vec4 fullscreenQuad[4] =
    224 	{
    225 		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
    226 		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
    227 		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
    228 		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
    229 	};
    230 	const char* const	vertexSource		=	"#version 300 es\n"
    231 												"in highp vec4 a_pos;\n"
    232 												"out mediump vec4 v_position;\n"
    233 												"void main ()\n"
    234 												"{\n"
    235 												"	v_position = a_pos;\n"
    236 												"	gl_Position = a_pos;\n"
    237 												"}\n";
    238 	const char* const	fragmentSourceNoTex	=	"#version 300 es\n"
    239 												"layout(location = 0) out mediump vec4 fragColor;\n"
    240 												"in mediump vec4 v_position;\n"
    241 												"void main ()\n"
    242 												"{\n"
    243 												"	fragColor = vec4((v_position.x + 1.0) * 0.5, 1.0, 1.0, 1.0);\n"
    244 												"}\n";
    245 	const char* const	fragmentSourceTex	=	"#version 300 es\n"
    246 												"layout(location = 0) out mediump vec4 fragColor;\n"
    247 												"uniform mediump sampler2D u_sampler;\n"
    248 												"in mediump vec4 v_position;\n"
    249 												"void main ()\n"
    250 												"{\n"
    251 												"	fragColor = texture(u_sampler, v_position.xy);\n"
    252 												"}\n";
    253 	const char* const	fragmentSource		=	(useTexture) ? (fragmentSourceTex) : (fragmentSourceNoTex);
    254 	const tcu::RGBA		formatThreshold		= m_context.getRenderTarget().getPixelFormat().getColorThreshold();
    255 
    256 	tcu::Surface		resultImage			(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    257 	tcu::Surface		errorMask			(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    258 	bool				error				=	false;
    259 
    260 	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a test pattern to detect " << ((useTexture) ? ("texture sampling") : ("")) << " side-effects." << tcu::TestLog::EndMessage;
    261 
    262 	// draw pattern
    263 	{
    264 		const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
    265 		const glu::ShaderProgram	patternProgram	(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource));
    266 		const GLint					positionLoc		= gl.getAttribLocation(patternProgram.getProgram(), "a_pos");
    267 		GLuint						textureID		= 0;
    268 
    269 		if (useTexture)
    270 		{
    271 			const int textureSize = 32;
    272 			std::vector<tcu::Vector<deUint8, 4> > buffer(textureSize*textureSize);
    273 
    274 			for (int x = 0; x < textureSize; ++x)
    275 			for (int y = 0; y < textureSize; ++y)
    276 			{
    277 				// sum of two axis aligned gradients. Each gradient is 127 at the edges and 0 at the center.
    278 				// pattern is symmetric (x and y) => no discontinuity near boundary => no need to worry of results with LINEAR filtering near boundaries
    279 				const deUint8 redComponent = (deUint8)de::clamp(de::abs((float)x / (float)textureSize - 0.5f) * 255.0f + de::abs((float)y / (float)textureSize - 0.5f) * 255.0f, 0.0f, 255.0f);
    280 
    281 				buffer[x * textureSize + y] = tcu::Vector<deUint8, 4>(redComponent, 255, 255, 255);
    282 			}
    283 
    284 			gl.genTextures(1, &textureID);
    285 			gl.bindTexture(GL_TEXTURE_2D, textureID);
    286 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureSize, textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer[0].getPtr());
    287 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    288 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    289 		}
    290 
    291 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    292 		gl.clear(GL_COLOR_BUFFER_BIT);
    293 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    294 		gl.useProgram(patternProgram.getProgram());
    295 
    296 		if (useTexture)
    297 			gl.uniform1i(gl.getUniformLocation(patternProgram.getProgram(), "u_sampler"), 0);
    298 
    299 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &fullscreenQuad[0]);
    300 
    301 		gl.enableVertexAttribArray(positionLoc);
    302 		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
    303 		gl.disableVertexAttribArray(positionLoc);
    304 
    305 		gl.useProgram(0);
    306 		gl.finish();
    307 		GLU_EXPECT_NO_ERROR(gl.getError(), "RenderCase::drawTestPattern");
    308 
    309 		if (textureID)
    310 			gl.deleteTextures(1, &textureID);
    311 
    312 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
    313 	}
    314 
    315 	// verify pattern
    316 	for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
    317 	for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
    318 	{
    319 		const float			texGradientPosX = deFloatFrac((float)x * 2.0f / (float)TEST_CANVAS_SIZE);
    320 		const float			texGradientPosY = deFloatFrac((float)y * 2.0f / (float)TEST_CANVAS_SIZE);
    321 		const deUint8		texRedComponent = (deUint8)de::clamp(de::abs(texGradientPosX - 0.5f) * 255.0f + de::abs(texGradientPosY - 0.5f) * 255.0f, 0.0f, 255.0f);
    322 
    323 		const tcu::RGBA		refColTexture	= tcu::RGBA(texRedComponent, 255, 255, 255);
    324 		const tcu::RGBA		refColGradient	= tcu::RGBA((int)((float)x / (float)TEST_CANVAS_SIZE * 255.0f), 255, 255, 255);
    325 		const tcu::RGBA&	refCol			= (useTexture) ? (refColTexture) : (refColGradient);
    326 
    327 		const int			colorThreshold	= 10;
    328 		const tcu::RGBA		col				= resultImage.getPixel(x, y);
    329 		const tcu::IVec4	colorDiff		= tcu::abs(col.toIVec() - refCol.toIVec());
    330 
    331 		if (colorDiff.x() > formatThreshold.getRed()   + colorThreshold ||
    332 			colorDiff.y() > formatThreshold.getGreen() + colorThreshold ||
    333 			colorDiff.z() > formatThreshold.getBlue()  + colorThreshold)
    334 		{
    335 			errorMask.setPixel(x, y, tcu::RGBA::red);
    336 			error = true;
    337 		}
    338 		else
    339 			errorMask.setPixel(x, y, tcu::RGBA::green);
    340 	}
    341 
    342 	// report error
    343 	if (error)
    344 	{
    345 		m_testCtx.getLog() << tcu::TestLog::Message << "Test pattern has missing/invalid pixels" << tcu::TestLog::EndMessage;
    346 		m_testCtx.getLog()
    347 			<< tcu::TestLog::ImageSet("Results", "Result verification")
    348 			<< tcu::TestLog::Image("Result",		"Result",		resultImage)
    349 			<< tcu::TestLog::Image("Error mask",	"Error mask",	errorMask)
    350 			<< tcu::TestLog::EndImageSet;
    351 	}
    352 	else
    353 		m_testCtx.getLog() << tcu::TestLog::Message << "No side-effects found." << tcu::TestLog::EndMessage;
    354 
    355 	return !error;
    356 }
    357 
    358 class FramebufferRenderCase : public RenderCase
    359 {
    360 public:
    361 	enum FrameBufferType
    362 	{
    363 		FBO_DEFAULT = 0,
    364 		FBO_RGBA4,
    365 		FBO_RGB5_A1,
    366 		FBO_RGB565,
    367 		FBO_RGBA8,
    368 		FBO_RGB10_A2,
    369 		FBO_RGBA_FLOAT16,
    370 		FBO_RGBA_FLOAT32,
    371 
    372 		FBO_LAST
    373 	};
    374 
    375 							FramebufferRenderCase	(Context& context, const char* name, const char* desc, FrameBufferType fboType);
    376 	virtual					~FramebufferRenderCase	(void);
    377 
    378 	virtual void			init					(void);
    379 	virtual void			deinit					(void);
    380 	IterateResult			iterate					(void);
    381 
    382 	virtual void			testFBO					(void) = DE_NULL;
    383 
    384 protected:
    385 	const FrameBufferType	m_fboType;
    386 
    387 private:
    388 	GLuint					m_texID;
    389 	GLuint					m_fboID;
    390 };
    391 
    392 FramebufferRenderCase::FramebufferRenderCase (Context& context, const char* name, const char* desc, FrameBufferType fboType)
    393 	: RenderCase	(context, name, desc, (fboType == FBO_DEFAULT) ? (RENDERTARGETTYPE_SCREEN) : (RENDERTARGETTYPE_FBO))
    394 	, m_fboType		(fboType)
    395 	, m_texID		(0)
    396 	, m_fboID		(0)
    397 {
    398 	DE_ASSERT(m_fboType < FBO_LAST);
    399 }
    400 
    401 FramebufferRenderCase::~FramebufferRenderCase (void)
    402 {
    403 	deinit();
    404 }
    405 
    406 void FramebufferRenderCase::init (void)
    407 {
    408 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    409 
    410 	// check requirements
    411 	if (m_fboType == FBO_RGBA_FLOAT16)
    412 	{
    413 		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_half_float") &&
    414 			!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float"))
    415 			throw tcu::NotSupportedError("Color renderable half float texture required.");
    416 	}
    417 	else if (m_fboType == FBO_RGBA_FLOAT32)
    418 	{
    419 		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float"))
    420 			throw tcu::NotSupportedError("Color renderable float texture required.");
    421 	}
    422 
    423 	// gen shader
    424 	RenderCase::init();
    425 
    426 	// create render target
    427 	if (m_fboType == FBO_DEFAULT)
    428 	{
    429 		m_testCtx.getLog() << tcu::TestLog::Message << "Using default framebuffer." << tcu::TestLog::EndMessage;
    430 	}
    431 	else
    432 	{
    433 		GLuint internalFormat	= 0;
    434 		GLuint format			= 0;
    435 		GLuint type				= 0;
    436 
    437 		switch (m_fboType)
    438 		{
    439 			case FBO_RGBA4:			internalFormat = GL_RGBA4;		format = GL_RGBA;	type = GL_UNSIGNED_SHORT_4_4_4_4;		break;
    440 			case FBO_RGB5_A1:		internalFormat = GL_RGB5_A1;	format = GL_RGBA;	type = GL_UNSIGNED_SHORT_5_5_5_1;		break;
    441 			case FBO_RGB565:		internalFormat = GL_RGB565;		format = GL_RGB;	type = GL_UNSIGNED_SHORT_5_6_5;			break;
    442 			case FBO_RGBA8:			internalFormat = GL_RGBA8;		format = GL_RGBA;	type = GL_UNSIGNED_BYTE;				break;
    443 			case FBO_RGB10_A2:		internalFormat = GL_RGB10_A2;	format = GL_RGBA;	type = GL_UNSIGNED_INT_2_10_10_10_REV;	break;
    444 			case FBO_RGBA_FLOAT16:	internalFormat = GL_RGBA16F;	format = GL_RGBA;	type = GL_HALF_FLOAT;					break;
    445 			case FBO_RGBA_FLOAT32:	internalFormat = GL_RGBA32F;	format = GL_RGBA;	type = GL_FLOAT;						break;
    446 
    447 			default:
    448 				DE_ASSERT(false);
    449 				break;
    450 		}
    451 
    452 		m_testCtx.getLog() << tcu::TestLog::Message
    453 			<< "Creating fbo. Texture internalFormat = " << glu::getPixelFormatStr(internalFormat)
    454 			<< ", format = " << glu::getPixelFormatStr(format)
    455 			<< ", type = " << glu::getTypeStr(type)
    456 			<< tcu::TestLog::EndMessage;
    457 
    458 		// gen texture
    459 		gl.genTextures(1, &m_texID);
    460 		gl.bindTexture(GL_TEXTURE_2D, m_texID);
    461 		gl.texImage2D(GL_TEXTURE_2D, 0, internalFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, 0, format, type, DE_NULL);
    462 		GLU_EXPECT_NO_ERROR(gl.getError(), "texture init");
    463 
    464 		// gen fbo
    465 		gl.genFramebuffers(1, &m_fboID);
    466 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
    467 		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texID, 0);
    468 		GLU_EXPECT_NO_ERROR(gl.getError(), "fbo init");
    469 
    470 		if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    471 			throw tcu::NotSupportedError("could not create fbo for testing.");
    472 	}
    473 }
    474 
    475 void FramebufferRenderCase::deinit (void)
    476 {
    477 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    478 
    479 	if (m_texID)
    480 	{
    481 		gl.deleteTextures(1, &m_texID);
    482 		m_texID = 0;
    483 	}
    484 
    485 	if (m_fboID)
    486 	{
    487 		gl.deleteFramebuffers(1, &m_fboID);
    488 		m_fboID = 0;
    489 	}
    490 }
    491 
    492 FramebufferRenderCase::IterateResult FramebufferRenderCase::iterate (void)
    493 {
    494 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    495 
    496 	// bind fbo (or don't if we are using default)
    497 	if (m_fboID)
    498 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
    499 
    500 	// do something with special floats
    501 	testFBO();
    502 
    503 	return STOP;
    504 }
    505 
    506 /*--------------------------------------------------------------------*//*!
    507  * \brief Tests special floats as vertex attributes
    508  *
    509  * Tests that special floats transferred to the shader using vertex
    510  * attributes do not change the results of normal floating point
    511  * calculations. Special floats are put to 4-vector's x and y components and
    512  * value 1.0 is put to z and w. The resulting fragment's green channel
    513  * should be 1.0 everywhere.
    514  *
    515  * After the calculation test a test pattern is drawn to detect possible
    516  * floating point operation anomalies.
    517  *//*--------------------------------------------------------------------*/
    518 class VertexAttributeCase : public RenderCase
    519 {
    520 public:
    521 	enum Storage
    522 	{
    523 		STORAGE_BUFFER = 0,
    524 		STORAGE_CLIENT,
    525 
    526 		STORAGE_LAST
    527 	};
    528 	enum ShaderType
    529 	{
    530 		TYPE_VERTEX = 0,
    531 		TYPE_FRAGMENT,
    532 
    533 		TYPE_LAST
    534 	};
    535 
    536 						VertexAttributeCase			(Context& context, const char* name, const char* desc, Storage storage, ShaderType type);
    537 						~VertexAttributeCase		(void);
    538 
    539 	void				init						(void);
    540 	void				deinit						(void);
    541 	IterateResult		iterate						(void);
    542 
    543 private:
    544 	std::string			genVertexSource				(void) const;
    545 	std::string			genFragmentSource			(void) const;
    546 
    547 	const Storage		m_storage;
    548 	const ShaderType	m_type;
    549 	GLuint				m_positionVboID;
    550 	GLuint				m_attribVboID;
    551 	GLuint				m_elementVboID;
    552 };
    553 
    554 VertexAttributeCase::VertexAttributeCase (Context& context, const char* name, const char* desc, Storage storage, ShaderType type)
    555 	: RenderCase			(context, name, desc)
    556 	, m_storage				(storage)
    557 	, m_type				(type)
    558 	, m_positionVboID		(0)
    559 	, m_attribVboID			(0)
    560 	, m_elementVboID		(0)
    561 {
    562 	DE_ASSERT(storage < STORAGE_LAST);
    563 	DE_ASSERT(type < TYPE_LAST);
    564 }
    565 
    566 VertexAttributeCase::~VertexAttributeCase (void)
    567 {
    568 	deinit();
    569 }
    570 
    571 void VertexAttributeCase::init (void)
    572 {
    573 	RenderCase::init();
    574 
    575 	// init gl resources
    576 	if (m_storage == STORAGE_BUFFER)
    577 	{
    578 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    579 
    580 		gl.genBuffers(1, &m_positionVboID);
    581 		gl.genBuffers(1, &m_attribVboID);
    582 		gl.genBuffers(1, &m_elementVboID);
    583 	}
    584 }
    585 
    586 void VertexAttributeCase::deinit (void)
    587 {
    588 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    589 
    590 	RenderCase::deinit();
    591 
    592 	if (m_attribVboID)
    593 	{
    594 		gl.deleteBuffers(1, &m_attribVboID);
    595 		m_attribVboID = 0;
    596 	}
    597 
    598 	if (m_positionVboID)
    599 	{
    600 		gl.deleteBuffers(1, &m_positionVboID);
    601 		m_positionVboID = 0;
    602 	}
    603 
    604 	if (m_elementVboID)
    605 	{
    606 		gl.deleteBuffers(1, &m_elementVboID);
    607 		m_elementVboID = 0;
    608 	}
    609 }
    610 
    611 VertexAttributeCase::IterateResult VertexAttributeCase::iterate (void)
    612 {
    613 	// Create a [s_specialFloats] X [s_specialFloats] grid of vertices with each vertex having 2 [s_specialFloats] values
    614 	// and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
    615 
    616 	std::vector<tcu::Vec4>	gridVertices	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
    617 	std::vector<tcu::UVec4>	gridAttributes	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
    618 	std::vector<deUint16>	indices			((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
    619 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    620 
    621 	// vertices
    622 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
    623 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
    624 	{
    625 		const deUint32	one		= 0x3F800000;
    626 		const float		posX	= (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
    627 		const float		posY	= (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
    628 
    629 		gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
    630 		gridAttributes[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
    631 	}
    632 
    633 	// tiles
    634 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
    635 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
    636 	{
    637 		const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
    638 
    639 		indices[baseNdx + 0] = (x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0);
    640 		indices[baseNdx + 1] = (x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1);
    641 		indices[baseNdx + 2] = (x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0);
    642 
    643 		indices[baseNdx + 3] = (x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0);
    644 		indices[baseNdx + 4] = (x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1);
    645 		indices[baseNdx + 5] = (x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1);
    646 	}
    647 
    648 	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a grid with the shader. Setting a_attr for each vertex to (special, special, 1, 1)." << tcu::TestLog::EndMessage;
    649 
    650 	// Draw grid
    651 	{
    652 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
    653 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
    654 		const GLint				attribLoc	= gl.getAttribLocation(m_program->getProgram(), "a_attr");
    655 
    656 		if (m_storage == STORAGE_BUFFER)
    657 		{
    658 			gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
    659 			gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridVertices.size() * sizeof(tcu::Vec4)), &gridVertices[0], GL_STATIC_DRAW);
    660 			GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
    661 
    662 			gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
    663 			gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridAttributes.size() * sizeof(tcu::UVec4)), &gridAttributes[0], GL_STATIC_DRAW);
    664 			GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
    665 
    666 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementVboID);
    667 			gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size() * sizeof(deUint16)), &indices[0], GL_STATIC_DRAW);
    668 			GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
    669 		}
    670 
    671 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    672 		gl.clear(GL_COLOR_BUFFER_BIT);
    673 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    674 		gl.useProgram(m_program->getProgram());
    675 
    676 		if (m_storage == STORAGE_BUFFER)
    677 		{
    678 			gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
    679 			gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    680 
    681 			gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
    682 			gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    683 
    684 			gl.enableVertexAttribArray(positionLoc);
    685 			gl.enableVertexAttribArray(attribLoc);
    686 			gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, DE_NULL);
    687 			gl.disableVertexAttribArray(positionLoc);
    688 			gl.disableVertexAttribArray(attribLoc);
    689 
    690 			gl.bindBuffer(GL_ARRAY_BUFFER, 0);
    691 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    692 		}
    693 		else if (m_storage == STORAGE_CLIENT)
    694 		{
    695 			gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
    696 			gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridAttributes[0]);
    697 
    698 			gl.enableVertexAttribArray(positionLoc);
    699 			gl.enableVertexAttribArray(attribLoc);
    700 			gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
    701 			gl.disableVertexAttribArray(positionLoc);
    702 			gl.disableVertexAttribArray(attribLoc);
    703 		}
    704 		else
    705 			DE_ASSERT(false);
    706 
    707 		gl.useProgram(0);
    708 		gl.finish();
    709 		GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
    710 
    711 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
    712 	}
    713 
    714 	// verify everywhere was drawn (all pixels have Green = 255)
    715 	if (!checkResultImage(resultImage))
    716 	{
    717 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
    718 		return STOP;
    719 	}
    720 
    721 	// test drawing still works
    722 	if (!drawTestPattern(false))
    723 	{
    724 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
    725 		return STOP;
    726 	}
    727 
    728 	// all ok
    729 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    730 	return STOP;
    731 }
    732 
    733 std::string VertexAttributeCase::genVertexSource (void) const
    734 {
    735 	if (m_type == TYPE_VERTEX)
    736 		return
    737 			"#version 300 es\n"
    738 			"in highp vec4 a_pos;\n"
    739 			"in highp vec4 a_attr;\n"
    740 			"out mediump vec4 v_out;\n"
    741 			"void main ()\n"
    742 			"{\n"
    743 			"	highp vec2 a1 = a_attr.xz + a_attr.yw; // add\n"
    744 			"	highp vec2 a2 = a_attr.xz - a_attr.yw; // sub\n"
    745 			"	highp vec2 a3 = a_attr.xz * a_attr.yw; // mul\n"
    746 			"	highp vec2 a4 = a_attr.xz / a_attr.yw; // div\n"
    747 			"	highp vec2 a5 = a_attr.xz + a_attr.yw * a_attr.xz; // fma\n"
    748 			"\n"
    749 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
    750 			"	v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
    751 			"	gl_Position = a_pos;\n"
    752 			"}\n";
    753 	else
    754 		return s_attrPassthroughVertexShaderSource;
    755 }
    756 
    757 std::string VertexAttributeCase::genFragmentSource (void) const
    758 {
    759 	if (m_type == TYPE_VERTEX)
    760 		return s_colorPassthroughFragmentShaderSource;
    761 	else
    762 		return
    763 			"#version 300 es\n"
    764 			"layout(location = 0) out mediump vec4 fragColor;\n"
    765 			"in highp vec4 v_attr;\n"
    766 			"void main ()\n"
    767 			"{\n"
    768 			"	highp vec2 a1 = v_attr.xz + v_attr.yw; // add\n"
    769 			"	highp vec2 a2 = v_attr.xz - v_attr.yw; // sub\n"
    770 			"	highp vec2 a3 = v_attr.xz * v_attr.yw; // mul\n"
    771 			"	highp vec2 a4 = v_attr.xz / v_attr.yw; // div\n"
    772 			"	highp vec2 a5 = v_attr.xz + v_attr.yw * v_attr.xz; // fma\n"
    773 			"	highp vec2 a6 = dFdx(v_attr.xz);\n"
    774 			"\n"
    775 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y) - 6.0);\n"
    776 			"	fragColor = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x+a6.x, 1.0);\n"
    777 			"}\n";
    778 }
    779 
    780 /*--------------------------------------------------------------------*//*!
    781  * \brief Tests special floats as uniforms
    782  *
    783  * Tests that special floats transferred to the shader as uniforms do
    784  * not change the results of normal floating point calculations. Special
    785  * floats are put to 4-vector's x and y components and value 1.0 is put to
    786  * z and w. The resulting fragment's green channel should be 1.0
    787  * everywhere.
    788  *
    789  * After the calculation test a test pattern is drawn to detect possible
    790  * floating point operation anomalies.
    791  *//*--------------------------------------------------------------------*/
    792 class UniformCase : public RenderCase
    793 {
    794 public:
    795 	enum ShaderType
    796 	{
    797 		TYPE_VERTEX = 0,
    798 		TYPE_FRAGMENT,
    799 	};
    800 
    801 						UniformCase					(Context& context, const char* name, const char* desc, ShaderType type);
    802 						~UniformCase				(void);
    803 
    804 	void				init						(void);
    805 	void				deinit						(void);
    806 	IterateResult		iterate						(void);
    807 
    808 private:
    809 	std::string			genVertexSource				(void) const;
    810 	std::string			genFragmentSource			(void) const;
    811 
    812 	const ShaderType	m_type;
    813 };
    814 
    815 UniformCase::UniformCase (Context& context, const char* name, const char* desc, ShaderType type)
    816 	: RenderCase	(context, name, desc)
    817 	, m_type		(type)
    818 {
    819 }
    820 
    821 UniformCase::~UniformCase (void)
    822 {
    823 	deinit();
    824 }
    825 
    826 void UniformCase::init (void)
    827 {
    828 	RenderCase::init();
    829 }
    830 
    831 void UniformCase::deinit (void)
    832 {
    833 	RenderCase::deinit();
    834 }
    835 
    836 UniformCase::IterateResult UniformCase::iterate (void)
    837 {
    838 	// Create a [s_specialFloats] X [s_specialFloats] grid of tile with each tile having 2 [s_specialFloats] values
    839 	// and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
    840 
    841 	std::vector<tcu::Vec4>	gridVertices	((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
    842 	std::vector<deUint16>	indices			(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
    843 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    844 
    845 	// vertices
    846 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
    847 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
    848 	{
    849 		const float		posX	= (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
    850 		const float		posY	= (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f;
    851 
    852 		gridVertices[x * (DE_LENGTH_OF_ARRAY(s_specialFloats)+1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
    853 	}
    854 
    855 	// tiles
    856 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
    857 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
    858 	{
    859 		const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats)) + y) * 6;
    860 
    861 		indices[baseNdx + 0] = (x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0);
    862 		indices[baseNdx + 1] = (x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1);
    863 		indices[baseNdx + 2] = (x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0);
    864 
    865 		indices[baseNdx + 3] = (x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0);
    866 		indices[baseNdx + 4] = (x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1);
    867 		indices[baseNdx + 5] = (x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1);
    868 	}
    869 
    870 	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a grid with the shader. Setting u_special for vertex each tile to (special, special, 1, 1)." << tcu::TestLog::EndMessage;
    871 
    872 	// Draw grid
    873 	{
    874 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
    875 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
    876 		const GLint				specialLoc	= gl.getUniformLocation(m_program->getProgram(), "u_special");
    877 
    878 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    879 		gl.clear(GL_COLOR_BUFFER_BIT);
    880 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    881 		gl.useProgram(m_program->getProgram());
    882 
    883 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
    884 		gl.enableVertexAttribArray(positionLoc);
    885 
    886 		for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
    887 		for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
    888 		{
    889 			const deUint32		one				= 0x3F800000;
    890 			const tcu::UVec4	uniformValue	= tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
    891 			const int			indexIndex		= (x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y) * 6;
    892 
    893 			gl.uniform4fv(specialLoc, 1, (const float*)uniformValue.getPtr());
    894 			gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
    895 		}
    896 
    897 
    898 		gl.disableVertexAttribArray(positionLoc);
    899 
    900 		gl.useProgram(0);
    901 		gl.finish();
    902 		GLU_EXPECT_NO_ERROR(gl.getError(), "UniformCase::iterate");
    903 
    904 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
    905 	}
    906 
    907 	// verify everywhere was drawn (all pixels have Green = 255)
    908 	if (!checkResultImage(resultImage))
    909 	{
    910 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
    911 		return STOP;
    912 	}
    913 
    914 	// test drawing still works
    915 	if (!drawTestPattern(false))
    916 	{
    917 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
    918 		return STOP;
    919 	}
    920 
    921 	// all ok
    922 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    923 	return STOP;
    924 }
    925 
    926 std::string UniformCase::genVertexSource (void) const
    927 {
    928 	if (m_type == TYPE_VERTEX)
    929 		return
    930 			"#version 300 es\n"
    931 			"in highp vec4 a_pos;\n"
    932 			"uniform highp vec4 u_special;\n"
    933 			"out mediump vec4 v_out;\n"
    934 			"void main ()\n"
    935 			"{\n"
    936 			"	highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
    937 			"	highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
    938 			"	highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
    939 			"	highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
    940 			"	highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
    941 			"\n"
    942 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
    943 			"	v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
    944 			"	gl_Position = a_pos;\n"
    945 			"}\n";
    946 	else
    947 		return
    948 			"#version 300 es\n"
    949 			"in highp vec4 a_pos;\n"
    950 			"void main ()\n"
    951 			"{\n"
    952 			"	gl_Position = a_pos;\n"
    953 			"}\n";
    954 }
    955 
    956 std::string UniformCase::genFragmentSource (void) const
    957 {
    958 	if (m_type == TYPE_VERTEX)
    959 		return s_colorPassthroughFragmentShaderSource;
    960 	else
    961 		return
    962 			"#version 300 es\n"
    963 			"layout(location = 0) out mediump vec4 fragColor;\n"
    964 			"uniform highp vec4 u_special;\n"
    965 			"void main ()\n"
    966 			"{\n"
    967 			"	highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
    968 			"	highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
    969 			"	highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
    970 			"	highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
    971 			"	highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
    972 			"	highp vec2 a6 = mod(u_special.xz, u_special.yw);\n"
    973 			"	highp vec2 a7 = mix(u_special.xz, u_special.yw, a6);\n"
    974 			"\n"
    975 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y + a7.y) - 7.0);\n"
    976 			"	fragColor = vec4(a1.x*a3.x, green, a5.x*a4.x + a2.x*a7.x, 1.0);\n"
    977 			"}\n";
    978 }
    979 
    980 /*--------------------------------------------------------------------*//*!
    981  * \brief Tests special floats in floating point textures
    982  *
    983  * Tests that sampling special floats from a floating point texture
    984  * does not affect the values of other color components of the sample. Test
    985  * samples a RG texture with R channel filled with special floats and G
    986  * channel filled with test values.
    987  *
    988  * Tests that linear sampling using compare mode = COMPARE_REF_TO_TEXTURE
    989  * of a floating point depth texture containing special floating point
    990  * values does not produce values outside the [0, 1] range.
    991  *
    992  * After the calculation test a test pattern is drawn to detect possible
    993  * texture sampling anomalies.
    994  *//*--------------------------------------------------------------------*/
    995 class TextureCase : public RenderCase
    996 {
    997 public:
    998 	enum ShaderType
    999 	{
   1000 		TYPE_VERTEX = 0,
   1001 		TYPE_FRAGMENT,
   1002 
   1003 		TYPE_LAST
   1004 	};
   1005 	enum TextureType
   1006 	{
   1007 		TEXTURE_FLOAT = 0,
   1008 		TEXTURE_DEPTH,
   1009 
   1010 		TEXTURE_LAST
   1011 	};
   1012 	enum UploadType
   1013 	{
   1014 		UPLOAD_CLIENT = 0,
   1015 		UPLOAD_PBO,
   1016 
   1017 		UPLOAD_LAST
   1018 	};
   1019 
   1020 						TextureCase					(Context& context, const char* name, const char* desc, ShaderType type, TextureType texType, UploadType uploadType);
   1021 						~TextureCase				(void);
   1022 
   1023 	void				init						(void);
   1024 	void				deinit						(void);
   1025 	IterateResult		iterate						(void);
   1026 
   1027 private:
   1028 	std::string			genVertexSource				(void) const;
   1029 	std::string			genFragmentSource			(void) const;
   1030 
   1031 	const ShaderType	m_type;
   1032 	const TextureType	m_textureType;
   1033 	const UploadType	m_uploadType;
   1034 	GLuint				m_textureID;
   1035 	GLuint				m_pboID;
   1036 };
   1037 
   1038 TextureCase::TextureCase (Context& context, const char* name, const char* desc, ShaderType type, TextureType texType, UploadType uploadType)
   1039 	: RenderCase	(context, name, desc)
   1040 	, m_type		(type)
   1041 	, m_textureType	(texType)
   1042 	, m_uploadType	(uploadType)
   1043 	, m_textureID	(0)
   1044 	, m_pboID		(0)
   1045 {
   1046 	DE_ASSERT(type < TYPE_LAST);
   1047 	DE_ASSERT(texType < TEXTURE_LAST);
   1048 	DE_ASSERT(uploadType < UPLOAD_LAST);
   1049 }
   1050 
   1051 TextureCase::~TextureCase (void)
   1052 {
   1053 	deinit();
   1054 }
   1055 
   1056 void TextureCase::init (void)
   1057 {
   1058 	// requirements
   1059 	{
   1060 		GLint maxTextureSize = 0;
   1061 		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
   1062 		if (maxTextureSize < TEST_TEXTURE_SIZE)
   1063 			throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_TEXTURE_SIZE));
   1064 	}
   1065 
   1066 	RenderCase::init();
   1067 
   1068 	// gen texture
   1069 	{
   1070 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   1071 		de::Random				rnd			(12345);
   1072 
   1073 		gl.genTextures(1, &m_textureID);
   1074 		gl.bindTexture(GL_TEXTURE_2D, m_textureID);
   1075 
   1076 		if (m_uploadType == UPLOAD_PBO)
   1077 		{
   1078 			gl.genBuffers(1, &m_pboID);
   1079 			gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pboID);
   1080 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
   1081 		}
   1082 
   1083 		if (m_textureType == TEXTURE_FLOAT)
   1084 		{
   1085 			std::vector<deUint32>	texData	(TEST_TEXTURE_SIZE*TEST_TEXTURE_SIZE*2);
   1086 			const deUint32*			dataPtr = (m_uploadType == UPLOAD_CLIENT) ? (&texData[0]) : (DE_NULL);
   1087 
   1088 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D 2-component float texture. Pixel contents are of form (special, 1)." << tcu::TestLog::EndMessage;
   1089 
   1090 			// set green channel to 1.0
   1091 			for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
   1092 			for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
   1093 			{
   1094 				texData[(x * TEST_TEXTURE_SIZE + y) * 2 + 0] = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1095 				texData[(x * TEST_TEXTURE_SIZE + y) * 2 + 1] = 0x3F800000;	// one
   1096 			}
   1097 
   1098 			if (m_uploadType == UPLOAD_PBO)
   1099 				gl.bufferData(GL_PIXEL_UNPACK_BUFFER, (glw::GLsizeiptr)(texData.size() * sizeof(deUint32)), &texData[0], GL_STATIC_DRAW);
   1100 
   1101 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_RG32F, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RG, GL_FLOAT, dataPtr);
   1102 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   1103 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   1104 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
   1105 		}
   1106 		else if (m_textureType == TEXTURE_DEPTH)
   1107 		{
   1108 			std::vector<deUint32>	texData	(TEST_TEXTURE_SIZE*TEST_TEXTURE_SIZE);
   1109 			const deUint32*			dataPtr = (m_uploadType == UPLOAD_CLIENT) ? (&texData[0]) : (DE_NULL);
   1110 
   1111 			m_testCtx.getLog() << tcu::TestLog::Message
   1112 				<< "Creating a 2D depth texture and filling it with special floating point values.\n"
   1113 				<< "  TEXTURE_COMPARE_MODE = COMPARE_REF_TO_TEXTURE"
   1114 				<< tcu::TestLog::EndMessage;
   1115 
   1116 			for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
   1117 			for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
   1118 				texData[x * TEST_TEXTURE_SIZE + y] = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1119 
   1120 			if (m_uploadType == UPLOAD_PBO)
   1121 				gl.bufferData(GL_PIXEL_UNPACK_BUFFER, (glw::GLsizeiptr)(texData.size() * sizeof(deUint32)), &texData[0], GL_STATIC_DRAW);
   1122 
   1123 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_DEPTH_COMPONENT, GL_FLOAT, dataPtr);
   1124 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
   1125 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
   1126 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1127 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   1128 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
   1129 		}
   1130 		else
   1131 			DE_ASSERT(false);
   1132 
   1133 		if (m_uploadType == UPLOAD_PBO)
   1134 		{
   1135 			m_testCtx.getLog() << tcu::TestLog::Message << "PBO used for image upload." << tcu::TestLog::EndMessage;
   1136 
   1137 			gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
   1138 			gl.deleteBuffers(1, &m_pboID);
   1139 			m_pboID = 0;
   1140 		}
   1141 	}
   1142 }
   1143 
   1144 void TextureCase::deinit (void)
   1145 {
   1146 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1147 
   1148 	RenderCase::deinit();
   1149 
   1150 	if (m_textureID)
   1151 	{
   1152 		gl.deleteTextures(1, &m_textureID);
   1153 		m_textureID = 0;
   1154 	}
   1155 	if (m_pboID)
   1156 	{
   1157 		gl.deleteBuffers(1, &m_pboID);
   1158 		m_pboID = 0;
   1159 	}
   1160 }
   1161 
   1162 TextureCase::IterateResult TextureCase::iterate (void)
   1163 {
   1164 	// Draw a grid and texture it with a floating point texture containing special values. If all goes well, nothing special should happen
   1165 
   1166 	const int				gridSize		= 16;
   1167 	std::vector<tcu::Vec4>	gridVertices	(gridSize * gridSize);
   1168 	std::vector<tcu::Vec2>	gridTexCoords	(gridSize * gridSize);
   1169 	std::vector<deUint16>	indices			((gridSize - 1) * (gridSize - 1) * 6);
   1170 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1171 
   1172 	// vertices
   1173 	for (int x = 0; x < gridSize; ++x)
   1174 	for (int y = 0; y < gridSize; ++y)
   1175 	{
   1176 		const float posX		= (float)x / ((float)gridSize - 1.0f) * 2.0f - 1.0f; // map from [0, gridSize - 1] to [-1, 1]
   1177 		const float posY		= (float)y / ((float)gridSize - 1.0f) * 2.0f - 1.0f;
   1178 		const float texCoordX	= deFloatPow(2.0f, (float)x - (float)gridSize / 2.0f);
   1179 		const float texCoordY	= deFloatPow(2.0f, (float)y - (float)gridSize / 2.0f);
   1180 
   1181 		gridVertices[x * gridSize + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
   1182 		gridTexCoords[x * gridSize + y]	= tcu::Vec2(texCoordX, texCoordY);
   1183 	}
   1184 
   1185 	// tiles
   1186 	for (int x = 0; x < gridSize - 1; ++x)
   1187 	for (int y = 0; y < gridSize - 1; ++y)
   1188 	{
   1189 		const int baseNdx = (x * (gridSize - 1) + y) * 6;
   1190 
   1191 		indices[baseNdx + 0] = (x+0) * gridSize + (y+0);
   1192 		indices[baseNdx + 1] = (x+1) * gridSize + (y+1);
   1193 		indices[baseNdx + 2] = (x+1) * gridSize + (y+0);
   1194 
   1195 		indices[baseNdx + 3] = (x+0) * gridSize + (y+0);
   1196 		indices[baseNdx + 4] = (x+1) * gridSize + (y+1);
   1197 		indices[baseNdx + 5] = (x+0) * gridSize + (y+1);
   1198 	}
   1199 
   1200 	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a textured grid with the shader." << tcu::TestLog::EndMessage;
   1201 
   1202 	// Draw grid
   1203 	{
   1204 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   1205 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
   1206 		const GLint				texCoordLoc	= gl.getAttribLocation(m_program->getProgram(), "a_attr");
   1207 		const GLint				samplerLoc	= gl.getUniformLocation(m_program->getProgram(), "u_sampler");
   1208 
   1209 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1210 		gl.clear(GL_COLOR_BUFFER_BIT);
   1211 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1212 		gl.useProgram(m_program->getProgram());
   1213 
   1214 		gl.uniform1i(samplerLoc, 0);
   1215 		gl.bindTexture(GL_TEXTURE_2D, m_textureID);
   1216 
   1217 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
   1218 		gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]);
   1219 
   1220 		gl.enableVertexAttribArray(positionLoc);
   1221 		gl.enableVertexAttribArray(texCoordLoc);
   1222 		gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
   1223 		gl.disableVertexAttribArray(positionLoc);
   1224 		gl.disableVertexAttribArray(texCoordLoc);
   1225 
   1226 		gl.useProgram(0);
   1227 		gl.finish();
   1228 		GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::iterate");
   1229 
   1230 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
   1231 	}
   1232 
   1233 	// verify everywhere was drawn (all pixels have Green = 255)
   1234 	if (!checkResultImage(resultImage))
   1235 	{
   1236 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
   1237 		return STOP;
   1238 	}
   1239 
   1240 	// test drawing and textures still works
   1241 	if (!drawTestPattern(true))
   1242 	{
   1243 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
   1244 		return STOP;
   1245 	}
   1246 
   1247 	// all ok
   1248 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1249 	return STOP;
   1250 }
   1251 
   1252 std::string TextureCase::genVertexSource (void) const
   1253 {
   1254 	// vertex shader is passthrough, fragment does the calculations
   1255 	if (m_type == TYPE_FRAGMENT)
   1256 		return s_attrPassthroughVertexShaderSource;
   1257 
   1258 	// vertex shader does the calculations
   1259 	std::ostringstream buf;
   1260 	buf <<	"#version 300 es\n"
   1261 			"in highp vec4 a_pos;\n"
   1262 			"in highp vec2 a_attr;\n"
   1263 			"out mediump vec4 v_out;\n";
   1264 
   1265 	if (m_textureType == TEXTURE_FLOAT)
   1266 		buf <<	"uniform highp sampler2D u_sampler;\n";
   1267 	else if (m_textureType == TEXTURE_DEPTH)
   1268 		buf <<	"uniform highp sampler2DShadow u_sampler;\n";
   1269 	else
   1270 		DE_ASSERT(DE_FALSE);
   1271 
   1272 	buf <<	"void main ()\n"
   1273 			"{\n";
   1274 
   1275 	if (m_textureType == TEXTURE_FLOAT)
   1276 		buf <<	"	v_out = vec4(textureLod(u_sampler, a_attr, 0.0).rg, 1.0, 1.0);\n";
   1277 	else if (m_textureType == TEXTURE_DEPTH)
   1278 		buf <<	"	highp float a1 = textureLod(u_sampler, vec3(a_attr, 0.0), 0.0);\n"
   1279 				"	v_out = vec4(a1, (a1 > 1.0 || a1 < 0.0) ? (0.0) : (1.0), 1.0, 1.0);\n";
   1280 	else
   1281 		DE_ASSERT(DE_FALSE);
   1282 
   1283 	buf <<	"	gl_Position = a_pos;\n"
   1284 			"}\n";
   1285 	return buf.str();
   1286 }
   1287 
   1288 std::string TextureCase::genFragmentSource (void) const
   1289 {
   1290 	// fragment shader is passthrough
   1291 	if (m_type == TYPE_VERTEX)
   1292 		return s_colorPassthroughFragmentShaderSource;
   1293 
   1294 	// fragment shader does the calculations
   1295 	std::ostringstream buf;
   1296 	buf <<	"#version 300 es\n"
   1297 			"layout(location = 0) out mediump vec4 fragColor;\n";
   1298 
   1299 	if (m_textureType == TEXTURE_FLOAT)
   1300 		buf <<	"uniform highp sampler2D u_sampler;\n";
   1301 	else if (m_textureType == TEXTURE_DEPTH)
   1302 		buf <<	"uniform highp sampler2DShadow u_sampler;\n";
   1303 	else
   1304 		DE_ASSERT(DE_FALSE);
   1305 
   1306 	buf <<	"in highp vec4 v_attr;\n"
   1307 			"void main ()\n"
   1308 			"{\n";
   1309 
   1310 	if (m_textureType == TEXTURE_FLOAT)
   1311 		buf <<	"	highp vec2 a1 = texture(u_sampler, v_attr.xy).rg;\n"
   1312 				"	fragColor = vec4(a1.x, a1.y, 1.0, 1.0);\n";
   1313 	else if (m_textureType == TEXTURE_DEPTH)
   1314 		buf <<	"	highp float a1 = texture(u_sampler, vec3(v_attr.xy, 0.0));\n"
   1315 				"	fragColor = vec4(a1, (a1 > 1.0 || a1 < 0.0) ? (0.0) : (1.0), 1.0, 1.0);\n";
   1316 	else
   1317 		DE_ASSERT(DE_FALSE);
   1318 
   1319 	buf << "}\n";
   1320 	return buf.str();
   1321 }
   1322 
   1323 /*--------------------------------------------------------------------*//*!
   1324  * \brief Tests special floats as texture samping arguments
   1325  *
   1326  * Tests that special floats given as texture coordinates or LOD levels
   1327  * to sampling functions do not return invalid values (values not in the
   1328  * texture). Every texel's green component is 1.0.
   1329  *
   1330  * After the calculation test a test pattern is drawn to detect possible
   1331  * texture sampling anomalies.
   1332  *//*--------------------------------------------------------------------*/
   1333 class TextureSamplerCase : public RenderCase
   1334 {
   1335 public:
   1336 	enum ShaderType
   1337 	{
   1338 		TYPE_VERTEX = 0,
   1339 		TYPE_FRAGMENT,
   1340 
   1341 		TYPE_LAST
   1342 	};
   1343 	enum TestType
   1344 	{
   1345 		TEST_TEX_COORD = 0,
   1346 		TEST_LOD,
   1347 		TEST_GRAD,
   1348 		TEST_TEX_COORD_CUBE,
   1349 
   1350 		TEST_LAST
   1351 	};
   1352 
   1353 						TextureSamplerCase			(Context& context, const char* name, const char* desc, ShaderType type, TestType testType);
   1354 						~TextureSamplerCase			(void);
   1355 
   1356 	void				init						(void);
   1357 	void				deinit						(void);
   1358 	IterateResult		iterate						(void);
   1359 
   1360 private:
   1361 	std::string			genVertexSource				(void) const;
   1362 	std::string			genFragmentSource			(void) const;
   1363 
   1364 	const ShaderType	m_type;
   1365 	const TestType		m_testType;
   1366 	GLuint				m_textureID;
   1367 };
   1368 
   1369 TextureSamplerCase::TextureSamplerCase (Context& context, const char* name, const char* desc, ShaderType type, TestType testType)
   1370 	: RenderCase	(context, name, desc)
   1371 	, m_type		(type)
   1372 	, m_testType	(testType)
   1373 	, m_textureID	(0)
   1374 {
   1375 	DE_ASSERT(type < TYPE_LAST);
   1376 	DE_ASSERT(testType < TEST_LAST);
   1377 }
   1378 
   1379 TextureSamplerCase::~TextureSamplerCase (void)
   1380 {
   1381 	deinit();
   1382 }
   1383 
   1384 void TextureSamplerCase::init (void)
   1385 {
   1386 	// requirements
   1387 	{
   1388 		GLint maxTextureSize = 0;
   1389 		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
   1390 		if (maxTextureSize < TEST_TEXTURE_SIZE)
   1391 			throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_TEXTURE_SIZE));
   1392 	}
   1393 
   1394 	RenderCase::init();
   1395 
   1396 	// gen texture
   1397 	{
   1398 		const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
   1399 		std::vector<deUint8>	texData	(TEST_TEXTURE_SIZE*TEST_TEXTURE_SIZE*4);
   1400 		de::Random				rnd		(12345);
   1401 
   1402 		gl.genTextures(1, &m_textureID);
   1403 
   1404 		for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
   1405 		for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
   1406 		{
   1407 			// RGBA8, green and alpha channel are always 255 for verification
   1408 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 0] = rnd.getUint32() & 0xFF;
   1409 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 1] = 0xFF;
   1410 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 2] = rnd.getUint32() & 0xFF;
   1411 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 3] = 0xFF;
   1412 		}
   1413 
   1414 		if (m_testType == TEST_TEX_COORD)
   1415 		{
   1416 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D texture with a test pattern." << tcu::TestLog::EndMessage;
   1417 
   1418 			gl.bindTexture(GL_TEXTURE_2D, m_textureID);
   1419 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
   1420 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1421 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   1422 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
   1423 		}
   1424 		else if (m_testType == TEST_LOD || m_testType == TEST_GRAD)
   1425 		{
   1426 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a mipmapped 2D texture with a test pattern." << tcu::TestLog::EndMessage;
   1427 
   1428 			gl.bindTexture(GL_TEXTURE_2D, m_textureID);
   1429 
   1430 			for (int level = 0; (TEST_TEXTURE_SIZE >> level); ++level)
   1431 				gl.texImage2D(GL_TEXTURE_2D, level, GL_RGBA8, TEST_TEXTURE_SIZE >> level, TEST_TEXTURE_SIZE >> level, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
   1432 
   1433 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1434 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
   1435 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
   1436 		}
   1437 		else if (m_testType == TEST_TEX_COORD_CUBE)
   1438 		{
   1439 			DE_STATIC_ASSERT(TEST_TEXTURE_CUBE_SIZE <= TEST_TEXTURE_SIZE);
   1440 
   1441 			static const GLenum faces[] =
   1442 			{
   1443 				GL_TEXTURE_CUBE_MAP_POSITIVE_X,
   1444 				GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
   1445 				GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
   1446 				GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
   1447 				GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
   1448 				GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
   1449 			};
   1450 
   1451 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a cube map with a test pattern." << tcu::TestLog::EndMessage;
   1452 
   1453 			gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
   1454 
   1455 			for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); ++faceNdx)
   1456 				gl.texImage2D(faces[faceNdx], 0, GL_RGBA8, TEST_TEXTURE_CUBE_SIZE, TEST_TEXTURE_CUBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
   1457 
   1458 			gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1459 			gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   1460 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
   1461 		}
   1462 		else
   1463 			DE_ASSERT(DE_FALSE);
   1464 	}
   1465 }
   1466 
   1467 void TextureSamplerCase::deinit (void)
   1468 {
   1469 	RenderCase::deinit();
   1470 
   1471 	if (m_textureID)
   1472 	{
   1473 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1474 
   1475 		gl.deleteTextures(1, &m_textureID);
   1476 		m_textureID = 0;
   1477 	}
   1478 }
   1479 
   1480 TextureSamplerCase::IterateResult TextureSamplerCase::iterate (void)
   1481 {
   1482 	// Draw a grid and texture it with a texture and sample it using special special values. The result samples should all have the green channel at 255 as per the test image.
   1483 
   1484 	std::vector<tcu::Vec4>	gridVertices	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
   1485 	std::vector<tcu::UVec2>	gridTexCoords	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
   1486 	std::vector<deUint16>	indices			((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
   1487 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1488 
   1489 	// vertices
   1490 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
   1491 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
   1492 	{
   1493 		const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
   1494 		const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
   1495 
   1496 		gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
   1497 		gridTexCoords[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::UVec2(s_specialFloats[x], s_specialFloats[y]);
   1498 	}
   1499 
   1500 	// tiles
   1501 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
   1502 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
   1503 	{
   1504 		const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
   1505 
   1506 		indices[baseNdx + 0] = (x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0);
   1507 		indices[baseNdx + 1] = (x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1);
   1508 		indices[baseNdx + 2] = (x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0);
   1509 
   1510 		indices[baseNdx + 3] = (x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0);
   1511 		indices[baseNdx + 4] = (x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1);
   1512 		indices[baseNdx + 5] = (x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1);
   1513 	}
   1514 
   1515 	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a textured grid with the shader. Sampling from the texture using special floating point values." << tcu::TestLog::EndMessage;
   1516 
   1517 	// Draw grid
   1518 	{
   1519 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   1520 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
   1521 		const GLint				texCoordLoc	= gl.getAttribLocation(m_program->getProgram(), "a_attr");
   1522 		const GLint				samplerLoc	= gl.getUniformLocation(m_program->getProgram(), "u_sampler");
   1523 
   1524 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1525 		gl.clear(GL_COLOR_BUFFER_BIT);
   1526 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1527 		gl.useProgram(m_program->getProgram());
   1528 
   1529 		gl.uniform1i(samplerLoc, 0);
   1530 		if (m_testType != TEST_TEX_COORD_CUBE)
   1531 			gl.bindTexture(GL_TEXTURE_2D, m_textureID);
   1532 		else
   1533 			gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
   1534 
   1535 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
   1536 		gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]);
   1537 
   1538 		gl.enableVertexAttribArray(positionLoc);
   1539 		gl.enableVertexAttribArray(texCoordLoc);
   1540 		gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
   1541 		gl.disableVertexAttribArray(positionLoc);
   1542 		gl.disableVertexAttribArray(texCoordLoc);
   1543 
   1544 		gl.useProgram(0);
   1545 		gl.finish();
   1546 		GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::iterate");
   1547 
   1548 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
   1549 	}
   1550 
   1551 	// verify everywhere was drawn and samples were from the texture (all pixels have Green = 255)
   1552 	if (!checkResultImage(resultImage))
   1553 	{
   1554 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
   1555 		return STOP;
   1556 	}
   1557 
   1558 	// test drawing and textures still works
   1559 	if (!drawTestPattern(true))
   1560 	{
   1561 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
   1562 		return STOP;
   1563 	}
   1564 
   1565 	// all ok
   1566 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1567 	return STOP;
   1568 }
   1569 
   1570 std::string TextureSamplerCase::genVertexSource (void) const
   1571 {
   1572 	// vertex shader is passthrough, fragment does the calculations
   1573 	if (m_type == TYPE_FRAGMENT)
   1574 		return s_attrPassthroughVertexShaderSource;
   1575 
   1576 	// vertex shader does the calculations
   1577 	std::ostringstream buf;
   1578 	buf <<	"#version 300 es\n"
   1579 			"in highp vec4 a_pos;\n"
   1580 			"in highp vec2 a_attr;\n";
   1581 
   1582 	if (m_testType != TEST_TEX_COORD_CUBE)
   1583 		buf <<	"uniform highp sampler2D u_sampler;\n";
   1584 	else
   1585 		buf <<	"uniform highp samplerCube u_sampler;\n";
   1586 
   1587 	buf <<	"out mediump vec4 v_out;\n"
   1588 			"void main ()\n"
   1589 			"{\n";
   1590 
   1591 	if (m_testType == TEST_TEX_COORD)
   1592 		buf <<	"	v_out = textureLod(u_sampler, a_attr, 0.0);\n";
   1593 	else if (m_testType == TEST_LOD)
   1594 		buf <<	"	v_out = textureLod(u_sampler, a_attr, a_attr.x);\n";
   1595 	else if (m_testType == TEST_GRAD)
   1596 		buf <<	"	v_out = textureGrad(u_sampler, a_attr, a_attr, a_attr.yx);\n";
   1597 	else if (m_testType == TEST_TEX_COORD_CUBE)
   1598 		buf <<	"	v_out = textureLod(u_sampler, vec3(a_attr, a_attr.x + a_attr.y), 0.0);\n";
   1599 	else
   1600 		DE_ASSERT(DE_FALSE);
   1601 
   1602 	buf <<	"\n"
   1603 			"	gl_Position = a_pos;\n"
   1604 			"}\n";
   1605 
   1606 	return buf.str();
   1607 }
   1608 
   1609 std::string TextureSamplerCase::genFragmentSource (void) const
   1610 {
   1611 	// fragment shader is passthrough
   1612 	if (m_type == TYPE_VERTEX)
   1613 		return s_colorPassthroughFragmentShaderSource;
   1614 
   1615 	// fragment shader does the calculations
   1616 	std::ostringstream buf;
   1617 	buf <<	"#version 300 es\n"
   1618 			"layout(location = 0) out mediump vec4 fragColor;\n";
   1619 
   1620 	if (m_testType != TEST_TEX_COORD_CUBE)
   1621 		buf <<	"uniform highp sampler2D u_sampler;\n";
   1622 	else
   1623 		buf <<	"uniform highp samplerCube u_sampler;\n";
   1624 
   1625 	buf <<	"in highp vec4 v_attr;\n"
   1626 			"void main ()\n"
   1627 			"{\n";
   1628 
   1629 	if (m_testType == TEST_TEX_COORD)
   1630 		buf << "	fragColor = texture(u_sampler, v_attr.xy);\n";
   1631 	else if (m_testType == TEST_LOD)
   1632 		buf << "	fragColor = texture(u_sampler, v_attr.xy, v_attr.x);\n";
   1633 	else if (m_testType == TEST_GRAD)
   1634 		buf <<	"	fragColor = textureGrad(u_sampler, v_attr.xy, v_attr.xy, v_attr.yx);\n";
   1635 	else if (m_testType == TEST_TEX_COORD_CUBE)
   1636 		buf <<	"	fragColor = texture(u_sampler, vec3(v_attr.xy,v_attr.x + v_attr.y));\n";
   1637 	else
   1638 		DE_ASSERT(DE_FALSE);
   1639 
   1640 	buf <<	"}\n";
   1641 
   1642 	return buf.str();
   1643 }
   1644 
   1645 /*--------------------------------------------------------------------*//*!
   1646  * \brief Tests special floats as fragment shader outputs
   1647  *
   1648  * Tests that outputting special floats from a fragment shader does not change
   1649  * the normal floating point values of outputted from a fragment shader. Special
   1650  * floats are outputted in the green component, normal floating point values
   1651  * in the red and blue component. Potential changes are tested by rendering
   1652  * test pattern two times with different floating point values. The resulting
   1653  * images' red and blue channels should be equal.
   1654  *//*--------------------------------------------------------------------*/
   1655 class OutputCase : public FramebufferRenderCase
   1656 {
   1657 public:
   1658 						OutputCase				(Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
   1659 						~OutputCase				(void);
   1660 
   1661 	void				testFBO					(void);
   1662 
   1663 private:
   1664 	std::string			genVertexSource			(void) const;
   1665 	std::string			genFragmentSource		(void) const;
   1666 };
   1667 
   1668 OutputCase::OutputCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
   1669 	: FramebufferRenderCase	(context, name, desc, type)
   1670 {
   1671 }
   1672 
   1673 OutputCase::~OutputCase (void)
   1674 {
   1675 	deinit();
   1676 }
   1677 
   1678 void OutputCase::testFBO (void)
   1679 {
   1680 	// Create a 1 X [s_specialFloats] grid of tiles (stripes).
   1681 	std::vector<tcu::Vec4>	gridVertices	((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * 2);
   1682 	std::vector<deUint16>	indices			(DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
   1683 	tcu::TextureFormat		textureFormat	(tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16 || m_fboType == FBO_RGBA_FLOAT32) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8));
   1684 	tcu::TextureLevel		specialImage	(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1685 	tcu::TextureLevel		normalImage		(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1686 
   1687 	// vertices
   1688 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
   1689 	{
   1690 		const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
   1691 
   1692 		gridVertices[y * 2 + 0] = tcu::Vec4(-1.0, posY, 0.0f, 1.0f);
   1693 		gridVertices[y * 2 + 1] = tcu::Vec4( 1.0, posY, 0.0f, 1.0f);
   1694 	}
   1695 
   1696 	// tiles
   1697 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
   1698 	{
   1699 		const int baseNdx = y * 6;
   1700 
   1701 		indices[baseNdx + 0] = (y + 0) * 2;
   1702 		indices[baseNdx + 1] = (y + 1) * 2;
   1703 		indices[baseNdx + 2] = (y + 1) * 2 + 1;
   1704 
   1705 		indices[baseNdx + 3] = (y + 0) * 2;
   1706 		indices[baseNdx + 4] = (y + 1) * 2 + 1;
   1707 		indices[baseNdx + 5] = (y + 0) * 2 + 1;
   1708 	}
   1709 
   1710 	// Draw grids
   1711 	{
   1712 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   1713 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
   1714 		const GLint				specialLoc	= gl.getUniformLocation(m_program->getProgram(), "u_special");
   1715 
   1716 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1717 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1718 		gl.useProgram(m_program->getProgram());
   1719 		GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
   1720 
   1721 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
   1722 		gl.enableVertexAttribArray(positionLoc);
   1723 
   1724 		// draw 2 passes. Special and normal.
   1725 		for (int passNdx = 0; passNdx < 2; ++passNdx)
   1726 		{
   1727 			const bool specialPass	= (passNdx == 0);
   1728 
   1729 			m_testCtx.getLog() << tcu::TestLog::Message << "Pass " << passNdx << ": Drawing stripes with the shader. Setting u_special for each stripe to (" << ((specialPass) ? ("special") : ("1.0")) << ")." << tcu::TestLog::EndMessage;
   1730 
   1731 			// draw stripes
   1732 			gl.clear(GL_COLOR_BUFFER_BIT);
   1733 			for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
   1734 			{
   1735 				const deUint32	one				= 0x3F800000;
   1736 				const deUint32	special			= s_specialFloats[y];
   1737 				const deUint32	uniformValue	= (specialPass) ? (special) : (one);
   1738 				const int		indexIndex		= y * 6;
   1739 
   1740 				gl.uniform1fv(specialLoc, 1, (const float*)&uniformValue);
   1741 				gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
   1742 			}
   1743 
   1744 			gl.finish();
   1745 			glu::readPixels(m_context.getRenderContext(), 0, 0, ((specialPass) ? (specialImage) : (normalImage)).getAccess());
   1746 		}
   1747 
   1748 		gl.disableVertexAttribArray(positionLoc);
   1749 		gl.useProgram(0);
   1750 		GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
   1751 	}
   1752 
   1753 	// Check results
   1754 	{
   1755 		tcu::Surface		errorMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1756 		const tcu::RGBA		badPixelColor	= tcu::RGBA::red;
   1757 		const tcu::RGBA		okPixelColor	= tcu::RGBA::green;
   1758 		int					badPixels		= 0;
   1759 
   1760 		m_testCtx.getLog() << tcu::TestLog::Message << "Checking passes have identical red and blue channels and the green channel is correct in the constant pass." << tcu::TestLog::EndMessage;
   1761 
   1762 		for (int y = 0; y < specialImage.getHeight(); ++y)
   1763 		for (int x = 0; x < specialImage.getWidth(); ++x)
   1764 		{
   1765 			const float		greenThreshold	= 0.1f;
   1766 			const tcu::Vec4	cNormal			= normalImage.getAccess().getPixel(x, y);
   1767 			const tcu::Vec4	cSpecial		= specialImage.getAccess().getPixel(x, y);
   1768 
   1769 			if (cNormal.x() != cSpecial.x() || cNormal.z() != cSpecial.z() || cNormal.y() < 1.0f - greenThreshold)
   1770 			{
   1771 				++badPixels;
   1772 				errorMask.setPixel(x, y, badPixelColor);
   1773 			}
   1774 			else
   1775 				errorMask.setPixel(x, y, okPixelColor);
   1776 		}
   1777 
   1778 		m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)." << tcu::TestLog::EndMessage;
   1779 
   1780 		if (badPixels)
   1781 		{
   1782 			m_testCtx.getLog()
   1783 					<< tcu::TestLog::ImageSet("Results", "Result verification")
   1784 					<< tcu::TestLog::Image("Image with special green channel",	"Image with special green channel",		specialImage)
   1785 					<< tcu::TestLog::Image("Image with constant green channel",	"Image with constant green channel",	normalImage)
   1786 					<< tcu::TestLog::Image("Error Mask",						"Error Mask",							errorMask)
   1787 					<< tcu::TestLog::EndImageSet;
   1788 
   1789 			// all ok?
   1790 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
   1791 		}
   1792 		else
   1793 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1794 	}
   1795 }
   1796 
   1797 std::string OutputCase::genVertexSource (void) const
   1798 {
   1799 	return
   1800 		"#version 300 es\n"
   1801 		"in highp vec4 a_pos;\n"
   1802 		"out highp vec2 v_pos;\n"
   1803 		"void main ()\n"
   1804 		"{\n"
   1805 		"	gl_Position = a_pos;\n"
   1806 		"	v_pos = a_pos.xy;\n"
   1807 		"}\n";
   1808 }
   1809 
   1810 std::string OutputCase::genFragmentSource (void) const
   1811 {
   1812 	return
   1813 		"#version 300 es\n"
   1814 		"layout(location = 0) out highp vec4 fragColor;\n"
   1815 		"uniform highp float u_special;\n"
   1816 		"in highp vec2 v_pos;\n"
   1817 		"void main ()\n"
   1818 		"{\n"
   1819 		"	fragColor = vec4((v_pos.x + 1.0) * 0.5, u_special, (v_pos.y + 1.0) * 0.5, 1.0);\n"
   1820 		"}\n";
   1821 }
   1822 
   1823 /*--------------------------------------------------------------------*//*!
   1824  * \brief Tests special floats in blending
   1825  *
   1826  * Tests special floats as alpha and color components with various blending
   1827  * modes. Test draws a test pattern and then does various blend operations
   1828  * with special float values. After the blending test another test pattern
   1829  * is drawn to detect possible blending anomalies. Test patterns should be
   1830  * identical.
   1831  *//*--------------------------------------------------------------------*/
   1832 class BlendingCase : public FramebufferRenderCase
   1833 {
   1834 public:
   1835 						BlendingCase			(Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
   1836 						~BlendingCase			(void);
   1837 
   1838 	void				testFBO					(void);
   1839 
   1840 private:
   1841 	void				drawTestImage			(tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex);
   1842 
   1843 	std::string			genVertexSource			(void) const;
   1844 	std::string			genFragmentSource		(void) const;
   1845 };
   1846 
   1847 BlendingCase::BlendingCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
   1848 	: FramebufferRenderCase	(context, name, desc, type)
   1849 {
   1850 }
   1851 
   1852 BlendingCase::~BlendingCase (void)
   1853 {
   1854 	deinit();
   1855 }
   1856 
   1857 void BlendingCase::testFBO (void)
   1858 {
   1859 	static const GLenum equations[] =
   1860 	{
   1861 		GL_FUNC_ADD,
   1862 		GL_FUNC_SUBTRACT,
   1863 		GL_FUNC_REVERSE_SUBTRACT,
   1864 		GL_MIN,
   1865 		GL_MAX
   1866 	};
   1867 	static const GLenum functions[] =
   1868 	{
   1869 		GL_ZERO,
   1870 		GL_ONE,
   1871 		GL_SRC_COLOR,
   1872 		GL_ONE_MINUS_SRC_COLOR,
   1873 		GL_SRC_ALPHA,
   1874 		GL_ONE_MINUS_SRC_ALPHA,
   1875 	};
   1876 
   1877 	// Create a [BlendFuncs] X [s_specialFloats] grid of tiles. ( BlendFuncs = equations x functions )
   1878 
   1879 	const int						numBlendFuncs	= DE_LENGTH_OF_ARRAY(equations) * DE_LENGTH_OF_ARRAY(functions);
   1880 	std::vector<tcu::Vec4>			gridVertices	((numBlendFuncs + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
   1881 	std::vector<deUint16>			indices			(numBlendFuncs * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
   1882 	tcu::TextureFormat				textureFormat	(tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16 || m_fboType == FBO_RGBA_FLOAT32) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8));
   1883 	tcu::TextureLevel				beforeImage		(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1884 	tcu::TextureLevel				afterImage		(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1885 
   1886 	// vertices
   1887 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
   1888 	for (int y = 0; y < numBlendFuncs + 1; ++y)
   1889 	{
   1890 		const float		posX	= (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats)] to [-1, 1]
   1891 		const float		posY	= (float)y / (float)numBlendFuncs * 2.0f - 1.0f;
   1892 
   1893 		gridVertices[x * (numBlendFuncs + 1) + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
   1894 	}
   1895 
   1896 	// tiles
   1897 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
   1898 	for (int y = 0; y < numBlendFuncs; ++y)
   1899 	{
   1900 		const int baseNdx = (x * numBlendFuncs + y) * 6;
   1901 
   1902 		indices[baseNdx + 0] = (x+0) * (numBlendFuncs + 1) + (y+0);
   1903 		indices[baseNdx + 1] = (x+1) * (numBlendFuncs + 1) + (y+1);
   1904 		indices[baseNdx + 2] = (x+1) * (numBlendFuncs + 1) + (y+0);
   1905 
   1906 		indices[baseNdx + 3] = (x+0) * (numBlendFuncs + 1) + (y+0);
   1907 		indices[baseNdx + 4] = (x+1) * (numBlendFuncs + 1) + (y+1);
   1908 		indices[baseNdx + 5] = (x+0) * (numBlendFuncs + 1) + (y+1);
   1909 	}
   1910 
   1911 	// Draw tiles
   1912 	{
   1913 		const int				numPasses	= 5;
   1914 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   1915 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
   1916 		const GLint				specialLoc	= gl.getUniformLocation(m_program->getProgram(), "u_special");
   1917 
   1918 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1919 		gl.clear(GL_COLOR_BUFFER_BIT);
   1920 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1921 		gl.useProgram(m_program->getProgram());
   1922 		gl.enable(GL_BLEND);
   1923 		GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
   1924 
   1925 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
   1926 		gl.enableVertexAttribArray(positionLoc);
   1927 
   1928 		// draw "before" image
   1929 		m_testCtx.getLog() << tcu::TestLog::Message << "Drawing pre-draw pattern." << tcu::TestLog::EndMessage;
   1930 		drawTestImage(beforeImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
   1931 		GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw pattern");
   1932 
   1933 		// draw multiple passes with special floats
   1934 		gl.clear(GL_COLOR_BUFFER_BIT);
   1935 		for (int passNdx = 0; passNdx < numPasses; ++passNdx)
   1936 		{
   1937 			de::Random rnd(123 + 567 * passNdx);
   1938 
   1939 			m_testCtx.getLog()
   1940 				<< tcu::TestLog::Message
   1941 				<< "Pass " << passNdx << ": Drawing tiles with the shader.\n"
   1942 				<< "\tVarying u_special for each tile.\n"
   1943 				<< "\tVarying blend function and blend equation for each tile.\n"
   1944 				<< tcu::TestLog::EndMessage;
   1945 
   1946 			// draw tiles
   1947 			for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
   1948 			for (int y = 0; y < numBlendFuncs; ++y)
   1949 			{
   1950 				const GLenum		blendEquation		= equations[y % DE_LENGTH_OF_ARRAY(equations)];
   1951 				const GLenum		blendFunction		= functions[y / DE_LENGTH_OF_ARRAY(equations)];
   1952 				const GLenum		blendFunctionDst	= rnd.choose<GLenum>(DE_ARRAY_BEGIN(functions), DE_ARRAY_END(functions));
   1953 				const int			indexIndex			= (x * numBlendFuncs + y) * 6;
   1954 
   1955 				// "rnd.get"s are run in a deterministic order
   1956 				const deUint32		componentR			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1957 				const deUint32		componentG			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1958 				const deUint32		componentB			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1959 				const deUint32		componentA			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1960 				const tcu::UVec4	uniformValue		= tcu::UVec4(componentR, componentG, componentB, componentA);
   1961 
   1962 				gl.uniform4fv(specialLoc, 1, (const float*)uniformValue.getPtr());
   1963 				gl.blendEquation(blendEquation);
   1964 				gl.blendFunc(blendFunction, blendFunctionDst);
   1965 				gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
   1966 			}
   1967 		}
   1968 		GLU_EXPECT_NO_ERROR(gl.getError(), "special passes");
   1969 
   1970 		// draw "after" image
   1971 		m_testCtx.getLog() << tcu::TestLog::Message << "Drawing post-draw pattern." << tcu::TestLog::EndMessage;
   1972 		drawTestImage(afterImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
   1973 		GLU_EXPECT_NO_ERROR(gl.getError(), "post-draw pattern");
   1974 
   1975 		gl.disableVertexAttribArray(positionLoc);
   1976 		gl.useProgram(0);
   1977 		GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
   1978 	}
   1979 
   1980 	// Check results
   1981 	{
   1982 		tcu::Surface		errorMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1983 		const tcu::RGBA		badPixelColor	= tcu::RGBA::red;
   1984 		const tcu::RGBA		okPixelColor	= tcu::RGBA::green;
   1985 		int					badPixels		= 0;
   1986 
   1987 		m_testCtx.getLog() << tcu::TestLog::Message << "Checking patterns are identical." << tcu::TestLog::EndMessage;
   1988 
   1989 		for (int y = 0; y < beforeImage.getHeight(); ++y)
   1990 		for (int x = 0; x < beforeImage.getWidth(); ++x)
   1991 		{
   1992 			const tcu::Vec4	cBefore	= beforeImage.getAccess().getPixel(x, y);
   1993 			const tcu::Vec4	cAfter	= afterImage.getAccess().getPixel(x, y);
   1994 
   1995 			if (cBefore != cAfter)
   1996 			{
   1997 				++badPixels;
   1998 				errorMask.setPixel(x, y, badPixelColor);
   1999 			}
   2000 			else
   2001 				errorMask.setPixel(x, y, okPixelColor);
   2002 		}
   2003 
   2004 		m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)." << tcu::TestLog::EndMessage;
   2005 
   2006 		if (badPixels)
   2007 		{
   2008 			m_testCtx.getLog()
   2009 					<< tcu::TestLog::ImageSet("Results", "Result verification")
   2010 					<< tcu::TestLog::Image("Pattern drawn before special float blending",	"Pattern drawn before special float blending",		beforeImage)
   2011 					<< tcu::TestLog::Image("Pattern drawn after special float blending",	"Pattern drawn after special float blending",		afterImage)
   2012 					<< tcu::TestLog::EndImageSet;
   2013 
   2014 			// all ok?
   2015 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
   2016 		}
   2017 		else
   2018 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   2019 	}
   2020 }
   2021 
   2022 void BlendingCase::drawTestImage (tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex)
   2023 {
   2024 	const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
   2025 	de::Random				rnd	(123);
   2026 
   2027 	gl.clear(GL_COLOR_BUFFER_BIT);
   2028 	gl.blendEquation(GL_FUNC_ADD);
   2029 	gl.blendFunc(GL_ONE, GL_ONE);
   2030 
   2031 	for (int tri = 0; tri < 20; ++tri)
   2032 	{
   2033 		tcu::Vec4 color;
   2034 		color.x() = rnd.getFloat();
   2035 		color.y() = rnd.getFloat();
   2036 		color.z() = rnd.getFloat();
   2037 		color.w() = rnd.getFloat();
   2038 		gl.uniform4fv(uColorLoc, 1, color.getPtr());
   2039 
   2040 		deUint16 indices[3];
   2041 		indices[0] = rnd.getInt(0, maxVertexIndex);
   2042 		indices[1] = rnd.getInt(0, maxVertexIndex);
   2043 		indices[2] = rnd.getInt(0, maxVertexIndex);
   2044 
   2045 		gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
   2046 	}
   2047 
   2048 	gl.finish();
   2049 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst);
   2050 }
   2051 
   2052 std::string BlendingCase::genVertexSource (void) const
   2053 {
   2054 	return
   2055 		"#version 300 es\n"
   2056 		"in highp vec4 a_pos;\n"
   2057 		"void main ()\n"
   2058 		"{\n"
   2059 		"	gl_Position = a_pos;\n"
   2060 		"}\n";
   2061 }
   2062 
   2063 std::string BlendingCase::genFragmentSource (void) const
   2064 {
   2065 	return
   2066 		"#version 300 es\n"
   2067 		"layout(location = 0) out highp vec4 fragColor;\n"
   2068 		"uniform highp vec4 u_special;\n"
   2069 		"void main ()\n"
   2070 		"{\n"
   2071 		"	fragColor = u_special;\n"
   2072 		"}\n";
   2073 }
   2074 
   2075 } //anonymous
   2076 
   2077 SpecialFloatTests::SpecialFloatTests (Context& context)
   2078 	: TestCaseGroup(context, "special_float", "Special float tests")
   2079 {
   2080 }
   2081 
   2082 SpecialFloatTests::~SpecialFloatTests (void)
   2083 {
   2084 }
   2085 
   2086 void SpecialFloatTests::init (void)
   2087 {
   2088 	tcu::TestCaseGroup* const vertexGroup		= new tcu::TestCaseGroup(m_testCtx, "vertex",		"Run vertex shader with special float values");
   2089 	tcu::TestCaseGroup* const fragmentGroup		= new tcu::TestCaseGroup(m_testCtx, "fragment",		"Run fragment shader with special float values");
   2090 	tcu::TestCaseGroup* const framebufferGroup	= new tcu::TestCaseGroup(m_testCtx, "framebuffer",	"Test framebuffers containing special float values");
   2091 
   2092 	// .vertex
   2093 	{
   2094 		vertexGroup->addChild(new VertexAttributeCase	(m_context, "attribute_buffer",			"special attribute values in a buffer",					VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_VERTEX));
   2095 		vertexGroup->addChild(new VertexAttributeCase	(m_context, "attribute_client",			"special attribute values in a client storage",			VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_VERTEX));
   2096 		vertexGroup->addChild(new UniformCase			(m_context, "uniform",					"special uniform values",								UniformCase::TYPE_VERTEX));
   2097 		vertexGroup->addChild(new TextureCase			(m_context, "texture",					"texture with special floating point values",			TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_CLIENT));
   2098 		vertexGroup->addChild(new TextureCase			(m_context, "texture_pbo",				"texture (via pbo) with special floating point values",	TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_PBO));
   2099 		vertexGroup->addChild(new TextureCase			(m_context, "texture_shadow",			"shadow texture with special floating point values",	TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_DEPTH, TextureCase::UPLOAD_CLIENT));
   2100 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord",		"special texture coords",								TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD));
   2101 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord_cube",	"special texture coords to cubemap",					TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD_CUBE));
   2102 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_lod",				"special texture lod",									TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_LOD));
   2103 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_grad",				"special texture grad",									TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_GRAD));
   2104 
   2105 		addChild(vertexGroup);
   2106 	}
   2107 
   2108 	// .fragment
   2109 	{
   2110 		fragmentGroup->addChild(new VertexAttributeCase	(m_context, "attribute_buffer",			"special attribute values in a buffer",					VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_FRAGMENT));
   2111 		fragmentGroup->addChild(new VertexAttributeCase	(m_context, "attribute_client",			"special attribute values in a client storage",			VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_FRAGMENT));
   2112 		fragmentGroup->addChild(new UniformCase			(m_context, "uniform",					"special uniform values",								UniformCase::TYPE_FRAGMENT));
   2113 		fragmentGroup->addChild(new TextureCase			(m_context, "texture",					"texture with special floating point values",			TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_CLIENT));
   2114 		fragmentGroup->addChild(new TextureCase			(m_context, "texture_pbo",				"texture (via pbo) with special floating point values",	TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_PBO));
   2115 		fragmentGroup->addChild(new TextureCase			(m_context, "texture_shadow",			"shadow texture with special floating point values",	TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_DEPTH, TextureCase::UPLOAD_CLIENT));
   2116 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord",		"special texture coords",								TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD));
   2117 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord_cube",	"special texture coords to cubemap",					TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD_CUBE));
   2118 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_lod",				"special texture lod",									TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_LOD));
   2119 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_grad",				"special texture grad",									TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_GRAD));
   2120 
   2121 		addChild(fragmentGroup);
   2122 	}
   2123 
   2124 	// .framebuffer
   2125 	{
   2126 		framebufferGroup->addChild(new OutputCase		(m_context, "write_default",			"write special floating point values to default framebuffer",	FramebufferRenderCase::FBO_DEFAULT));
   2127 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgba4",				"write special floating point values to RGBA4 framebuffer",		FramebufferRenderCase::FBO_RGBA4));
   2128 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgb5_a1",			"write special floating point values to RGB5_A1 framebuffer",	FramebufferRenderCase::FBO_RGB5_A1));
   2129 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgb565",				"write special floating point values to RGB565 framebuffer",	FramebufferRenderCase::FBO_RGB565));
   2130 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgba8",				"write special floating point values to RGBA8 framebuffer",		FramebufferRenderCase::FBO_RGBA8));
   2131 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgb10_a2",			"write special floating point values to RGB10_A2 framebuffer",	FramebufferRenderCase::FBO_RGB10_A2));
   2132 		framebufferGroup->addChild(new OutputCase		(m_context, "write_float16",			"write special floating point values to float16 framebuffer",	FramebufferRenderCase::FBO_RGBA_FLOAT16));
   2133 		framebufferGroup->addChild(new OutputCase		(m_context, "write_float32",			"write special floating point values to float32 framebuffer",	FramebufferRenderCase::FBO_RGBA_FLOAT32));
   2134 
   2135 		framebufferGroup->addChild(new BlendingCase		(m_context, "blend_default",			"blend special floating point values in a default framebuffer",	FramebufferRenderCase::FBO_DEFAULT));
   2136 		framebufferGroup->addChild(new BlendingCase		(m_context, "blend_rgba8",				"blend special floating point values in a RGBA8 framebuffer",	FramebufferRenderCase::FBO_RGBA8));
   2137 		framebufferGroup->addChild(new BlendingCase		(m_context, "blend_float16",			"blend special floating point values in a float16 framebuffer",	FramebufferRenderCase::FBO_RGBA_FLOAT16));
   2138 
   2139 		addChild(framebufferGroup);
   2140 	}
   2141 }
   2142 
   2143 } // Stress
   2144 } // gles3
   2145 } // deqp
   2146