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
43using namespace glw;
44
45namespace deqp
46{
47namespace gles2
48{
49namespace Stress
50{
51namespace
52{
53
54static const int		TEST_CANVAS_SIZE		= 256;
55static const int		TEST_TEXTURE_SIZE		= 128;
56static const int		TEST_TEXTURE_CUBE_SIZE	= 32;
57static 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
83static 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";
88static 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
97class RenderCase : public TestCase
98{
99public:
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
112protected:
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
123RenderCase::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
130RenderCase::~RenderCase (void)
131{
132	deinit();
133}
134
135void 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
168void RenderCase::deinit (void)
169{
170	if (m_program)
171	{
172		delete m_program;
173		m_program = DE_NULL;
174	}
175}
176
177bool 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
218bool 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
350class FramebufferRenderCase : public RenderCase
351{
352public:
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
374protected:
375	const FrameBufferType	m_fboType;
376
377private:
378	GLuint					m_texID;
379	GLuint					m_fboID;
380};
381
382FramebufferRenderCase::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
391FramebufferRenderCase::~FramebufferRenderCase (void)
392{
393	deinit();
394}
395
396void 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
463void 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
480FramebufferRenderCase::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 *//*--------------------------------------------------------------------*/
506class VertexAttributeCase : public RenderCase
507{
508public:
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
531private:
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
542VertexAttributeCase::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
554VertexAttributeCase::~VertexAttributeCase (void)
555{
556	deinit();
557}
558
559void 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
574void 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
599VertexAttributeCase::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
721std::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
744std::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 *//*--------------------------------------------------------------------*/
777class UniformCase : public RenderCase
778{
779public:
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
793private:
794	std::string			genVertexSource				(void) const;
795	std::string			genFragmentSource			(void) const;
796
797	const ShaderType	m_type;
798};
799
800UniformCase::UniformCase (Context& context, const char* name, const char* desc, ShaderType type)
801	: RenderCase	(context, name, desc)
802	, m_type		(type)
803{
804}
805
806UniformCase::~UniformCase (void)
807{
808	deinit();
809}
810
811void UniformCase::init (void)
812{
813	RenderCase::init();
814}
815
816void UniformCase::deinit (void)
817{
818	RenderCase::deinit();
819}
820
821UniformCase::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
910std::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
938std::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 *//*--------------------------------------------------------------------*/
970class TextureSamplerCase : public RenderCase
971{
972public:
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
996private:
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
1005TextureSamplerCase::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
1015TextureSamplerCase::~TextureSamplerCase (void)
1016{
1017	deinit();
1018}
1019
1020void 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
1112void 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
1125TextureSamplerCase::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
1215std::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
1251std::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 *//*--------------------------------------------------------------------*/
1292class OutputCase : public FramebufferRenderCase
1293{
1294public:
1295						OutputCase				(Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
1296						~OutputCase				(void);
1297
1298	void				testFBO					(void);
1299
1300private:
1301	std::string			genVertexSource			(void) const;
1302	std::string			genFragmentSource		(void) const;
1303};
1304
1305OutputCase::OutputCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
1306	: FramebufferRenderCase	(context, name, desc, type)
1307{
1308}
1309
1310OutputCase::~OutputCase (void)
1311{
1312	deinit();
1313}
1314
1315void 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
1434std::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
1446std::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 *//*--------------------------------------------------------------------*/
1466class BlendingCase : public FramebufferRenderCase
1467{
1468public:
1469						BlendingCase			(Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
1470						~BlendingCase			(void);
1471
1472	void				testFBO					(void);
1473
1474private:
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
1481BlendingCase::BlendingCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
1482	: FramebufferRenderCase	(context, name, desc, type)
1483{
1484}
1485
1486BlendingCase::~BlendingCase (void)
1487{
1488	deinit();
1489}
1490
1491void 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
1654void 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
1684std::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
1694std::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
1706SpecialFloatTests::SpecialFloatTests (Context& context)
1707	: TestCaseGroup(context, "special_float", "Special float tests")
1708{
1709}
1710
1711SpecialFloatTests::~SpecialFloatTests (void)
1712{
1713}
1714
1715void 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