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