Home | History | Annotate | Download | only in stress
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 2.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 "es2sSpecialFloatTests.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 gles2
     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 =	"varying mediump vec4 v_out;\n"
     84 																	"void main ()\n"
     85 																	"{\n"
     86 																	"	gl_FragColor = v_out;\n"
     87 																	"}\n";
     88 static const char* const s_attrPassthroughVertexShaderSource	=	"attribute highp vec4 a_pos;\n"
     89 																	"attribute highp vec4 a_attr;\n"
     90 																	"varying mediump vec4 v_attr;\n"
     91 																	"void main ()\n"
     92 																	"{\n"
     93 																	"	v_attr = a_attr;\n"
     94 																	"	gl_Position = a_pos;\n"
     95 																	"}\n";
     96 
     97 class RenderCase : public TestCase
     98 {
     99 public:
    100 	enum RenderTargetType
    101 	{
    102 		RENDERTARGETTYPE_SCREEN,
    103 		RENDERTARGETTYPE_FBO
    104 	};
    105 
    106 								RenderCase			(Context& context, const char* name, const char* desc, RenderTargetType renderTargetType = RENDERTARGETTYPE_SCREEN);
    107 	virtual						~RenderCase			(void);
    108 
    109 	virtual void				init				(void);
    110 	virtual void				deinit				(void);
    111 
    112 protected:
    113 	bool						checkResultImage	(const tcu::Surface& result);
    114 	bool						drawTestPattern		(bool useTexture);
    115 
    116 	virtual std::string			genVertexSource		(void) const = 0;
    117 	virtual std::string			genFragmentSource	(void) const = 0;
    118 
    119 	const glu::ShaderProgram*	m_program;
    120 	const RenderTargetType		m_renderTargetType;
    121 };
    122 
    123 RenderCase::RenderCase (Context& context, const char* name, const char* desc, RenderTargetType renderTargetType)
    124 	: TestCase				(context, name, desc)
    125 	, m_program				(DE_NULL)
    126 	, m_renderTargetType	(renderTargetType)
    127 {
    128 }
    129 
    130 RenderCase::~RenderCase (void)
    131 {
    132 	deinit();
    133 }
    134 
    135 void RenderCase::init (void)
    136 {
    137 	const int width	 = m_context.getRenderTarget().getWidth();
    138 	const int height = m_context.getRenderTarget().getHeight();
    139 
    140 	// check target size
    141 	if (m_renderTargetType == RENDERTARGETTYPE_SCREEN)
    142 	{
    143 		if (width < TEST_CANVAS_SIZE || height < TEST_CANVAS_SIZE)
    144 			throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(TEST_CANVAS_SIZE) + "x" + de::toString(TEST_CANVAS_SIZE));
    145 	}
    146 	else if (m_renderTargetType == RENDERTARGETTYPE_FBO)
    147 	{
    148 		GLint maxTexSize = 0;
    149 		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
    150 
    151 		if (maxTexSize < TEST_CANVAS_SIZE)
    152 			throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_CANVAS_SIZE));
    153 	}
    154 	else
    155 		DE_ASSERT(false);
    156 
    157 	// gen shader
    158 
    159 	m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shader." << tcu::TestLog::EndMessage;
    160 
    161 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(genFragmentSource()));
    162 	m_testCtx.getLog() << *m_program;
    163 
    164 	if (!m_program->isOk())
    165 		throw tcu::TestError("shader compile failed");
    166 }
    167 
    168 void RenderCase::deinit (void)
    169 {
    170 	if (m_program)
    171 	{
    172 		delete m_program;
    173 		m_program = DE_NULL;
    174 	}
    175 }
    176 
    177 bool RenderCase::checkResultImage (const tcu::Surface& result)
    178 {
    179 	tcu::Surface	errorMask	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    180 	bool			error		= false;
    181 
    182 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output image." << tcu::TestLog::EndMessage;
    183 
    184 	for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
    185 	for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
    186 	{
    187 		const tcu::RGBA col = result.getPixel(x, y);
    188 
    189 		if (col.getGreen() == 255)
    190 			errorMask.setPixel(x, y, tcu::RGBA::green());
    191 		else
    192 		{
    193 			errorMask.setPixel(x, y, tcu::RGBA::red());
    194 			error = true;
    195 		}
    196 	}
    197 
    198 	if (error)
    199 	{
    200 		m_testCtx.getLog() << tcu::TestLog::Message << "Result image has missing or invalid pixels" << tcu::TestLog::EndMessage;
    201 		m_testCtx.getLog()
    202 			<< tcu::TestLog::ImageSet("Results", "Result verification")
    203 			<< tcu::TestLog::Image("Result",		"Result",		result)
    204 			<< tcu::TestLog::Image("Error mask",	"Error mask",	errorMask)
    205 			<< tcu::TestLog::EndImageSet;
    206 	}
    207 	else
    208 	{
    209 		m_testCtx.getLog()
    210 			<< tcu::TestLog::ImageSet("Results", "Result verification")
    211 			<< tcu::TestLog::Image("Result", "Result", result)
    212 			<< tcu::TestLog::EndImageSet;
    213 	}
    214 
    215 	return !error;
    216 }
    217 
    218 bool RenderCase::drawTestPattern (bool useTexture)
    219 {
    220 	static const tcu::Vec4 fullscreenQuad[4] =
    221 	{
    222 		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
    223 		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
    224 		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
    225 		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
    226 	};
    227 	const char* const	vertexSource		=	"attribute highp vec4 a_pos;\n"
    228 												"varying mediump vec4 v_position;\n"
    229 												"void main ()\n"
    230 												"{\n"
    231 												"	v_position = a_pos;\n"
    232 												"	gl_Position = a_pos;\n"
    233 												"}\n";
    234 	const char* const	fragmentSourceNoTex	=	"varying mediump vec4 v_position;\n"
    235 												"void main ()\n"
    236 												"{\n"
    237 												"	gl_FragColor = vec4((v_position.x + 1.0) * 0.5, 1.0, 1.0, 1.0);\n"
    238 												"}\n";
    239 	const char* const	fragmentSourceTex	=	"uniform mediump sampler2D u_sampler;\n"
    240 												"varying mediump vec4 v_position;\n"
    241 												"void main ()\n"
    242 												"{\n"
    243 												"	gl_FragColor = texture2D(u_sampler, v_position.xy);\n"
    244 												"}\n";
    245 	const char* const	fragmentSource		=	(useTexture) ? (fragmentSourceTex) : (fragmentSourceNoTex);
    246 	const tcu::RGBA		formatThreshold		= m_context.getRenderTarget().getPixelFormat().getColorThreshold();
    247 
    248 	tcu::Surface		resultImage			(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    249 	tcu::Surface		errorMask			(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    250 	bool				error				=	false;
    251 
    252 	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a test pattern to detect " << ((useTexture) ? ("texture sampling") : ("")) << " side-effects." << tcu::TestLog::EndMessage;
    253 
    254 	// draw pattern
    255 	{
    256 		const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
    257 		const glu::ShaderProgram	patternProgram	(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource));
    258 		const GLint					positionLoc		= gl.getAttribLocation(patternProgram.getProgram(), "a_pos");
    259 		GLuint						textureID		= 0;
    260 
    261 		if (useTexture)
    262 		{
    263 			const int textureSize = 32;
    264 			std::vector<tcu::Vector<deUint8, 4> > buffer(textureSize*textureSize);
    265 
    266 			for (int x = 0; x < textureSize; ++x)
    267 			for (int y = 0; y < textureSize; ++y)
    268 			{
    269 				// sum of two axis aligned gradients. Each gradient is 127 at the edges and 0 at the center.
    270 				// pattern is symmetric (x and y) => no discontinuity near boundary => no need to worry of results with LINEAR filtering near boundaries
    271 				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);
    272 
    273 				buffer[x * textureSize + y] = tcu::Vector<deUint8, 4>(redComponent, 255, 255, 255);
    274 			}
    275 
    276 			gl.genTextures(1, &textureID);
    277 			gl.bindTexture(GL_TEXTURE_2D, textureID);
    278 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureSize, textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer[0].getPtr());
    279 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    280 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    281 		}
    282 
    283 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    284 		gl.clear(GL_COLOR_BUFFER_BIT);
    285 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    286 		gl.useProgram(patternProgram.getProgram());
    287 
    288 		if (useTexture)
    289 			gl.uniform1i(gl.getUniformLocation(patternProgram.getProgram(), "u_sampler"), 0);
    290 
    291 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &fullscreenQuad[0]);
    292 
    293 		gl.enableVertexAttribArray(positionLoc);
    294 		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
    295 		gl.disableVertexAttribArray(positionLoc);
    296 
    297 		gl.useProgram(0);
    298 		gl.finish();
    299 		GLU_EXPECT_NO_ERROR(gl.getError(), "RenderCase::drawTestPattern");
    300 
    301 		if (textureID)
    302 			gl.deleteTextures(1, &textureID);
    303 
    304 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
    305 	}
    306 
    307 	// verify pattern
    308 	for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
    309 	for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
    310 	{
    311 		const float			texGradientPosX = deFloatFrac((float)x * 2.0f / (float)TEST_CANVAS_SIZE);
    312 		const float			texGradientPosY = deFloatFrac((float)y * 2.0f / (float)TEST_CANVAS_SIZE);
    313 		const deUint8		texRedComponent = (deUint8)de::clamp(de::abs(texGradientPosX - 0.5f) * 255.0f + de::abs(texGradientPosY - 0.5f) * 255.0f, 0.0f, 255.0f);
    314 
    315 		const tcu::RGBA		refColTexture	= tcu::RGBA(texRedComponent, 255, 255, 255);
    316 		const tcu::RGBA		refColGradient	= tcu::RGBA((int)((float)x / (float)TEST_CANVAS_SIZE * 255.0f), 255, 255, 255);
    317 		const tcu::RGBA&	refCol			= (useTexture) ? (refColTexture) : (refColGradient);
    318 
    319 		const int			colorThreshold	= 10;
    320 		const tcu::RGBA		col				= resultImage.getPixel(x, y);
    321 		const tcu::IVec4	colorDiff		= tcu::abs(col.toIVec() - refCol.toIVec());
    322 
    323 		if (colorDiff.x() > formatThreshold.getRed()   + colorThreshold ||
    324 			colorDiff.y() > formatThreshold.getGreen() + colorThreshold ||
    325 			colorDiff.z() > formatThreshold.getBlue()  + colorThreshold)
    326 		{
    327 			errorMask.setPixel(x, y, tcu::RGBA::red());
    328 			error = true;
    329 		}
    330 		else
    331 			errorMask.setPixel(x, y, tcu::RGBA::green());
    332 	}
    333 
    334 	// report error
    335 	if (error)
    336 	{
    337 		m_testCtx.getLog() << tcu::TestLog::Message << "Test pattern has missing/invalid pixels" << tcu::TestLog::EndMessage;
    338 		m_testCtx.getLog()
    339 			<< tcu::TestLog::ImageSet("Results", "Result verification")
    340 			<< tcu::TestLog::Image("Result",		"Result",		resultImage)
    341 			<< tcu::TestLog::Image("Error mask",	"Error mask",	errorMask)
    342 			<< tcu::TestLog::EndImageSet;
    343 	}
    344 	else
    345 		m_testCtx.getLog() << tcu::TestLog::Message << "No side-effects found." << tcu::TestLog::EndMessage;
    346 
    347 	return !error;
    348 }
    349 
    350 class FramebufferRenderCase : public RenderCase
    351 {
    352 public:
    353 	enum FrameBufferType
    354 	{
    355 		FBO_DEFAULT = 0,
    356 		FBO_RGBA,
    357 		FBO_RGBA4,
    358 		FBO_RGB5_A1,
    359 		FBO_RGB565,
    360 		FBO_RGBA_FLOAT16,
    361 
    362 		FBO_LAST
    363 	};
    364 
    365 							FramebufferRenderCase	(Context& context, const char* name, const char* desc, FrameBufferType fboType);
    366 	virtual					~FramebufferRenderCase	(void);
    367 
    368 	virtual void			init					(void);
    369 	virtual void			deinit					(void);
    370 	IterateResult			iterate					(void);
    371 
    372 	virtual void			testFBO					(void) = DE_NULL;
    373 
    374 protected:
    375 	const FrameBufferType	m_fboType;
    376 
    377 private:
    378 	GLuint					m_texID;
    379 	GLuint					m_fboID;
    380 };
    381 
    382 FramebufferRenderCase::FramebufferRenderCase (Context& context, const char* name, const char* desc, FrameBufferType fboType)
    383 	: RenderCase	(context, name, desc, (fboType == FBO_DEFAULT) ? (RENDERTARGETTYPE_SCREEN) : (RENDERTARGETTYPE_FBO))
    384 	, m_fboType		(fboType)
    385 	, m_texID		(0)
    386 	, m_fboID		(0)
    387 {
    388 	DE_ASSERT(m_fboType < FBO_LAST);
    389 }
    390 
    391 FramebufferRenderCase::~FramebufferRenderCase (void)
    392 {
    393 	deinit();
    394 }
    395 
    396 void FramebufferRenderCase::init (void)
    397 {
    398 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    399 
    400 	// check requirements
    401 	if (m_fboType == FBO_RGBA_FLOAT16)
    402 	{
    403 		// half float texture is allowed (OES_texture_half_float) and it is color renderable (EXT_color_buffer_half_float)
    404 		if (!m_context.getContextInfo().isExtensionSupported("GL_OES_texture_half_float") ||
    405 			!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_half_float"))
    406 			throw tcu::NotSupportedError("Color renderable half float texture required.");
    407 	}
    408 
    409 	// gen shader
    410 	RenderCase::init();
    411 
    412 	// create render target
    413 	if (m_fboType == FBO_DEFAULT)
    414 	{
    415 		m_testCtx.getLog() << tcu::TestLog::Message << "Using default framebuffer." << tcu::TestLog::EndMessage;
    416 	}
    417 	else
    418 	{
    419 		GLuint internalFormat	= 0;
    420 		GLuint format			= 0;
    421 		GLuint type				= 0;
    422 
    423 #if !defined(GL_HALF_FLOAT_OES)
    424 #	define	GL_HALF_FLOAT_OES 0x8D61
    425 #endif
    426 
    427 		switch (m_fboType)
    428 		{
    429 			case FBO_RGBA:			internalFormat = GL_RGBA;	format = GL_RGBA;	type = GL_UNSIGNED_BYTE;				break;
    430 			case FBO_RGBA4:			internalFormat = GL_RGBA;	format = GL_RGBA;	type = GL_UNSIGNED_SHORT_4_4_4_4;		break;
    431 			case FBO_RGB5_A1:		internalFormat = GL_RGBA;	format = GL_RGBA;	type = GL_UNSIGNED_SHORT_5_5_5_1;		break;
    432 			case FBO_RGB565:		internalFormat = GL_RGB;	format = GL_RGB;	type = GL_UNSIGNED_SHORT_5_6_5;			break;
    433 			case FBO_RGBA_FLOAT16:	internalFormat = GL_RGBA;	format = GL_RGBA;	type = GL_HALF_FLOAT_OES;				break;
    434 
    435 			default:
    436 				DE_ASSERT(false);
    437 				break;
    438 		}
    439 
    440 		m_testCtx.getLog() << tcu::TestLog::Message
    441 			<< "Creating fbo. Texture internalFormat = " << glu::getTextureFormatStr(internalFormat)
    442 			<< ", format = " << glu::getTextureFormatStr(format)
    443 			<< ", type = " << glu::getTypeStr(type)
    444 			<< tcu::TestLog::EndMessage;
    445 
    446 		// gen texture
    447 		gl.genTextures(1, &m_texID);
    448 		gl.bindTexture(GL_TEXTURE_2D, m_texID);
    449 		gl.texImage2D(GL_TEXTURE_2D, 0, internalFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, 0, format, type, DE_NULL);
    450 		GLU_EXPECT_NO_ERROR(gl.getError(), "texture init");
    451 
    452 		// gen fbo
    453 		gl.genFramebuffers(1, &m_fboID);
    454 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
    455 		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texID, 0);
    456 		GLU_EXPECT_NO_ERROR(gl.getError(), "fbo init");
    457 
    458 		if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    459 			throw tcu::NotSupportedError("could not create fbo for testing.");
    460 	}
    461 }
    462 
    463 void FramebufferRenderCase::deinit (void)
    464 {
    465 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    466 
    467 	if (m_texID)
    468 	{
    469 		gl.deleteTextures(1, &m_texID);
    470 		m_texID = 0;
    471 	}
    472 
    473 	if (m_fboID)
    474 	{
    475 		gl.deleteFramebuffers(1, &m_fboID);
    476 		m_fboID = 0;
    477 	}
    478 }
    479 
    480 FramebufferRenderCase::IterateResult FramebufferRenderCase::iterate (void)
    481 {
    482 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    483 
    484 	// bind fbo (or don't if we are using default)
    485 	if (m_fboID)
    486 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
    487 
    488 	// do something with special floats
    489 	testFBO();
    490 
    491 	return STOP;
    492 }
    493 
    494 /*--------------------------------------------------------------------*//*!
    495  * \brief Tests special floats as vertex attributes
    496  *
    497  * Tests that special floats transferred to the shader using vertex
    498  * attributes do not change the results of normal floating point
    499  * calculations. Special floats are put to 4-vector's x and y components and
    500  * value 1.0 is put to z and w. The resulting fragment's green channel
    501  * should be 1.0 everywhere.
    502  *
    503  * After the calculation test a test pattern is drawn to detect possible
    504  * floating point operation anomalies.
    505  *//*--------------------------------------------------------------------*/
    506 class VertexAttributeCase : public RenderCase
    507 {
    508 public:
    509 	enum Storage
    510 	{
    511 		STORAGE_BUFFER = 0,
    512 		STORAGE_CLIENT,
    513 
    514 		STORAGE_LAST
    515 	};
    516 	enum ShaderType
    517 	{
    518 		TYPE_VERTEX = 0,
    519 		TYPE_FRAGMENT,
    520 
    521 		TYPE_LAST
    522 	};
    523 
    524 						VertexAttributeCase			(Context& context, const char* name, const char* desc, Storage storage, ShaderType type);
    525 						~VertexAttributeCase		(void);
    526 
    527 	void				init						(void);
    528 	void				deinit						(void);
    529 	IterateResult		iterate						(void);
    530 
    531 private:
    532 	std::string			genVertexSource				(void) const;
    533 	std::string			genFragmentSource			(void) const;
    534 
    535 	const Storage		m_storage;
    536 	const ShaderType	m_type;
    537 	GLuint				m_positionVboID;
    538 	GLuint				m_attribVboID;
    539 	GLuint				m_elementVboID;
    540 };
    541 
    542 VertexAttributeCase::VertexAttributeCase (Context& context, const char* name, const char* desc, Storage storage, ShaderType type)
    543 	: RenderCase			(context, name, desc)
    544 	, m_storage				(storage)
    545 	, m_type				(type)
    546 	, m_positionVboID		(0)
    547 	, m_attribVboID			(0)
    548 	, m_elementVboID		(0)
    549 {
    550 	DE_ASSERT(storage < STORAGE_LAST);
    551 	DE_ASSERT(type < TYPE_LAST);
    552 }
    553 
    554 VertexAttributeCase::~VertexAttributeCase (void)
    555 {
    556 	deinit();
    557 }
    558 
    559 void VertexAttributeCase::init (void)
    560 {
    561 	RenderCase::init();
    562 
    563 	// init gl resources
    564 	if (m_storage == STORAGE_BUFFER)
    565 	{
    566 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    567 
    568 		gl.genBuffers(1, &m_positionVboID);
    569 		gl.genBuffers(1, &m_attribVboID);
    570 		gl.genBuffers(1, &m_elementVboID);
    571 	}
    572 }
    573 
    574 void VertexAttributeCase::deinit (void)
    575 {
    576 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    577 
    578 	RenderCase::deinit();
    579 
    580 	if (m_attribVboID)
    581 	{
    582 		gl.deleteBuffers(1, &m_attribVboID);
    583 		m_attribVboID = 0;
    584 	}
    585 
    586 	if (m_positionVboID)
    587 	{
    588 		gl.deleteBuffers(1, &m_positionVboID);
    589 		m_positionVboID = 0;
    590 	}
    591 
    592 	if (m_elementVboID)
    593 	{
    594 		gl.deleteBuffers(1, &m_elementVboID);
    595 		m_elementVboID = 0;
    596 	}
    597 }
    598 
    599 VertexAttributeCase::IterateResult VertexAttributeCase::iterate (void)
    600 {
    601 	// Create a [s_specialFloats] X [s_specialFloats] grid of vertices with each vertex having 2 [s_specialFloats] values
    602 	// and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
    603 
    604 	std::vector<tcu::Vec4>	gridVertices	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
    605 	std::vector<tcu::UVec4>	gridAttributes	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
    606 	std::vector<deUint16>	indices			((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
    607 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    608 
    609 	// vertices
    610 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
    611 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
    612 	{
    613 		const deUint32	one		= 0x3F800000;
    614 		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]
    615 		const float		posY	= (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
    616 
    617 		gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
    618 		gridAttributes[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
    619 	}
    620 
    621 	// tiles
    622 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
    623 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
    624 	{
    625 		const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
    626 
    627 		indices[baseNdx + 0] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
    628 		indices[baseNdx + 1] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
    629 		indices[baseNdx + 2] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
    630 
    631 		indices[baseNdx + 3] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
    632 		indices[baseNdx + 4] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
    633 		indices[baseNdx + 5] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
    634 	}
    635 
    636 	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;
    637 
    638 	// Draw grid
    639 	{
    640 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
    641 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
    642 		const GLint				attribLoc	= gl.getAttribLocation(m_program->getProgram(), "a_attr");
    643 
    644 		if (m_storage == STORAGE_BUFFER)
    645 		{
    646 			gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
    647 			gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridVertices.size() * sizeof(tcu::Vec4)), &gridVertices[0], GL_STATIC_DRAW);
    648 			GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
    649 
    650 			gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
    651 			gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridAttributes.size() * sizeof(tcu::UVec4)), &gridAttributes[0], GL_STATIC_DRAW);
    652 			GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
    653 
    654 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementVboID);
    655 			gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size() * sizeof(deUint16)), &indices[0], GL_STATIC_DRAW);
    656 			GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
    657 		}
    658 
    659 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    660 		gl.clear(GL_COLOR_BUFFER_BIT);
    661 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    662 		gl.useProgram(m_program->getProgram());
    663 
    664 		if (m_storage == STORAGE_BUFFER)
    665 		{
    666 			gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
    667 			gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    668 
    669 			gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
    670 			gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    671 
    672 			gl.enableVertexAttribArray(positionLoc);
    673 			gl.enableVertexAttribArray(attribLoc);
    674 			gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, DE_NULL);
    675 			gl.disableVertexAttribArray(positionLoc);
    676 			gl.disableVertexAttribArray(attribLoc);
    677 
    678 			gl.bindBuffer(GL_ARRAY_BUFFER, 0);
    679 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    680 		}
    681 		else if (m_storage == STORAGE_CLIENT)
    682 		{
    683 			gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
    684 			gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridAttributes[0]);
    685 
    686 			gl.enableVertexAttribArray(positionLoc);
    687 			gl.enableVertexAttribArray(attribLoc);
    688 			gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
    689 			gl.disableVertexAttribArray(positionLoc);
    690 			gl.disableVertexAttribArray(attribLoc);
    691 		}
    692 		else
    693 			DE_ASSERT(false);
    694 
    695 		gl.useProgram(0);
    696 		gl.finish();
    697 		GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
    698 
    699 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
    700 	}
    701 
    702 	// verify everywhere was drawn (all pixels have Green = 255)
    703 	if (!checkResultImage(resultImage))
    704 	{
    705 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
    706 		return STOP;
    707 	}
    708 
    709 	// test drawing still works
    710 	if (!drawTestPattern(false))
    711 	{
    712 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
    713 		return STOP;
    714 	}
    715 
    716 	// all ok
    717 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    718 	return STOP;
    719 }
    720 
    721 std::string VertexAttributeCase::genVertexSource (void) const
    722 {
    723 	if (m_type == TYPE_VERTEX)
    724 		return
    725 			"attribute highp vec4 a_pos;\n"
    726 			"attribute highp vec4 a_attr;\n"
    727 			"varying mediump vec4 v_out;\n"
    728 			"void main ()\n"
    729 			"{\n"
    730 			"	highp vec2 a1 = a_attr.xz + a_attr.yw; // add\n"
    731 			"	highp vec2 a2 = a_attr.xz - a_attr.yw; // sub\n"
    732 			"	highp vec2 a3 = a_attr.xz * a_attr.yw; // mul\n"
    733 			"	highp vec2 a4 = a_attr.xz / a_attr.yw; // div\n"
    734 			"	highp vec2 a5 = a_attr.xz + a_attr.yw * a_attr.xz; // fma\n"
    735 			"\n"
    736 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
    737 			"	v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
    738 			"	gl_Position = a_pos;\n"
    739 			"}\n";
    740 	else
    741 		return s_attrPassthroughVertexShaderSource;
    742 }
    743 
    744 std::string VertexAttributeCase::genFragmentSource (void) const
    745 {
    746 	if (m_type == TYPE_VERTEX)
    747 		return s_colorPassthroughFragmentShaderSource;
    748 	else
    749 		return
    750 			"varying mediump vec4 v_attr;\n"
    751 			"void main ()\n"
    752 			"{\n"
    753 			"	mediump vec2 a1 = v_attr.xz + v_attr.yw; // add\n"
    754 			"	mediump vec2 a2 = v_attr.xz - v_attr.yw; // sub\n"
    755 			"	mediump vec2 a3 = v_attr.xz * v_attr.yw; // mul\n"
    756 			"	mediump vec2 a4 = v_attr.xz / v_attr.yw; // div\n"
    757 			"	mediump vec2 a5 = v_attr.xz + v_attr.yw * v_attr.xz; // fma\n"
    758 			"\n"
    759 			"	const mediump float epsilon = 0.1; // allow small differences. To results to be wrong they must be more wrong than that.\n"
    760 			"	mediump float green = 1.0 + epsilon - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
    761 			"	gl_FragColor = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
    762 			"}\n";
    763 }
    764 
    765 /*--------------------------------------------------------------------*//*!
    766  * \brief Tests special floats as uniforms
    767  *
    768  * Tests that special floats transferred to the shader as uniforms do
    769  * not change the results of normal floating point calculations. Special
    770  * floats are put to 4-vector's x and y components and value 1.0 is put to
    771  * z and w. The resulting fragment's green channel should be 1.0
    772  * everywhere.
    773  *
    774  * After the calculation test a test pattern is drawn to detect possible
    775  * floating point operation anomalies.
    776  *//*--------------------------------------------------------------------*/
    777 class UniformCase : public RenderCase
    778 {
    779 public:
    780 	enum ShaderType
    781 	{
    782 		TYPE_VERTEX = 0,
    783 		TYPE_FRAGMENT,
    784 	};
    785 
    786 						UniformCase					(Context& context, const char* name, const char* desc, ShaderType type);
    787 						~UniformCase				(void);
    788 
    789 	void				init						(void);
    790 	void				deinit						(void);
    791 	IterateResult		iterate						(void);
    792 
    793 private:
    794 	std::string			genVertexSource				(void) const;
    795 	std::string			genFragmentSource			(void) const;
    796 
    797 	const ShaderType	m_type;
    798 };
    799 
    800 UniformCase::UniformCase (Context& context, const char* name, const char* desc, ShaderType type)
    801 	: RenderCase	(context, name, desc)
    802 	, m_type		(type)
    803 {
    804 }
    805 
    806 UniformCase::~UniformCase (void)
    807 {
    808 	deinit();
    809 }
    810 
    811 void UniformCase::init (void)
    812 {
    813 	RenderCase::init();
    814 }
    815 
    816 void UniformCase::deinit (void)
    817 {
    818 	RenderCase::deinit();
    819 }
    820 
    821 UniformCase::IterateResult UniformCase::iterate (void)
    822 {
    823 	// Create a [s_specialFloats] X [s_specialFloats] grid of tile with each tile having 2 [s_specialFloats] values
    824 	// and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
    825 
    826 	std::vector<tcu::Vec4>	gridVertices	((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
    827 	std::vector<deUint16>	indices			(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
    828 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    829 
    830 	// vertices
    831 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
    832 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
    833 	{
    834 		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]
    835 		const float		posY	= (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f;
    836 
    837 		gridVertices[x * (DE_LENGTH_OF_ARRAY(s_specialFloats)+1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
    838 	}
    839 
    840 	// tiles
    841 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
    842 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
    843 	{
    844 		const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats)) + y) * 6;
    845 
    846 		indices[baseNdx + 0] = (deUint16)((x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0));
    847 		indices[baseNdx + 1] = (deUint16)((x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1));
    848 		indices[baseNdx + 2] = (deUint16)((x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0));
    849 
    850 		indices[baseNdx + 3] = (deUint16)((x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0));
    851 		indices[baseNdx + 4] = (deUint16)((x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1));
    852 		indices[baseNdx + 5] = (deUint16)((x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1));
    853 	}
    854 
    855 	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;
    856 
    857 	// Draw grid
    858 	{
    859 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
    860 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
    861 		const GLint				specialLoc	= gl.getUniformLocation(m_program->getProgram(), "u_special");
    862 
    863 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    864 		gl.clear(GL_COLOR_BUFFER_BIT);
    865 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
    866 		gl.useProgram(m_program->getProgram());
    867 
    868 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
    869 		gl.enableVertexAttribArray(positionLoc);
    870 
    871 		for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
    872 		for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
    873 		{
    874 			const deUint32		one				= 0x3F800000;
    875 			const tcu::UVec4	uniformValue	= tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
    876 			const int			indexIndex		= (x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y) * 6;
    877 
    878 			gl.uniform4fv(specialLoc, 1, (const float*)uniformValue.getPtr());
    879 			gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
    880 		}
    881 
    882 		gl.disableVertexAttribArray(positionLoc);
    883 
    884 		gl.useProgram(0);
    885 		gl.finish();
    886 		GLU_EXPECT_NO_ERROR(gl.getError(), "UniformCase::iterate");
    887 
    888 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
    889 	}
    890 
    891 	// verify everywhere was drawn (all pixels have Green = 255)
    892 	if (!checkResultImage(resultImage))
    893 	{
    894 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
    895 		return STOP;
    896 	}
    897 
    898 	// test drawing still works
    899 	if (!drawTestPattern(false))
    900 	{
    901 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
    902 		return STOP;
    903 	}
    904 
    905 	// all ok
    906 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    907 	return STOP;
    908 }
    909 
    910 std::string UniformCase::genVertexSource (void) const
    911 {
    912 	if (m_type == TYPE_VERTEX)
    913 		return
    914 			"attribute highp vec4 a_pos;\n"
    915 			"uniform highp vec4 u_special;\n"
    916 			"varying mediump vec4 v_out;\n"
    917 			"void main ()\n"
    918 			"{\n"
    919 			"	highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
    920 			"	highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
    921 			"	highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
    922 			"	highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
    923 			"	highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
    924 			"\n"
    925 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
    926 			"	v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
    927 			"	gl_Position = a_pos;\n"
    928 			"}\n";
    929 	else
    930 		return
    931 			"attribute highp vec4 a_pos;\n"
    932 			"void main ()\n"
    933 			"{\n"
    934 			"	gl_Position = a_pos;\n"
    935 			"}\n";
    936 }
    937 
    938 std::string UniformCase::genFragmentSource (void) const
    939 {
    940 	if (m_type == TYPE_VERTEX)
    941 		return s_colorPassthroughFragmentShaderSource;
    942 	else
    943 		return
    944 			"uniform mediump vec4 u_special;\n"
    945 			"void main ()\n"
    946 			"{\n"
    947 			"	mediump vec2 a1 = u_special.xz + u_special.yw; // add\n"
    948 			"	mediump vec2 a2 = u_special.xz - u_special.yw; // sub\n"
    949 			"	mediump vec2 a3 = u_special.xz * u_special.yw; // mul\n"
    950 			"	mediump vec2 a4 = u_special.xz / u_special.yw; // div\n"
    951 			"	mediump vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
    952 			"	mediump vec2 a6 = mod(u_special.xz, u_special.yw);\n"
    953 			"	mediump vec2 a7 = mix(u_special.xz, u_special.yw, a6);\n"
    954 			"\n"
    955 			"	mediump float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y + a7.y) - 7.0);\n"
    956 			"	gl_FragColor = vec4(a1.x*a3.x, green, a5.x*a4.x + a2.x*a7.x, 1.0);\n"
    957 			"}\n";
    958 }
    959 
    960 /*--------------------------------------------------------------------*//*!
    961  * \brief Tests special floats as texture samping arguments
    962  *
    963  * Tests that special floats given as texture coordinates or LOD levels
    964  * to sampling functions do not return invalid values (values not in the
    965  * texture). Every texel's green component is 1.0.
    966  *
    967  * After the calculation test a test pattern is drawn to detect possible
    968  * texture sampling anomalies.
    969  *//*--------------------------------------------------------------------*/
    970 class TextureSamplerCase : public RenderCase
    971 {
    972 public:
    973 	enum ShaderType
    974 	{
    975 		TYPE_VERTEX = 0,
    976 		TYPE_FRAGMENT,
    977 
    978 		TYPE_LAST
    979 	};
    980 	enum TestType
    981 	{
    982 		TEST_TEX_COORD = 0,
    983 		TEST_LOD,
    984 		TEST_TEX_COORD_CUBE,
    985 
    986 		TEST_LAST
    987 	};
    988 
    989 						TextureSamplerCase			(Context& context, const char* name, const char* desc, ShaderType type, TestType testType);
    990 						~TextureSamplerCase			(void);
    991 
    992 	void				init						(void);
    993 	void				deinit						(void);
    994 	IterateResult		iterate						(void);
    995 
    996 private:
    997 	std::string			genVertexSource				(void) const;
    998 	std::string			genFragmentSource			(void) const;
    999 
   1000 	const ShaderType	m_type;
   1001 	const TestType		m_testType;
   1002 	GLuint				m_textureID;
   1003 };
   1004 
   1005 TextureSamplerCase::TextureSamplerCase (Context& context, const char* name, const char* desc, ShaderType type, TestType testType)
   1006 	: RenderCase	(context, name, desc)
   1007 	, m_type		(type)
   1008 	, m_testType	(testType)
   1009 	, m_textureID	(0)
   1010 {
   1011 	DE_ASSERT(type < TYPE_LAST);
   1012 	DE_ASSERT(testType < TEST_LAST);
   1013 }
   1014 
   1015 TextureSamplerCase::~TextureSamplerCase (void)
   1016 {
   1017 	deinit();
   1018 }
   1019 
   1020 void TextureSamplerCase::init (void)
   1021 {
   1022 	// requirements
   1023 	{
   1024 		GLint maxTextureSize = 0;
   1025 		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
   1026 		if (maxTextureSize < TEST_TEXTURE_SIZE)
   1027 			throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_TEXTURE_SIZE));
   1028 	}
   1029 
   1030 	// vertex shader supports textures?
   1031 	if (m_type == TYPE_VERTEX)
   1032 	{
   1033 		GLint maxVertexTexUnits = 0;
   1034 		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTexUnits);
   1035 		if (maxVertexTexUnits < 1)
   1036 			throw tcu::NotSupportedError("GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS must be at least 1");
   1037 	}
   1038 
   1039 	RenderCase::init();
   1040 
   1041 	// gen texture
   1042 	{
   1043 		const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
   1044 		std::vector<deUint8>	texData	(TEST_TEXTURE_SIZE*TEST_TEXTURE_SIZE*4);
   1045 		de::Random				rnd		(12345);
   1046 
   1047 		gl.genTextures(1, &m_textureID);
   1048 
   1049 		for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
   1050 		for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
   1051 		{
   1052 			// RGBA8, green and alpha channel are always 255 for verification
   1053 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 0] = rnd.getUint32() & 0xFF;
   1054 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 1] = 0xFF;
   1055 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 2] = rnd.getUint32() & 0xFF;
   1056 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 3] = 0xFF;
   1057 		}
   1058 
   1059 		if (m_testType == TEST_TEX_COORD)
   1060 		{
   1061 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D texture with a test pattern." << tcu::TestLog::EndMessage;
   1062 
   1063 			gl.bindTexture(GL_TEXTURE_2D, m_textureID);
   1064 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
   1065 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1066 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   1067 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
   1068 		}
   1069 		else if (m_testType == TEST_LOD)
   1070 		{
   1071 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a mipmapped 2D texture with a test pattern." << tcu::TestLog::EndMessage;
   1072 
   1073 			gl.bindTexture(GL_TEXTURE_2D, m_textureID);
   1074 
   1075 			for (int level = 0; (TEST_TEXTURE_SIZE >> level); ++level)
   1076 				gl.texImage2D(GL_TEXTURE_2D, level, GL_RGBA, TEST_TEXTURE_SIZE >> level, TEST_TEXTURE_SIZE >> level, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
   1077 
   1078 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1079 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
   1080 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
   1081 		}
   1082 		else if (m_testType == TEST_TEX_COORD_CUBE)
   1083 		{
   1084 			DE_STATIC_ASSERT(TEST_TEXTURE_CUBE_SIZE <= TEST_TEXTURE_SIZE);
   1085 
   1086 			static const GLenum faces[] =
   1087 			{
   1088 				GL_TEXTURE_CUBE_MAP_POSITIVE_X,
   1089 				GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
   1090 				GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
   1091 				GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
   1092 				GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
   1093 				GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
   1094 			};
   1095 
   1096 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a cube map with a test pattern." << tcu::TestLog::EndMessage;
   1097 
   1098 			gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
   1099 
   1100 			for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); ++faceNdx)
   1101 				gl.texImage2D(faces[faceNdx], 0, GL_RGBA, TEST_TEXTURE_CUBE_SIZE, TEST_TEXTURE_CUBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
   1102 
   1103 			gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1104 			gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   1105 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
   1106 		}
   1107 		else
   1108 			DE_ASSERT(DE_FALSE);
   1109 	}
   1110 }
   1111 
   1112 void TextureSamplerCase::deinit (void)
   1113 {
   1114 	RenderCase::deinit();
   1115 
   1116 	if (m_textureID)
   1117 	{
   1118 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1119 
   1120 		gl.deleteTextures(1, &m_textureID);
   1121 		m_textureID = 0;
   1122 	}
   1123 }
   1124 
   1125 TextureSamplerCase::IterateResult TextureSamplerCase::iterate (void)
   1126 {
   1127 	// 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.
   1128 
   1129 	std::vector<tcu::Vec4>	gridVertices	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
   1130 	std::vector<tcu::UVec2>	gridTexCoords	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
   1131 	std::vector<deUint16>	indices			((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
   1132 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1133 
   1134 	// vertices
   1135 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
   1136 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
   1137 	{
   1138 		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]
   1139 		const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
   1140 
   1141 		gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
   1142 		gridTexCoords[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::UVec2(s_specialFloats[x], s_specialFloats[y]);
   1143 	}
   1144 
   1145 	// tiles
   1146 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
   1147 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
   1148 	{
   1149 		const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
   1150 
   1151 		indices[baseNdx + 0] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
   1152 		indices[baseNdx + 1] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
   1153 		indices[baseNdx + 2] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
   1154 
   1155 		indices[baseNdx + 3] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
   1156 		indices[baseNdx + 4] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
   1157 		indices[baseNdx + 5] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
   1158 	}
   1159 
   1160 	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;
   1161 
   1162 	// Draw grid
   1163 	{
   1164 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   1165 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
   1166 		const GLint				texCoordLoc	= gl.getAttribLocation(m_program->getProgram(), "a_attr");
   1167 		const GLint				samplerLoc	= gl.getUniformLocation(m_program->getProgram(), "u_sampler");
   1168 
   1169 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1170 		gl.clear(GL_COLOR_BUFFER_BIT);
   1171 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1172 		gl.useProgram(m_program->getProgram());
   1173 
   1174 		gl.uniform1i(samplerLoc, 0);
   1175 		if (m_testType != TEST_TEX_COORD_CUBE)
   1176 			gl.bindTexture(GL_TEXTURE_2D, m_textureID);
   1177 		else
   1178 			gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
   1179 
   1180 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
   1181 		gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]);
   1182 
   1183 		gl.enableVertexAttribArray(positionLoc);
   1184 		gl.enableVertexAttribArray(texCoordLoc);
   1185 		gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
   1186 		gl.disableVertexAttribArray(positionLoc);
   1187 		gl.disableVertexAttribArray(texCoordLoc);
   1188 
   1189 		gl.useProgram(0);
   1190 		gl.finish();
   1191 		GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::iterate");
   1192 
   1193 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
   1194 	}
   1195 
   1196 	// verify everywhere was drawn and samples were from the texture (all pixels have Green = 255)
   1197 	if (!checkResultImage(resultImage))
   1198 	{
   1199 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
   1200 		return STOP;
   1201 	}
   1202 
   1203 	// test drawing and textures still works
   1204 	if (!drawTestPattern(true))
   1205 	{
   1206 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
   1207 		return STOP;
   1208 	}
   1209 
   1210 	// all ok
   1211 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1212 	return STOP;
   1213 }
   1214 
   1215 std::string TextureSamplerCase::genVertexSource (void) const
   1216 {
   1217 	// vertex shader is passthrough, fragment does the calculations
   1218 	if (m_type == TYPE_FRAGMENT)
   1219 		return s_attrPassthroughVertexShaderSource;
   1220 
   1221 	// vertex shader does the calculations
   1222 	std::ostringstream buf;
   1223 	buf <<	"attribute highp vec4 a_pos;\n"
   1224 			"attribute highp vec2 a_attr;\n";
   1225 
   1226 	if (m_testType != TEST_TEX_COORD_CUBE)
   1227 		buf <<	"uniform highp sampler2D u_sampler;\n";
   1228 	else
   1229 		buf <<	"uniform highp samplerCube u_sampler;\n";
   1230 
   1231 	buf <<	"varying mediump vec4 v_out;\n"
   1232 			"void main ()\n"
   1233 			"{\n";
   1234 
   1235 	if (m_testType == TEST_TEX_COORD)
   1236 		buf <<	"	v_out = texture2DLod(u_sampler, a_attr, 0.0);\n";
   1237 	else if (m_testType == TEST_LOD)
   1238 		buf <<	"	v_out = texture2DLod(u_sampler, a_attr, a_attr.x);\n";
   1239 	else if (m_testType == TEST_TEX_COORD_CUBE)
   1240 		buf <<	"	v_out = textureCubeLod(u_sampler, vec3(a_attr, a_attr.x+a_attr.y), 0.0);\n";
   1241 	else
   1242 		DE_ASSERT(DE_FALSE);
   1243 
   1244 	buf <<	"\n"
   1245 			"	gl_Position = a_pos;\n"
   1246 			"}\n";
   1247 
   1248 	return buf.str();
   1249 }
   1250 
   1251 std::string TextureSamplerCase::genFragmentSource (void) const
   1252 {
   1253 	// fragment shader is passthrough
   1254 	if (m_type == TYPE_VERTEX)
   1255 		return s_colorPassthroughFragmentShaderSource;
   1256 
   1257 	// fragment shader does the calculations
   1258 	std::ostringstream buf;
   1259 	if (m_testType != TEST_TEX_COORD_CUBE)
   1260 		buf <<	"uniform mediump sampler2D u_sampler;\n";
   1261 	else
   1262 		buf <<	"uniform mediump samplerCube u_sampler;\n";
   1263 
   1264 	buf <<	"varying mediump vec4 v_attr;\n"
   1265 			"void main ()\n"
   1266 			"{\n";
   1267 
   1268 	if (m_testType == TEST_TEX_COORD)
   1269 		buf << "	gl_FragColor = texture2D(u_sampler, v_attr.xy);\n";
   1270 	else if (m_testType == TEST_LOD)
   1271 		buf << "	gl_FragColor = texture2D(u_sampler, v_attr.xy, v_attr.x);\n";
   1272 	else if (m_testType == TEST_TEX_COORD_CUBE)
   1273 		buf <<	"	gl_FragColor = textureCube(u_sampler, vec3(v_attr.xy, v_attr.x + v_attr.y));\n";
   1274 	else
   1275 		DE_ASSERT(DE_FALSE);
   1276 
   1277 	buf <<	"}\n";
   1278 
   1279 	return buf.str();
   1280 }
   1281 
   1282 /*--------------------------------------------------------------------*//*!
   1283  * \brief Tests special floats as fragment shader outputs
   1284  *
   1285  * Tests that outputting special floats from a fragment shader does not change
   1286  * the normal floating point values of outputted from a fragment shader. Special
   1287  * floats are outputted in the green component, normal floating point values
   1288  * in the red and blue component. Potential changes are tested by rendering
   1289  * test pattern two times with different floating point values. The resulting
   1290  * images' red and blue channels should be equal.
   1291  *//*--------------------------------------------------------------------*/
   1292 class OutputCase : public FramebufferRenderCase
   1293 {
   1294 public:
   1295 						OutputCase				(Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
   1296 						~OutputCase				(void);
   1297 
   1298 	void				testFBO					(void);
   1299 
   1300 private:
   1301 	std::string			genVertexSource			(void) const;
   1302 	std::string			genFragmentSource		(void) const;
   1303 };
   1304 
   1305 OutputCase::OutputCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
   1306 	: FramebufferRenderCase	(context, name, desc, type)
   1307 {
   1308 }
   1309 
   1310 OutputCase::~OutputCase (void)
   1311 {
   1312 	deinit();
   1313 }
   1314 
   1315 void OutputCase::testFBO (void)
   1316 {
   1317 	// Create a 1 X [s_specialFloats] grid of tiles (stripes).
   1318 	std::vector<tcu::Vec4>	gridVertices	((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * 2);
   1319 	std::vector<deUint16>	indices			(DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
   1320 	tcu::TextureFormat		textureFormat	(tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8));
   1321 	tcu::TextureLevel		specialImage	(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1322 	tcu::TextureLevel		normalImage		(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1323 
   1324 	// vertices
   1325 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
   1326 	{
   1327 		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]
   1328 
   1329 		gridVertices[y * 2 + 0] = tcu::Vec4(-1.0, posY, 0.0f, 1.0f);
   1330 		gridVertices[y * 2 + 1] = tcu::Vec4( 1.0, posY, 0.0f, 1.0f);
   1331 	}
   1332 
   1333 	// tiles
   1334 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
   1335 	{
   1336 		const int baseNdx = y * 6;
   1337 
   1338 		indices[baseNdx + 0] = (deUint16)((y + 0) * 2);
   1339 		indices[baseNdx + 1] = (deUint16)((y + 1) * 2);
   1340 		indices[baseNdx + 2] = (deUint16)((y + 1) * 2 + 1);
   1341 
   1342 		indices[baseNdx + 3] = (deUint16)((y + 0) * 2);
   1343 		indices[baseNdx + 4] = (deUint16)((y + 1) * 2 + 1);
   1344 		indices[baseNdx + 5] = (deUint16)((y + 0) * 2 + 1);
   1345 	}
   1346 
   1347 	// Draw grids
   1348 	{
   1349 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   1350 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
   1351 		const GLint				specialLoc	= gl.getUniformLocation(m_program->getProgram(), "u_special");
   1352 
   1353 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1354 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1355 		gl.useProgram(m_program->getProgram());
   1356 		GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
   1357 
   1358 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
   1359 		gl.enableVertexAttribArray(positionLoc);
   1360 
   1361 		// draw 2 passes. Special and normal.
   1362 		for (int passNdx = 0; passNdx < 2; ++passNdx)
   1363 		{
   1364 			const bool specialPass	= (passNdx == 0);
   1365 
   1366 			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;
   1367 
   1368 			// draw stripes
   1369 			gl.clear(GL_COLOR_BUFFER_BIT);
   1370 			for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
   1371 			{
   1372 				const deUint32	one				= 0x3F800000;
   1373 				const deUint32	special			= s_specialFloats[y];
   1374 				const deUint32	uniformValue	= (specialPass) ? (special) : (one);
   1375 				const int		indexIndex		= y * 6;
   1376 
   1377 				gl.uniform1fv(specialLoc, 1, (const float*)&uniformValue);
   1378 				gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
   1379 			}
   1380 
   1381 			gl.finish();
   1382 			glu::readPixels(m_context.getRenderContext(), 0, 0, ((specialPass) ? (specialImage) : (normalImage)).getAccess());
   1383 		}
   1384 
   1385 		gl.disableVertexAttribArray(positionLoc);
   1386 		gl.useProgram(0);
   1387 		GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
   1388 	}
   1389 
   1390 	// Check results
   1391 	{
   1392 		tcu::Surface		errorMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1393 		const tcu::RGBA		badPixelColor	= tcu::RGBA::red();
   1394 		const tcu::RGBA		okPixelColor	= tcu::RGBA::green();
   1395 		int					badPixels		= 0;
   1396 
   1397 		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;
   1398 
   1399 		for (int y = 0; y < specialImage.getHeight(); ++y)
   1400 		for (int x = 0; x < specialImage.getWidth(); ++x)
   1401 		{
   1402 			const float		greenThreshold	= 0.1f;
   1403 			const tcu::Vec4	cNormal			= normalImage.getAccess().getPixel(x, y);
   1404 			const tcu::Vec4	cSpecial		= specialImage.getAccess().getPixel(x, y);
   1405 
   1406 			if (cNormal.x() != cSpecial.x() || cNormal.z() != cSpecial.z() || cNormal.y() < 1.0f - greenThreshold)
   1407 			{
   1408 				++badPixels;
   1409 				errorMask.setPixel(x, y, badPixelColor);
   1410 			}
   1411 			else
   1412 				errorMask.setPixel(x, y, okPixelColor);
   1413 		}
   1414 
   1415 		m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)." << tcu::TestLog::EndMessage;
   1416 
   1417 		if (badPixels)
   1418 		{
   1419 			m_testCtx.getLog()
   1420 					<< tcu::TestLog::ImageSet("Results", "Result verification")
   1421 					<< tcu::TestLog::Image("Image with special green channel",	"Image with special green channel",		specialImage)
   1422 					<< tcu::TestLog::Image("Image with constant green channel",	"Image with constant green channel",	normalImage)
   1423 					<< tcu::TestLog::Image("Error Mask",						"Error Mask",							errorMask)
   1424 					<< tcu::TestLog::EndImageSet;
   1425 
   1426 			// all ok?
   1427 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
   1428 		}
   1429 		else
   1430 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1431 	}
   1432 }
   1433 
   1434 std::string OutputCase::genVertexSource (void) const
   1435 {
   1436 	return
   1437 		"attribute highp vec4 a_pos;\n"
   1438 		"varying mediump vec2 v_pos;\n"
   1439 		"void main ()\n"
   1440 		"{\n"
   1441 		"	gl_Position = a_pos;\n"
   1442 		"	v_pos = a_pos.xy;\n"
   1443 		"}\n";
   1444 }
   1445 
   1446 std::string OutputCase::genFragmentSource (void) const
   1447 {
   1448 	return
   1449 		"uniform mediump float u_special;\n"
   1450 		"varying mediump vec2 v_pos;\n"
   1451 		"void main ()\n"
   1452 		"{\n"
   1453 		"	gl_FragColor = vec4((v_pos.x + 1.0) * 0.5, u_special, (v_pos.y + 1.0) * 0.5, 1.0);\n"
   1454 		"}\n";
   1455 }
   1456 
   1457 /*--------------------------------------------------------------------*//*!
   1458  * \brief Tests special floats in blending
   1459  *
   1460  * Tests special floats as alpha and color components with various blending
   1461  * modes. Test draws a test pattern and then does various blend operations
   1462  * with special float values. After the blending test another test pattern
   1463  * is drawn to detect possible blending anomalies. Test patterns should be
   1464  * identical.
   1465  *//*--------------------------------------------------------------------*/
   1466 class BlendingCase : public FramebufferRenderCase
   1467 {
   1468 public:
   1469 						BlendingCase			(Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
   1470 						~BlendingCase			(void);
   1471 
   1472 	void				testFBO					(void);
   1473 
   1474 private:
   1475 	void				drawTestImage			(tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex);
   1476 
   1477 	std::string			genVertexSource			(void) const;
   1478 	std::string			genFragmentSource		(void) const;
   1479 };
   1480 
   1481 BlendingCase::BlendingCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
   1482 	: FramebufferRenderCase	(context, name, desc, type)
   1483 {
   1484 }
   1485 
   1486 BlendingCase::~BlendingCase (void)
   1487 {
   1488 	deinit();
   1489 }
   1490 
   1491 void BlendingCase::testFBO (void)
   1492 {
   1493 	static const GLenum equations[] =
   1494 	{
   1495 		GL_FUNC_ADD,
   1496 		GL_FUNC_SUBTRACT,
   1497 		GL_FUNC_REVERSE_SUBTRACT,
   1498 	};
   1499 	static const GLenum functions[] =
   1500 	{
   1501 		GL_ZERO,
   1502 		GL_ONE,
   1503 		GL_SRC_COLOR,
   1504 		GL_ONE_MINUS_SRC_COLOR,
   1505 		GL_SRC_ALPHA,
   1506 		GL_ONE_MINUS_SRC_ALPHA,
   1507 	};
   1508 
   1509 	// Create a [BlendFuncs] X [s_specialFloats] grid of tiles. ( BlendFuncs = equations x functions )
   1510 
   1511 	const int						numBlendFuncs	= DE_LENGTH_OF_ARRAY(equations) * DE_LENGTH_OF_ARRAY(functions);
   1512 	std::vector<tcu::Vec4>			gridVertices	((numBlendFuncs + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
   1513 	std::vector<deUint16>			indices			(numBlendFuncs * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
   1514 	tcu::TextureFormat				textureFormat	(tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8));
   1515 	tcu::TextureLevel				beforeImage		(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1516 	tcu::TextureLevel				afterImage		(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1517 
   1518 	// vertices
   1519 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
   1520 	for (int y = 0; y < numBlendFuncs + 1; ++y)
   1521 	{
   1522 		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]
   1523 		const float		posY	= (float)y / (float)numBlendFuncs * 2.0f - 1.0f;
   1524 
   1525 		gridVertices[x * (numBlendFuncs + 1) + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
   1526 	}
   1527 
   1528 	// tiles
   1529 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
   1530 	for (int y = 0; y < numBlendFuncs; ++y)
   1531 	{
   1532 		const int baseNdx = (x * numBlendFuncs + y) * 6;
   1533 
   1534 		indices[baseNdx + 0] = (deUint16)((x+0) * (numBlendFuncs + 1) + (y+0));
   1535 		indices[baseNdx + 1] = (deUint16)((x+1) * (numBlendFuncs + 1) + (y+1));
   1536 		indices[baseNdx + 2] = (deUint16)((x+1) * (numBlendFuncs + 1) + (y+0));
   1537 
   1538 		indices[baseNdx + 3] = (deUint16)((x+0) * (numBlendFuncs + 1) + (y+0));
   1539 		indices[baseNdx + 4] = (deUint16)((x+1) * (numBlendFuncs + 1) + (y+1));
   1540 		indices[baseNdx + 5] = (deUint16)((x+0) * (numBlendFuncs + 1) + (y+1));
   1541 	}
   1542 
   1543 	// Draw tiles
   1544 	{
   1545 		const int				numPasses	= 5;
   1546 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   1547 		const GLint				positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_pos");
   1548 		const GLint				specialLoc	= gl.getUniformLocation(m_program->getProgram(), "u_special");
   1549 
   1550 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1551 		gl.clear(GL_COLOR_BUFFER_BIT);
   1552 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1553 		gl.useProgram(m_program->getProgram());
   1554 		gl.enable(GL_BLEND);
   1555 		GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
   1556 
   1557 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
   1558 		gl.enableVertexAttribArray(positionLoc);
   1559 
   1560 		// draw "before" image
   1561 		m_testCtx.getLog() << tcu::TestLog::Message << "Drawing pre-draw pattern." << tcu::TestLog::EndMessage;
   1562 		drawTestImage(beforeImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
   1563 		GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw pattern");
   1564 
   1565 		// draw multiple passes with special floats
   1566 		gl.clear(GL_COLOR_BUFFER_BIT);
   1567 		for (int passNdx = 0; passNdx < numPasses; ++passNdx)
   1568 		{
   1569 			de::Random rnd(123 + 567 * passNdx);
   1570 
   1571 			m_testCtx.getLog()
   1572 				<< tcu::TestLog::Message
   1573 				<< "Pass " << passNdx << ": Drawing tiles with the shader.\n"
   1574 				<< "\tVarying u_special for each tile.\n"
   1575 				<< "\tVarying blend function and blend equation for each tile.\n"
   1576 				<< tcu::TestLog::EndMessage;
   1577 
   1578 			// draw tiles
   1579 			for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
   1580 			for (int y = 0; y < numBlendFuncs; ++y)
   1581 			{
   1582 				const GLenum		blendEquation		= equations[y % DE_LENGTH_OF_ARRAY(equations)];
   1583 				const GLenum		blendFunction		= functions[y / DE_LENGTH_OF_ARRAY(equations)];
   1584 				const GLenum		blendFunctionDst	= rnd.choose<GLenum>(DE_ARRAY_BEGIN(functions), DE_ARRAY_END(functions));
   1585 				const int			indexIndex			= (x * numBlendFuncs + y) * 6;
   1586 
   1587 				// "rnd.get"s are run in a deterministic order
   1588 				const deUint32		componentR			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1589 				const deUint32		componentG			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1590 				const deUint32		componentB			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1591 				const deUint32		componentA			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
   1592 				const tcu::UVec4	uniformValue		= tcu::UVec4(componentR, componentG, componentB, componentA);
   1593 
   1594 				gl.uniform4fv(specialLoc, 1, (const float*)uniformValue.getPtr());
   1595 				gl.blendEquation(blendEquation);
   1596 				gl.blendFunc(blendFunction, blendFunctionDst);
   1597 				gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
   1598 			}
   1599 		}
   1600 		GLU_EXPECT_NO_ERROR(gl.getError(), "special passes");
   1601 
   1602 		// draw "after" image
   1603 		m_testCtx.getLog() << tcu::TestLog::Message << "Drawing post-draw pattern." << tcu::TestLog::EndMessage;
   1604 		drawTestImage(afterImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
   1605 		GLU_EXPECT_NO_ERROR(gl.getError(), "post-draw pattern");
   1606 
   1607 		gl.disableVertexAttribArray(positionLoc);
   1608 		gl.useProgram(0);
   1609 		GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
   1610 	}
   1611 
   1612 	// Check results
   1613 	{
   1614 		tcu::Surface		errorMask		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
   1615 		const tcu::RGBA		badPixelColor	= tcu::RGBA::red();
   1616 		const tcu::RGBA		okPixelColor	= tcu::RGBA::green();
   1617 		int					badPixels		= 0;
   1618 
   1619 		m_testCtx.getLog() << tcu::TestLog::Message << "Checking patterns are identical." << tcu::TestLog::EndMessage;
   1620 
   1621 		for (int y = 0; y < beforeImage.getHeight(); ++y)
   1622 		for (int x = 0; x < beforeImage.getWidth(); ++x)
   1623 		{
   1624 			const tcu::Vec4	cBefore	= beforeImage.getAccess().getPixel(x, y);
   1625 			const tcu::Vec4	cAfter	= afterImage.getAccess().getPixel(x, y);
   1626 
   1627 			if (cBefore != cAfter)
   1628 			{
   1629 				++badPixels;
   1630 				errorMask.setPixel(x, y, badPixelColor);
   1631 			}
   1632 			else
   1633 				errorMask.setPixel(x, y, okPixelColor);
   1634 		}
   1635 
   1636 		m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)." << tcu::TestLog::EndMessage;
   1637 
   1638 		if (badPixels)
   1639 		{
   1640 			m_testCtx.getLog()
   1641 					<< tcu::TestLog::ImageSet("Results", "Result verification")
   1642 					<< tcu::TestLog::Image("Pattern drawn before special float blending",	"Pattern drawn before special float blending",		beforeImage)
   1643 					<< tcu::TestLog::Image("Pattern drawn after special float blending",	"Pattern drawn after special float blending",		afterImage)
   1644 					<< tcu::TestLog::EndImageSet;
   1645 
   1646 			// all ok?
   1647 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
   1648 		}
   1649 		else
   1650 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1651 	}
   1652 }
   1653 
   1654 void BlendingCase::drawTestImage (tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex)
   1655 {
   1656 	const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
   1657 	de::Random				rnd	(123);
   1658 
   1659 	gl.clear(GL_COLOR_BUFFER_BIT);
   1660 	gl.blendEquation(GL_FUNC_ADD);
   1661 	gl.blendFunc(GL_ONE, GL_ONE);
   1662 
   1663 	for (int tri = 0; tri < 20; ++tri)
   1664 	{
   1665 		tcu::Vec4 color;
   1666 		color.x() = rnd.getFloat();
   1667 		color.y() = rnd.getFloat();
   1668 		color.z() = rnd.getFloat();
   1669 		color.w() = rnd.getFloat();
   1670 		gl.uniform4fv(uColorLoc, 1, color.getPtr());
   1671 
   1672 		deUint16 indices[3];
   1673 		indices[0] = (deUint16)rnd.getInt(0, maxVertexIndex);
   1674 		indices[1] = (deUint16)rnd.getInt(0, maxVertexIndex);
   1675 		indices[2] = (deUint16)rnd.getInt(0, maxVertexIndex);
   1676 
   1677 		gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
   1678 	}
   1679 
   1680 	gl.finish();
   1681 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst);
   1682 }
   1683 
   1684 std::string BlendingCase::genVertexSource (void) const
   1685 {
   1686 	return
   1687 		"attribute highp vec4 a_pos;\n"
   1688 		"void main ()\n"
   1689 		"{\n"
   1690 		"	gl_Position = a_pos;\n"
   1691 		"}\n";
   1692 }
   1693 
   1694 std::string BlendingCase::genFragmentSource (void) const
   1695 {
   1696 	return
   1697 		"uniform mediump vec4 u_special;\n"
   1698 		"void main ()\n"
   1699 		"{\n"
   1700 		"	gl_FragColor = u_special;\n"
   1701 		"}\n";
   1702 }
   1703 
   1704 } //anonymous
   1705 
   1706 SpecialFloatTests::SpecialFloatTests (Context& context)
   1707 	: TestCaseGroup(context, "special_float", "Special float tests")
   1708 {
   1709 }
   1710 
   1711 SpecialFloatTests::~SpecialFloatTests (void)
   1712 {
   1713 }
   1714 
   1715 void SpecialFloatTests::init (void)
   1716 {
   1717 	tcu::TestCaseGroup* const vertexGroup	= new tcu::TestCaseGroup(m_testCtx, "vertex",	"Run vertex shader with special float values");
   1718 	tcu::TestCaseGroup* const fragmentGroup	= new tcu::TestCaseGroup(m_testCtx, "fragment",	"Run fragment shader with special float values");
   1719 	tcu::TestCaseGroup* const framebufferGroup	= new tcu::TestCaseGroup(m_testCtx, "framebuffer",	"Test framebuffers containing special float values");
   1720 
   1721 	// .vertex
   1722 	{
   1723 		vertexGroup->addChild(new VertexAttributeCase	(m_context, "attribute_buffer",			"special attribute values in a buffer",					VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_VERTEX));
   1724 		vertexGroup->addChild(new VertexAttributeCase	(m_context, "attribute_client",			"special attribute values in a client storage",			VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_VERTEX));
   1725 		vertexGroup->addChild(new UniformCase			(m_context, "uniform",					"special uniform values",								UniformCase::TYPE_VERTEX));
   1726 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord",		"special texture coords",								TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD));
   1727 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord_cube",	"special texture coords to cubemap",					TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD_CUBE));
   1728 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_lod",				"special texture lod",									TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_LOD));
   1729 
   1730 		addChild(vertexGroup);
   1731 	}
   1732 
   1733 	// .fragment
   1734 	{
   1735 		fragmentGroup->addChild(new VertexAttributeCase	(m_context, "attribute_buffer",			"special attribute values in a buffer",					VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_FRAGMENT));
   1736 		fragmentGroup->addChild(new VertexAttributeCase	(m_context, "attribute_client",			"special attribute values in a client storage",			VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_FRAGMENT));
   1737 		fragmentGroup->addChild(new UniformCase			(m_context, "uniform",					"special uniform values",								UniformCase::TYPE_FRAGMENT));
   1738 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord",		"special texture coords",								TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD));
   1739 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord_cube",	"special texture coords to cubemap",					TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD_CUBE));
   1740 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_lod",				"special texture lod",									TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_LOD));
   1741 
   1742 		addChild(fragmentGroup);
   1743 	}
   1744 
   1745 	// .framebuffer
   1746 	{
   1747 		framebufferGroup->addChild(new OutputCase		(m_context, "write_default",			"write special floating point values to default framebuffer",	FramebufferRenderCase::FBO_DEFAULT));
   1748 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgba",				"write special floating point values to RGBA framebuffer",		FramebufferRenderCase::FBO_RGBA));
   1749 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgba4",				"write special floating point values to RGBA4 framebuffer",		FramebufferRenderCase::FBO_RGBA4));
   1750 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgb5_a1",			"write special floating point values to RGB5_A1 framebuffer",	FramebufferRenderCase::FBO_RGB5_A1));
   1751 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgb565",				"write special floating point values to RGB565 framebuffer",	FramebufferRenderCase::FBO_RGB565));
   1752 		framebufferGroup->addChild(new OutputCase		(m_context, "write_float16",			"write special floating point values to float16 framebuffer",	FramebufferRenderCase::FBO_RGBA_FLOAT16));
   1753 
   1754 		framebufferGroup->addChild(new BlendingCase		(m_context, "blend_default",			"blend special floating point values in a default framebuffer",	FramebufferRenderCase::FBO_DEFAULT));
   1755 		framebufferGroup->addChild(new BlendingCase		(m_context, "blend_rgba",				"blend special floating point values in a RGBA framebuffer",	FramebufferRenderCase::FBO_RGBA));
   1756 		framebufferGroup->addChild(new BlendingCase		(m_context, "blend_float16",			"blend special floating point values in a float16 framebuffer",	FramebufferRenderCase::FBO_RGBA_FLOAT16));
   1757 
   1758 		addChild(framebufferGroup);
   1759 	}
   1760 }
   1761 
   1762 } // Stress
   1763 } // gles2
   1764 } // deqp
   1765