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