1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Special float stress tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3sSpecialFloatTests.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluStrUtil.hpp"
29 #include "gluContextInfo.hpp"
30 #include "glwEnums.hpp"
31 #include "glwFunctions.hpp"
32 #include "tcuRenderTarget.hpp"
33 #include "tcuSurface.hpp"
34 #include "tcuTestLog.hpp"
35 #include "tcuVectorUtil.hpp"
36 #include "deStringUtil.hpp"
37 #include "deMath.h"
38 #include "deRandom.hpp"
39 
40 #include <limits>
41 #include <sstream>
42 
43 using namespace glw;
44 
45 namespace deqp
46 {
47 namespace gles3
48 {
49 namespace Stress
50 {
51 namespace
52 {
53 
54 static const int		TEST_CANVAS_SIZE		= 256;
55 static const int		TEST_TEXTURE_SIZE		= 128;
56 static const int		TEST_TEXTURE_CUBE_SIZE	= 32;
57 static const deUint32	s_specialFloats[]		=
58 {
59 	0x00000000,	//          zero
60 	0x80000000,	// negative zero
61 	0x3F800000,	//          one
62 	0xBF800000,	// negative one
63 	0x00800000,	// minimum positive normalized value
64 	0x80800000,	// maximum negative normalized value
65 	0x00000001,	// minimum positive denorm value
66 	0x80000001,	// maximum negative denorm value
67 	0x7F7FFFFF,	// maximum finite value.
68 	0xFF7FFFFF,	// minimum finite value.
69 	0x7F800000,	//  inf
70 	0xFF800000,	// -inf
71 	0x34000000,	//          epsilon
72 	0xB4000000,	// negative epsilon
73 	0x7FC00000,	//          quiet_NaN
74 	0xFFC00000,	// negative quiet_NaN
75 	0x7FC00001,	//          signaling_NaN
76 	0xFFC00001,	// negative signaling_NaN
77 	0x7FEAAAAA,	//          quiet payloaded NaN		(payload of repeated pattern of 101010...)
78 	0xFFEAAAAA,	// negative quiet payloaded NaN		( .. )
79 	0x7FAAAAAA,	//          signaling payloaded NaN	( .. )
80 	0xFFAAAAAA,	// negative signaling payloaded NaN	( .. )
81 };
82 
83 static const char* const s_colorPassthroughFragmentShaderSource	=	"#version 300 es\n"
84 																	"layout(location = 0) out mediump vec4 fragColor;\n"
85 																	"in mediump vec4 v_out;\n"
86 																	"void main ()\n"
87 																	"{\n"
88 																	"	fragColor = v_out;\n"
89 																	"}\n";
90 static const char* const s_attrPassthroughVertexShaderSource	=	"#version 300 es\n"
91 																	"in highp vec4 a_pos;\n"
92 																	"in highp vec4 a_attr;\n"
93 																	"out highp vec4 v_attr;\n"
94 																	"void main ()\n"
95 																	"{\n"
96 																	"	v_attr = a_attr;\n"
97 																	"	gl_Position = a_pos;\n"
98 																	"}\n";
99 
100 class RenderCase : public TestCase
101 {
102 public:
103 	enum RenderTargetType
104 	{
105 		RENDERTARGETTYPE_SCREEN,
106 		RENDERTARGETTYPE_FBO
107 	};
108 
109 								RenderCase			(Context& context, const char* name, const char* desc, RenderTargetType renderTargetType = RENDERTARGETTYPE_SCREEN);
110 	virtual						~RenderCase			(void);
111 
112 	virtual void				init				(void);
113 	virtual void				deinit				(void);
114 
115 protected:
116 	bool						checkResultImage	(const tcu::Surface& result);
117 	bool						drawTestPattern		(bool useTexture);
118 
119 	virtual std::string			genVertexSource		(void) const = 0;
120 	virtual std::string			genFragmentSource	(void) const = 0;
121 
122 	const glu::ShaderProgram*	m_program;
123 	const RenderTargetType		m_renderTargetType;
124 };
125 
RenderCase(Context & context,const char * name,const char * desc,RenderTargetType renderTargetType)126 RenderCase::RenderCase (Context& context, const char* name, const char* desc, RenderTargetType renderTargetType)
127 	: TestCase				(context, name, desc)
128 	, m_program				(DE_NULL)
129 	, m_renderTargetType	(renderTargetType)
130 {
131 }
132 
~RenderCase(void)133 RenderCase::~RenderCase (void)
134 {
135 	deinit();
136 }
137 
init(void)138 void RenderCase::init (void)
139 {
140 	const int width	 = m_context.getRenderTarget().getWidth();
141 	const int height = m_context.getRenderTarget().getHeight();
142 
143 	// check target size
144 	if (m_renderTargetType == RENDERTARGETTYPE_SCREEN)
145 	{
146 		if (width < TEST_CANVAS_SIZE || height < TEST_CANVAS_SIZE)
147 			throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(TEST_CANVAS_SIZE) + "x" + de::toString(TEST_CANVAS_SIZE));
148 	}
149 	else if (m_renderTargetType == RENDERTARGETTYPE_FBO)
150 	{
151 		GLint maxTexSize = 0;
152 		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
153 
154 		if (maxTexSize < TEST_CANVAS_SIZE)
155 			throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_CANVAS_SIZE));
156 	}
157 	else
158 		DE_ASSERT(false);
159 
160 	// gen shader
161 
162 	m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shader." << tcu::TestLog::EndMessage;
163 
164 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(genFragmentSource()));
165 	m_testCtx.getLog() << *m_program;
166 
167 	if (!m_program->isOk())
168 		throw tcu::TestError("shader compile failed");
169 }
170 
deinit(void)171 void RenderCase::deinit (void)
172 {
173 	if (m_program)
174 	{
175 		delete m_program;
176 		m_program = DE_NULL;
177 	}
178 }
179 
checkResultImage(const tcu::Surface & result)180 bool RenderCase::checkResultImage (const tcu::Surface& result)
181 {
182 	tcu::Surface	errorMask	(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
183 	bool			error		= false;
184 
185 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output image." << tcu::TestLog::EndMessage;
186 
187 	for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
188 	for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
189 	{
190 		const tcu::RGBA col = result.getPixel(x, y);
191 
192 		if (col.getGreen() == 255)
193 			errorMask.setPixel(x, y, tcu::RGBA::green());
194 		else
195 		{
196 			errorMask.setPixel(x, y, tcu::RGBA::red());
197 			error = true;
198 		}
199 	}
200 
201 	if (error)
202 	{
203 		m_testCtx.getLog() << tcu::TestLog::Message << "Result image has missing or invalid pixels" << tcu::TestLog::EndMessage;
204 		m_testCtx.getLog()
205 			<< tcu::TestLog::ImageSet("Results", "Result verification")
206 			<< tcu::TestLog::Image("Result",		"Result",		result)
207 			<< tcu::TestLog::Image("Error mask",	"Error mask",	errorMask)
208 			<< tcu::TestLog::EndImageSet;
209 	}
210 	else
211 	{
212 		m_testCtx.getLog()
213 			<< tcu::TestLog::ImageSet("Results", "Result verification")
214 			<< tcu::TestLog::Image("Result", "Result", result)
215 			<< tcu::TestLog::EndImageSet;
216 	}
217 
218 	return !error;
219 }
220 
drawTestPattern(bool useTexture)221 bool RenderCase::drawTestPattern (bool useTexture)
222 {
223 	static const tcu::Vec4 fullscreenQuad[4] =
224 	{
225 		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
226 		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
227 		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
228 		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
229 	};
230 	const char* const	vertexSource		=	"#version 300 es\n"
231 												"in highp vec4 a_pos;\n"
232 												"out mediump vec4 v_position;\n"
233 												"void main ()\n"
234 												"{\n"
235 												"	v_position = a_pos;\n"
236 												"	gl_Position = a_pos;\n"
237 												"}\n";
238 	const char* const	fragmentSourceNoTex	=	"#version 300 es\n"
239 												"layout(location = 0) out mediump vec4 fragColor;\n"
240 												"in mediump vec4 v_position;\n"
241 												"void main ()\n"
242 												"{\n"
243 												"	fragColor = vec4((v_position.x + 1.0) * 0.5, 1.0, 1.0, 1.0);\n"
244 												"}\n";
245 	const char* const	fragmentSourceTex	=	"#version 300 es\n"
246 												"layout(location = 0) out mediump vec4 fragColor;\n"
247 												"uniform mediump sampler2D u_sampler;\n"
248 												"in mediump vec4 v_position;\n"
249 												"void main ()\n"
250 												"{\n"
251 												"	fragColor = texture(u_sampler, v_position.xy);\n"
252 												"}\n";
253 	const char* const	fragmentSource		=	(useTexture) ? (fragmentSourceTex) : (fragmentSourceNoTex);
254 	const tcu::RGBA		formatThreshold		= m_context.getRenderTarget().getPixelFormat().getColorThreshold();
255 
256 	tcu::Surface		resultImage			(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
257 	tcu::Surface		errorMask			(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
258 	bool				error				=	false;
259 
260 	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a test pattern to detect " << ((useTexture) ? ("texture sampling") : ("")) << " side-effects." << tcu::TestLog::EndMessage;
261 
262 	// draw pattern
263 	{
264 		const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
265 		const glu::ShaderProgram	patternProgram	(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource));
266 		const GLint					positionLoc		= gl.getAttribLocation(patternProgram.getProgram(), "a_pos");
267 		GLuint						textureID		= 0;
268 
269 		if (useTexture)
270 		{
271 			const int textureSize = 32;
272 			std::vector<tcu::Vector<deUint8, 4> > buffer(textureSize*textureSize);
273 
274 			for (int x = 0; x < textureSize; ++x)
275 			for (int y = 0; y < textureSize; ++y)
276 			{
277 				// sum of two axis aligned gradients. Each gradient is 127 at the edges and 0 at the center.
278 				// pattern is symmetric (x and y) => no discontinuity near boundary => no need to worry of results with LINEAR filtering near boundaries
279 				const deUint8 redComponent = (deUint8)de::clamp(de::abs((float)x / (float)textureSize - 0.5f) * 255.0f + de::abs((float)y / (float)textureSize - 0.5f) * 255.0f, 0.0f, 255.0f);
280 
281 				buffer[x * textureSize + y] = tcu::Vector<deUint8, 4>(redComponent, 255, 255, 255);
282 			}
283 
284 			gl.genTextures(1, &textureID);
285 			gl.bindTexture(GL_TEXTURE_2D, textureID);
286 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureSize, textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer[0].getPtr());
287 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
288 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
289 		}
290 
291 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
292 		gl.clear(GL_COLOR_BUFFER_BIT);
293 		gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
294 		gl.useProgram(patternProgram.getProgram());
295 
296 		if (useTexture)
297 			gl.uniform1i(gl.getUniformLocation(patternProgram.getProgram(), "u_sampler"), 0);
298 
299 		gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &fullscreenQuad[0]);
300 
301 		gl.enableVertexAttribArray(positionLoc);
302 		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
303 		gl.disableVertexAttribArray(positionLoc);
304 
305 		gl.useProgram(0);
306 		gl.finish();
307 		GLU_EXPECT_NO_ERROR(gl.getError(), "RenderCase::drawTestPattern");
308 
309 		if (textureID)
310 			gl.deleteTextures(1, &textureID);
311 
312 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
313 	}
314 
315 	// verify pattern
316 	for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
317 	for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
318 	{
319 		const float			texGradientPosX = deFloatFrac((float)x * 2.0f / (float)TEST_CANVAS_SIZE);
320 		const float			texGradientPosY = deFloatFrac((float)y * 2.0f / (float)TEST_CANVAS_SIZE);
321 		const deUint8		texRedComponent = (deUint8)de::clamp(de::abs(texGradientPosX - 0.5f) * 255.0f + de::abs(texGradientPosY - 0.5f) * 255.0f, 0.0f, 255.0f);
322 
323 		const tcu::RGBA		refColTexture	= tcu::RGBA(texRedComponent, 255, 255, 255);
324 		const tcu::RGBA		refColGradient	= tcu::RGBA((int)((float)x / (float)TEST_CANVAS_SIZE * 255.0f), 255, 255, 255);
325 		const tcu::RGBA&	refCol			= (useTexture) ? (refColTexture) : (refColGradient);
326 
327 		const int			colorThreshold	= 10;
328 		const tcu::RGBA		col				= resultImage.getPixel(x, y);
329 		const tcu::IVec4	colorDiff		= tcu::abs(col.toIVec() - refCol.toIVec());
330 
331 		if (colorDiff.x() > formatThreshold.getRed()   + colorThreshold ||
332 			colorDiff.y() > formatThreshold.getGreen() + colorThreshold ||
333 			colorDiff.z() > formatThreshold.getBlue()  + colorThreshold)
334 		{
335 			errorMask.setPixel(x, y, tcu::RGBA::red());
336 			error = true;
337 		}
338 		else
339 			errorMask.setPixel(x, y, tcu::RGBA::green());
340 	}
341 
342 	// report error
343 	if (error)
344 	{
345 		m_testCtx.getLog() << tcu::TestLog::Message << "Test pattern has missing/invalid pixels" << tcu::TestLog::EndMessage;
346 		m_testCtx.getLog()
347 			<< tcu::TestLog::ImageSet("Results", "Result verification")
348 			<< tcu::TestLog::Image("Result",		"Result",		resultImage)
349 			<< tcu::TestLog::Image("Error mask",	"Error mask",	errorMask)
350 			<< tcu::TestLog::EndImageSet;
351 	}
352 	else
353 		m_testCtx.getLog() << tcu::TestLog::Message << "No side-effects found." << tcu::TestLog::EndMessage;
354 
355 	return !error;
356 }
357 
358 class FramebufferRenderCase : public RenderCase
359 {
360 public:
361 	enum FrameBufferType
362 	{
363 		FBO_DEFAULT = 0,
364 		FBO_RGBA4,
365 		FBO_RGB5_A1,
366 		FBO_RGB565,
367 		FBO_RGBA8,
368 		FBO_RGB10_A2,
369 		FBO_RGBA_FLOAT16,
370 		FBO_RGBA_FLOAT32,
371 
372 		FBO_LAST
373 	};
374 
375 							FramebufferRenderCase	(Context& context, const char* name, const char* desc, FrameBufferType fboType);
376 	virtual					~FramebufferRenderCase	(void);
377 
378 	virtual void			init					(void);
379 	virtual void			deinit					(void);
380 	IterateResult			iterate					(void);
381 
382 	virtual void			testFBO					(void) = DE_NULL;
383 
384 protected:
385 	const FrameBufferType	m_fboType;
386 
387 private:
388 	GLuint					m_texID;
389 	GLuint					m_fboID;
390 };
391 
FramebufferRenderCase(Context & context,const char * name,const char * desc,FrameBufferType fboType)392 FramebufferRenderCase::FramebufferRenderCase (Context& context, const char* name, const char* desc, FrameBufferType fboType)
393 	: RenderCase	(context, name, desc, (fboType == FBO_DEFAULT) ? (RENDERTARGETTYPE_SCREEN) : (RENDERTARGETTYPE_FBO))
394 	, m_fboType		(fboType)
395 	, m_texID		(0)
396 	, m_fboID		(0)
397 {
398 	DE_ASSERT(m_fboType < FBO_LAST);
399 }
400 
~FramebufferRenderCase(void)401 FramebufferRenderCase::~FramebufferRenderCase (void)
402 {
403 	deinit();
404 }
405 
init(void)406 void FramebufferRenderCase::init (void)
407 {
408 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
409 
410 	// check requirements
411 	if (m_fboType == FBO_RGBA_FLOAT16)
412 	{
413 		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_half_float") &&
414 			!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float"))
415 			throw tcu::NotSupportedError("Color renderable half float texture required.");
416 	}
417 	else if (m_fboType == FBO_RGBA_FLOAT32)
418 	{
419 		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float"))
420 			throw tcu::NotSupportedError("Color renderable float texture required.");
421 	}
422 
423 	// gen shader
424 	RenderCase::init();
425 
426 	// create render target
427 	if (m_fboType == FBO_DEFAULT)
428 	{
429 		m_testCtx.getLog() << tcu::TestLog::Message << "Using default framebuffer." << tcu::TestLog::EndMessage;
430 	}
431 	else
432 	{
433 		GLuint internalFormat	= 0;
434 		GLuint format			= 0;
435 		GLuint type				= 0;
436 
437 		switch (m_fboType)
438 		{
439 			case FBO_RGBA4:			internalFormat = GL_RGBA4;		format = GL_RGBA;	type = GL_UNSIGNED_SHORT_4_4_4_4;		break;
440 			case FBO_RGB5_A1:		internalFormat = GL_RGB5_A1;	format = GL_RGBA;	type = GL_UNSIGNED_SHORT_5_5_5_1;		break;
441 			case FBO_RGB565:		internalFormat = GL_RGB565;		format = GL_RGB;	type = GL_UNSIGNED_SHORT_5_6_5;			break;
442 			case FBO_RGBA8:			internalFormat = GL_RGBA8;		format = GL_RGBA;	type = GL_UNSIGNED_BYTE;				break;
443 			case FBO_RGB10_A2:		internalFormat = GL_RGB10_A2;	format = GL_RGBA;	type = GL_UNSIGNED_INT_2_10_10_10_REV;	break;
444 			case FBO_RGBA_FLOAT16:	internalFormat = GL_RGBA16F;	format = GL_RGBA;	type = GL_HALF_FLOAT;					break;
445 			case FBO_RGBA_FLOAT32:	internalFormat = GL_RGBA32F;	format = GL_RGBA;	type = GL_FLOAT;						break;
446 
447 			default:
448 				DE_ASSERT(false);
449 				break;
450 		}
451 
452 		m_testCtx.getLog() << tcu::TestLog::Message
453 			<< "Creating fbo. Texture internalFormat = " << glu::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 
deinit(void)475 void FramebufferRenderCase::deinit (void)
476 {
477 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
478 
479 	if (m_texID)
480 	{
481 		gl.deleteTextures(1, &m_texID);
482 		m_texID = 0;
483 	}
484 
485 	if (m_fboID)
486 	{
487 		gl.deleteFramebuffers(1, &m_fboID);
488 		m_fboID = 0;
489 	}
490 }
491 
iterate(void)492 FramebufferRenderCase::IterateResult FramebufferRenderCase::iterate (void)
493 {
494 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
495 
496 	// bind fbo (or don't if we are using default)
497 	if (m_fboID)
498 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
499 
500 	// do something with special floats
501 	testFBO();
502 
503 	return STOP;
504 }
505 
506 /*--------------------------------------------------------------------*//*!
507  * \brief Tests special floats as vertex attributes
508  *
509  * Tests that special floats transferred to the shader using vertex
510  * attributes do not change the results of normal floating point
511  * calculations. Special floats are put to 4-vector's x and y components and
512  * value 1.0 is put to z and w. The resulting fragment's green channel
513  * should be 1.0 everywhere.
514  *
515  * After the calculation test a test pattern is drawn to detect possible
516  * floating point operation anomalies.
517  *//*--------------------------------------------------------------------*/
518 class VertexAttributeCase : public RenderCase
519 {
520 public:
521 	enum Storage
522 	{
523 		STORAGE_BUFFER = 0,
524 		STORAGE_CLIENT,
525 
526 		STORAGE_LAST
527 	};
528 	enum ShaderType
529 	{
530 		TYPE_VERTEX = 0,
531 		TYPE_FRAGMENT,
532 
533 		TYPE_LAST
534 	};
535 
536 						VertexAttributeCase			(Context& context, const char* name, const char* desc, Storage storage, ShaderType type);
537 						~VertexAttributeCase		(void);
538 
539 	void				init						(void);
540 	void				deinit						(void);
541 	IterateResult		iterate						(void);
542 
543 private:
544 	std::string			genVertexSource				(void) const;
545 	std::string			genFragmentSource			(void) const;
546 
547 	const Storage		m_storage;
548 	const ShaderType	m_type;
549 	GLuint				m_positionVboID;
550 	GLuint				m_attribVboID;
551 	GLuint				m_elementVboID;
552 };
553 
VertexAttributeCase(Context & context,const char * name,const char * desc,Storage storage,ShaderType type)554 VertexAttributeCase::VertexAttributeCase (Context& context, const char* name, const char* desc, Storage storage, ShaderType type)
555 	: RenderCase			(context, name, desc)
556 	, m_storage				(storage)
557 	, m_type				(type)
558 	, m_positionVboID		(0)
559 	, m_attribVboID			(0)
560 	, m_elementVboID		(0)
561 {
562 	DE_ASSERT(storage < STORAGE_LAST);
563 	DE_ASSERT(type < TYPE_LAST);
564 }
565 
~VertexAttributeCase(void)566 VertexAttributeCase::~VertexAttributeCase (void)
567 {
568 	deinit();
569 }
570 
init(void)571 void VertexAttributeCase::init (void)
572 {
573 	RenderCase::init();
574 
575 	// init gl resources
576 	if (m_storage == STORAGE_BUFFER)
577 	{
578 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
579 
580 		gl.genBuffers(1, &m_positionVboID);
581 		gl.genBuffers(1, &m_attribVboID);
582 		gl.genBuffers(1, &m_elementVboID);
583 	}
584 }
585 
deinit(void)586 void VertexAttributeCase::deinit (void)
587 {
588 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
589 
590 	RenderCase::deinit();
591 
592 	if (m_attribVboID)
593 	{
594 		gl.deleteBuffers(1, &m_attribVboID);
595 		m_attribVboID = 0;
596 	}
597 
598 	if (m_positionVboID)
599 	{
600 		gl.deleteBuffers(1, &m_positionVboID);
601 		m_positionVboID = 0;
602 	}
603 
604 	if (m_elementVboID)
605 	{
606 		gl.deleteBuffers(1, &m_elementVboID);
607 		m_elementVboID = 0;
608 	}
609 }
610 
iterate(void)611 VertexAttributeCase::IterateResult VertexAttributeCase::iterate (void)
612 {
613 	// Create a [s_specialFloats] X [s_specialFloats] grid of vertices with each vertex having 2 [s_specialFloats] values
614 	// and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
615 
616 	std::vector<tcu::Vec4>	gridVertices	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
617 	std::vector<tcu::UVec4>	gridAttributes	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
618 	std::vector<deUint16>	indices			((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
619 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
620 
621 	// vertices
622 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
623 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
624 	{
625 		const deUint32	one		= 0x3F800000;
626 		const float		posX	= (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
627 		const float		posY	= (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
628 
629 		gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
630 		gridAttributes[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
631 	}
632 
633 	// tiles
634 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
635 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
636 	{
637 		const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
638 
639 		indices[baseNdx + 0] = (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 
genVertexSource(void) const733 std::string VertexAttributeCase::genVertexSource (void) const
734 {
735 	if (m_type == TYPE_VERTEX)
736 		return
737 			"#version 300 es\n"
738 			"in highp vec4 a_pos;\n"
739 			"in highp vec4 a_attr;\n"
740 			"out mediump vec4 v_out;\n"
741 			"void main ()\n"
742 			"{\n"
743 			"	highp vec2 a1 = a_attr.xz + a_attr.yw; // add\n"
744 			"	highp vec2 a2 = a_attr.xz - a_attr.yw; // sub\n"
745 			"	highp vec2 a3 = a_attr.xz * a_attr.yw; // mul\n"
746 			"	highp vec2 a4 = a_attr.xz / a_attr.yw; // div\n"
747 			"	highp vec2 a5 = a_attr.xz + a_attr.yw * a_attr.xz; // fma\n"
748 			"\n"
749 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
750 			"	v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
751 			"	gl_Position = a_pos;\n"
752 			"}\n";
753 	else
754 		return s_attrPassthroughVertexShaderSource;
755 }
756 
genFragmentSource(void) const757 std::string VertexAttributeCase::genFragmentSource (void) const
758 {
759 	if (m_type == TYPE_VERTEX)
760 		return s_colorPassthroughFragmentShaderSource;
761 	else
762 		return
763 			"#version 300 es\n"
764 			"layout(location = 0) out mediump vec4 fragColor;\n"
765 			"in highp vec4 v_attr;\n"
766 			"void main ()\n"
767 			"{\n"
768 			"	highp vec2 a1 = v_attr.xz + v_attr.yw; // add\n"
769 			"	highp vec2 a2 = v_attr.xz - v_attr.yw; // sub\n"
770 			"	highp vec2 a3 = v_attr.xz * v_attr.yw; // mul\n"
771 			"	highp vec2 a4 = v_attr.xz / v_attr.yw; // div\n"
772 			"	highp vec2 a5 = v_attr.xz + v_attr.yw * v_attr.xz; // fma\n"
773 			"	highp vec2 a6 = dFdx(v_attr.xz);\n"
774 			"\n"
775 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y) - 6.0);\n"
776 			"	fragColor = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x+a6.x, 1.0);\n"
777 			"}\n";
778 }
779 
780 /*--------------------------------------------------------------------*//*!
781  * \brief Tests special floats as uniforms
782  *
783  * Tests that special floats transferred to the shader as uniforms do
784  * not change the results of normal floating point calculations. Special
785  * floats are put to 4-vector's x and y components and value 1.0 is put to
786  * z and w. The resulting fragment's green channel should be 1.0
787  * everywhere.
788  *
789  * After the calculation test a test pattern is drawn to detect possible
790  * floating point operation anomalies.
791  *//*--------------------------------------------------------------------*/
792 class UniformCase : public RenderCase
793 {
794 public:
795 	enum ShaderType
796 	{
797 		TYPE_VERTEX = 0,
798 		TYPE_FRAGMENT,
799 	};
800 
801 						UniformCase					(Context& context, const char* name, const char* desc, ShaderType type);
802 						~UniformCase				(void);
803 
804 	void				init						(void);
805 	void				deinit						(void);
806 	IterateResult		iterate						(void);
807 
808 private:
809 	std::string			genVertexSource				(void) const;
810 	std::string			genFragmentSource			(void) const;
811 
812 	const ShaderType	m_type;
813 };
814 
UniformCase(Context & context,const char * name,const char * desc,ShaderType type)815 UniformCase::UniformCase (Context& context, const char* name, const char* desc, ShaderType type)
816 	: RenderCase	(context, name, desc)
817 	, m_type		(type)
818 {
819 }
820 
~UniformCase(void)821 UniformCase::~UniformCase (void)
822 {
823 	deinit();
824 }
825 
init(void)826 void UniformCase::init (void)
827 {
828 	RenderCase::init();
829 }
830 
deinit(void)831 void UniformCase::deinit (void)
832 {
833 	RenderCase::deinit();
834 }
835 
iterate(void)836 UniformCase::IterateResult UniformCase::iterate (void)
837 {
838 	// Create a [s_specialFloats] X [s_specialFloats] grid of tile with each tile having 2 [s_specialFloats] values
839 	// and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
840 
841 	std::vector<tcu::Vec4>	gridVertices	((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
842 	std::vector<deUint16>	indices			(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
843 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
844 
845 	// vertices
846 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
847 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
848 	{
849 		const float		posX	= (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
850 		const float		posY	= (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f;
851 
852 		gridVertices[x * (DE_LENGTH_OF_ARRAY(s_specialFloats)+1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
853 	}
854 
855 	// tiles
856 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
857 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
858 	{
859 		const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats)) + y) * 6;
860 
861 		indices[baseNdx + 0] = (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 
genVertexSource(void) const926 std::string UniformCase::genVertexSource (void) const
927 {
928 	if (m_type == TYPE_VERTEX)
929 		return
930 			"#version 300 es\n"
931 			"in highp vec4 a_pos;\n"
932 			"uniform highp vec4 u_special;\n"
933 			"out mediump vec4 v_out;\n"
934 			"void main ()\n"
935 			"{\n"
936 			"	highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
937 			"	highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
938 			"	highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
939 			"	highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
940 			"	highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
941 			"\n"
942 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
943 			"	v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
944 			"	gl_Position = a_pos;\n"
945 			"}\n";
946 	else
947 		return
948 			"#version 300 es\n"
949 			"in highp vec4 a_pos;\n"
950 			"void main ()\n"
951 			"{\n"
952 			"	gl_Position = a_pos;\n"
953 			"}\n";
954 }
955 
genFragmentSource(void) const956 std::string UniformCase::genFragmentSource (void) const
957 {
958 	if (m_type == TYPE_VERTEX)
959 		return s_colorPassthroughFragmentShaderSource;
960 	else
961 		return
962 			"#version 300 es\n"
963 			"layout(location = 0) out mediump vec4 fragColor;\n"
964 			"uniform highp vec4 u_special;\n"
965 			"void main ()\n"
966 			"{\n"
967 			"	highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
968 			"	highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
969 			"	highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
970 			"	highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
971 			"	highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
972 			"	highp vec2 a6 = mod(u_special.xz, u_special.yw);\n"
973 			"	highp vec2 a7 = mix(u_special.xz, u_special.yw, a6);\n"
974 			"\n"
975 			"	highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y + a7.y) - 7.0);\n"
976 			"	fragColor = vec4(a1.x*a3.x, green, a5.x*a4.x + a2.x*a7.x, 1.0);\n"
977 			"}\n";
978 }
979 
980 /*--------------------------------------------------------------------*//*!
981  * \brief Tests special floats in floating point textures
982  *
983  * Tests that sampling special floats from a floating point texture
984  * does not affect the values of other color components of the sample. Test
985  * samples a RG texture with R channel filled with special floats and G
986  * channel filled with test values.
987  *
988  * Tests that linear sampling using compare mode = COMPARE_REF_TO_TEXTURE
989  * of a floating point depth texture containing special floating point
990  * values does not produce values outside the [0, 1] range.
991  *
992  * After the calculation test a test pattern is drawn to detect possible
993  * texture sampling anomalies.
994  *//*--------------------------------------------------------------------*/
995 class TextureCase : public RenderCase
996 {
997 public:
998 	enum ShaderType
999 	{
1000 		TYPE_VERTEX = 0,
1001 		TYPE_FRAGMENT,
1002 
1003 		TYPE_LAST
1004 	};
1005 	enum TextureType
1006 	{
1007 		TEXTURE_FLOAT = 0,
1008 		TEXTURE_DEPTH,
1009 
1010 		TEXTURE_LAST
1011 	};
1012 	enum UploadType
1013 	{
1014 		UPLOAD_CLIENT = 0,
1015 		UPLOAD_PBO,
1016 
1017 		UPLOAD_LAST
1018 	};
1019 
1020 						TextureCase					(Context& context, const char* name, const char* desc, ShaderType type, TextureType texType, UploadType uploadType);
1021 						~TextureCase				(void);
1022 
1023 	void				init						(void);
1024 	void				deinit						(void);
1025 	IterateResult		iterate						(void);
1026 
1027 private:
1028 	std::string			genVertexSource				(void) const;
1029 	std::string			genFragmentSource			(void) const;
1030 
1031 	const ShaderType	m_type;
1032 	const TextureType	m_textureType;
1033 	const UploadType	m_uploadType;
1034 	GLuint				m_textureID;
1035 	GLuint				m_pboID;
1036 };
1037 
TextureCase(Context & context,const char * name,const char * desc,ShaderType type,TextureType texType,UploadType uploadType)1038 TextureCase::TextureCase (Context& context, const char* name, const char* desc, ShaderType type, TextureType texType, UploadType uploadType)
1039 	: RenderCase	(context, name, desc)
1040 	, m_type		(type)
1041 	, m_textureType	(texType)
1042 	, m_uploadType	(uploadType)
1043 	, m_textureID	(0)
1044 	, m_pboID		(0)
1045 {
1046 	DE_ASSERT(type < TYPE_LAST);
1047 	DE_ASSERT(texType < TEXTURE_LAST);
1048 	DE_ASSERT(uploadType < UPLOAD_LAST);
1049 }
1050 
~TextureCase(void)1051 TextureCase::~TextureCase (void)
1052 {
1053 	deinit();
1054 }
1055 
init(void)1056 void TextureCase::init (void)
1057 {
1058 	// requirements
1059 	{
1060 		GLint maxTextureSize = 0;
1061 		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1062 		if (maxTextureSize < TEST_TEXTURE_SIZE)
1063 			throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_TEXTURE_SIZE));
1064 	}
1065 
1066 	RenderCase::init();
1067 
1068 	// gen texture
1069 	{
1070 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
1071 		de::Random				rnd			(12345);
1072 
1073 		gl.genTextures(1, &m_textureID);
1074 		gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1075 
1076 		if (m_uploadType == UPLOAD_PBO)
1077 		{
1078 			gl.genBuffers(1, &m_pboID);
1079 			gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pboID);
1080 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
1081 		}
1082 
1083 		if (m_textureType == TEXTURE_FLOAT)
1084 		{
1085 			std::vector<deUint32>	texData	(TEST_TEXTURE_SIZE*TEST_TEXTURE_SIZE*2);
1086 			const deUint32*			dataPtr = (m_uploadType == UPLOAD_CLIENT) ? (&texData[0]) : (DE_NULL);
1087 
1088 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D 2-component float texture. Pixel contents are of form (special, 1)." << tcu::TestLog::EndMessage;
1089 
1090 			// set green channel to 1.0
1091 			for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1092 			for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1093 			{
1094 				texData[(x * TEST_TEXTURE_SIZE + y) * 2 + 0] = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1095 				texData[(x * TEST_TEXTURE_SIZE + y) * 2 + 1] = 0x3F800000;	// one
1096 			}
1097 
1098 			if (m_uploadType == UPLOAD_PBO)
1099 				gl.bufferData(GL_PIXEL_UNPACK_BUFFER, (glw::GLsizeiptr)(texData.size() * sizeof(deUint32)), &texData[0], GL_STATIC_DRAW);
1100 
1101 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_RG32F, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RG, GL_FLOAT, dataPtr);
1102 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1103 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1104 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
1105 		}
1106 		else if (m_textureType == TEXTURE_DEPTH)
1107 		{
1108 			std::vector<deUint32>	texData	(TEST_TEXTURE_SIZE*TEST_TEXTURE_SIZE);
1109 			const deUint32*			dataPtr = (m_uploadType == UPLOAD_CLIENT) ? (&texData[0]) : (DE_NULL);
1110 
1111 			m_testCtx.getLog() << tcu::TestLog::Message
1112 				<< "Creating a 2D depth texture and filling it with special floating point values.\n"
1113 				<< "  TEXTURE_COMPARE_MODE = COMPARE_REF_TO_TEXTURE"
1114 				<< tcu::TestLog::EndMessage;
1115 
1116 			for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1117 			for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1118 				texData[x * TEST_TEXTURE_SIZE + y] = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1119 
1120 			if (m_uploadType == UPLOAD_PBO)
1121 				gl.bufferData(GL_PIXEL_UNPACK_BUFFER, (glw::GLsizeiptr)(texData.size() * sizeof(deUint32)), &texData[0], GL_STATIC_DRAW);
1122 
1123 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_DEPTH_COMPONENT, GL_FLOAT, dataPtr);
1124 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
1125 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
1126 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1127 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1128 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
1129 		}
1130 		else
1131 			DE_ASSERT(false);
1132 
1133 		if (m_uploadType == UPLOAD_PBO)
1134 		{
1135 			m_testCtx.getLog() << tcu::TestLog::Message << "PBO used for image upload." << tcu::TestLog::EndMessage;
1136 
1137 			gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1138 			gl.deleteBuffers(1, &m_pboID);
1139 			m_pboID = 0;
1140 		}
1141 	}
1142 }
1143 
deinit(void)1144 void TextureCase::deinit (void)
1145 {
1146 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1147 
1148 	RenderCase::deinit();
1149 
1150 	if (m_textureID)
1151 	{
1152 		gl.deleteTextures(1, &m_textureID);
1153 		m_textureID = 0;
1154 	}
1155 	if (m_pboID)
1156 	{
1157 		gl.deleteBuffers(1, &m_pboID);
1158 		m_pboID = 0;
1159 	}
1160 }
1161 
iterate(void)1162 TextureCase::IterateResult TextureCase::iterate (void)
1163 {
1164 	// Draw a grid and texture it with a floating point texture containing special values. If all goes well, nothing special should happen
1165 
1166 	const int				gridSize		= 16;
1167 	std::vector<tcu::Vec4>	gridVertices	(gridSize * gridSize);
1168 	std::vector<tcu::Vec2>	gridTexCoords	(gridSize * gridSize);
1169 	std::vector<deUint16>	indices			((gridSize - 1) * (gridSize - 1) * 6);
1170 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1171 
1172 	// vertices
1173 	for (int x = 0; x < gridSize; ++x)
1174 	for (int y = 0; y < gridSize; ++y)
1175 	{
1176 		const float posX		= (float)x / ((float)gridSize - 1.0f) * 2.0f - 1.0f; // map from [0, gridSize - 1] to [-1, 1]
1177 		const float posY		= (float)y / ((float)gridSize - 1.0f) * 2.0f - 1.0f;
1178 		const float texCoordX	= deFloatPow(2.0f, (float)x - (float)gridSize / 2.0f);
1179 		const float texCoordY	= deFloatPow(2.0f, (float)y - (float)gridSize / 2.0f);
1180 
1181 		gridVertices[x * gridSize + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
1182 		gridTexCoords[x * gridSize + y]	= tcu::Vec2(texCoordX, texCoordY);
1183 	}
1184 
1185 	// tiles
1186 	for (int x = 0; x < gridSize - 1; ++x)
1187 	for (int y = 0; y < gridSize - 1; ++y)
1188 	{
1189 		const int baseNdx = (x * (gridSize - 1) + y) * 6;
1190 
1191 		indices[baseNdx + 0] = (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 
genVertexSource(void) const1252 std::string TextureCase::genVertexSource (void) const
1253 {
1254 	// vertex shader is passthrough, fragment does the calculations
1255 	if (m_type == TYPE_FRAGMENT)
1256 		return s_attrPassthroughVertexShaderSource;
1257 
1258 	// vertex shader does the calculations
1259 	std::ostringstream buf;
1260 	buf <<	"#version 300 es\n"
1261 			"in highp vec4 a_pos;\n"
1262 			"in highp vec2 a_attr;\n"
1263 			"out mediump vec4 v_out;\n";
1264 
1265 	if (m_textureType == TEXTURE_FLOAT)
1266 		buf <<	"uniform highp sampler2D u_sampler;\n";
1267 	else if (m_textureType == TEXTURE_DEPTH)
1268 		buf <<	"uniform highp sampler2DShadow u_sampler;\n";
1269 	else
1270 		DE_ASSERT(DE_FALSE);
1271 
1272 	buf <<	"void main ()\n"
1273 			"{\n";
1274 
1275 	if (m_textureType == TEXTURE_FLOAT)
1276 		buf <<	"	v_out = vec4(textureLod(u_sampler, a_attr, 0.0).rg, 1.0, 1.0);\n";
1277 	else if (m_textureType == TEXTURE_DEPTH)
1278 		buf <<	"	highp float a1 = textureLod(u_sampler, vec3(a_attr, 0.0), 0.0);\n"
1279 				"	v_out = vec4(a1, (a1 > 1.0 || a1 < 0.0) ? (0.0) : (1.0), 1.0, 1.0);\n";
1280 	else
1281 		DE_ASSERT(DE_FALSE);
1282 
1283 	buf <<	"	gl_Position = a_pos;\n"
1284 			"}\n";
1285 	return buf.str();
1286 }
1287 
genFragmentSource(void) const1288 std::string TextureCase::genFragmentSource (void) const
1289 {
1290 	// fragment shader is passthrough
1291 	if (m_type == TYPE_VERTEX)
1292 		return s_colorPassthroughFragmentShaderSource;
1293 
1294 	// fragment shader does the calculations
1295 	std::ostringstream buf;
1296 	buf <<	"#version 300 es\n"
1297 			"layout(location = 0) out mediump vec4 fragColor;\n";
1298 
1299 	if (m_textureType == TEXTURE_FLOAT)
1300 		buf <<	"uniform highp sampler2D u_sampler;\n";
1301 	else if (m_textureType == TEXTURE_DEPTH)
1302 		buf <<	"uniform highp sampler2DShadow u_sampler;\n";
1303 	else
1304 		DE_ASSERT(DE_FALSE);
1305 
1306 	buf <<	"in highp vec4 v_attr;\n"
1307 			"void main ()\n"
1308 			"{\n";
1309 
1310 	if (m_textureType == TEXTURE_FLOAT)
1311 		buf <<	"	highp vec2 a1 = texture(u_sampler, v_attr.xy).rg;\n"
1312 				"	fragColor = vec4(a1.x, a1.y, 1.0, 1.0);\n";
1313 	else if (m_textureType == TEXTURE_DEPTH)
1314 		buf <<	"	highp float a1 = texture(u_sampler, vec3(v_attr.xy, 0.0));\n"
1315 				"	fragColor = vec4(a1, (a1 > 1.0 || a1 < 0.0) ? (0.0) : (1.0), 1.0, 1.0);\n";
1316 	else
1317 		DE_ASSERT(DE_FALSE);
1318 
1319 	buf << "}\n";
1320 	return buf.str();
1321 }
1322 
1323 /*--------------------------------------------------------------------*//*!
1324  * \brief Tests special floats as texture samping arguments
1325  *
1326  * Tests that special floats given as texture coordinates or LOD levels
1327  * to sampling functions do not return invalid values (values not in the
1328  * texture). Every texel's green component is 1.0.
1329  *
1330  * After the calculation test a test pattern is drawn to detect possible
1331  * texture sampling anomalies.
1332  *//*--------------------------------------------------------------------*/
1333 class TextureSamplerCase : public RenderCase
1334 {
1335 public:
1336 	enum ShaderType
1337 	{
1338 		TYPE_VERTEX = 0,
1339 		TYPE_FRAGMENT,
1340 
1341 		TYPE_LAST
1342 	};
1343 	enum TestType
1344 	{
1345 		TEST_TEX_COORD = 0,
1346 		TEST_LOD,
1347 		TEST_GRAD,
1348 		TEST_TEX_COORD_CUBE,
1349 
1350 		TEST_LAST
1351 	};
1352 
1353 						TextureSamplerCase			(Context& context, const char* name, const char* desc, ShaderType type, TestType testType);
1354 						~TextureSamplerCase			(void);
1355 
1356 	void				init						(void);
1357 	void				deinit						(void);
1358 	IterateResult		iterate						(void);
1359 
1360 private:
1361 	std::string			genVertexSource				(void) const;
1362 	std::string			genFragmentSource			(void) const;
1363 
1364 	const ShaderType	m_type;
1365 	const TestType		m_testType;
1366 	GLuint				m_textureID;
1367 };
1368 
TextureSamplerCase(Context & context,const char * name,const char * desc,ShaderType type,TestType testType)1369 TextureSamplerCase::TextureSamplerCase (Context& context, const char* name, const char* desc, ShaderType type, TestType testType)
1370 	: RenderCase	(context, name, desc)
1371 	, m_type		(type)
1372 	, m_testType	(testType)
1373 	, m_textureID	(0)
1374 {
1375 	DE_ASSERT(type < TYPE_LAST);
1376 	DE_ASSERT(testType < TEST_LAST);
1377 }
1378 
~TextureSamplerCase(void)1379 TextureSamplerCase::~TextureSamplerCase (void)
1380 {
1381 	deinit();
1382 }
1383 
init(void)1384 void TextureSamplerCase::init (void)
1385 {
1386 	// requirements
1387 	{
1388 		GLint maxTextureSize = 0;
1389 		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1390 		if (maxTextureSize < TEST_TEXTURE_SIZE)
1391 			throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_TEXTURE_SIZE));
1392 	}
1393 
1394 	RenderCase::init();
1395 
1396 	// gen texture
1397 	{
1398 		const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
1399 		std::vector<deUint8>	texData	(TEST_TEXTURE_SIZE*TEST_TEXTURE_SIZE*4);
1400 		de::Random				rnd		(12345);
1401 
1402 		gl.genTextures(1, &m_textureID);
1403 
1404 		for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1405 		for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1406 		{
1407 			// RGBA8, green and alpha channel are always 255 for verification
1408 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 0] = rnd.getUint32() & 0xFF;
1409 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 1] = 0xFF;
1410 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 2] = rnd.getUint32() & 0xFF;
1411 			texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 3] = 0xFF;
1412 		}
1413 
1414 		if (m_testType == TEST_TEX_COORD)
1415 		{
1416 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D texture with a test pattern." << tcu::TestLog::EndMessage;
1417 
1418 			gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1419 			gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
1420 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1421 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1422 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1423 		}
1424 		else if (m_testType == TEST_LOD || m_testType == TEST_GRAD)
1425 		{
1426 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a mipmapped 2D texture with a test pattern." << tcu::TestLog::EndMessage;
1427 
1428 			gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1429 
1430 			for (int level = 0; (TEST_TEXTURE_SIZE >> level); ++level)
1431 				gl.texImage2D(GL_TEXTURE_2D, level, GL_RGBA8, TEST_TEXTURE_SIZE >> level, TEST_TEXTURE_SIZE >> level, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
1432 
1433 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1434 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1435 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1436 		}
1437 		else if (m_testType == TEST_TEX_COORD_CUBE)
1438 		{
1439 			DE_STATIC_ASSERT(TEST_TEXTURE_CUBE_SIZE <= TEST_TEXTURE_SIZE);
1440 
1441 			static const GLenum faces[] =
1442 			{
1443 				GL_TEXTURE_CUBE_MAP_POSITIVE_X,
1444 				GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
1445 				GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
1446 				GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
1447 				GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
1448 				GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
1449 			};
1450 
1451 			m_testCtx.getLog() << tcu::TestLog::Message << "Creating a cube map with a test pattern." << tcu::TestLog::EndMessage;
1452 
1453 			gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
1454 
1455 			for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); ++faceNdx)
1456 				gl.texImage2D(faces[faceNdx], 0, GL_RGBA8, TEST_TEXTURE_CUBE_SIZE, TEST_TEXTURE_CUBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
1457 
1458 			gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1459 			gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1460 			GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1461 		}
1462 		else
1463 			DE_ASSERT(DE_FALSE);
1464 	}
1465 }
1466 
deinit(void)1467 void TextureSamplerCase::deinit (void)
1468 {
1469 	RenderCase::deinit();
1470 
1471 	if (m_textureID)
1472 	{
1473 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1474 
1475 		gl.deleteTextures(1, &m_textureID);
1476 		m_textureID = 0;
1477 	}
1478 }
1479 
iterate(void)1480 TextureSamplerCase::IterateResult TextureSamplerCase::iterate (void)
1481 {
1482 	// Draw a grid and texture it with a texture and sample it using special special values. The result samples should all have the green channel at 255 as per the test image.
1483 
1484 	std::vector<tcu::Vec4>	gridVertices	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1485 	std::vector<tcu::UVec2>	gridTexCoords	(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1486 	std::vector<deUint16>	indices			((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
1487 	tcu::Surface			resultImage		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1488 
1489 	// vertices
1490 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1491 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1492 	{
1493 		const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
1494 		const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
1495 
1496 		gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
1497 		gridTexCoords[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]	= tcu::UVec2(s_specialFloats[x], s_specialFloats[y]);
1498 	}
1499 
1500 	// tiles
1501 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
1502 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
1503 	{
1504 		const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
1505 
1506 		indices[baseNdx + 0] = (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 
genVertexSource(void) const1570 std::string TextureSamplerCase::genVertexSource (void) const
1571 {
1572 	// vertex shader is passthrough, fragment does the calculations
1573 	if (m_type == TYPE_FRAGMENT)
1574 		return s_attrPassthroughVertexShaderSource;
1575 
1576 	// vertex shader does the calculations
1577 	std::ostringstream buf;
1578 	buf <<	"#version 300 es\n"
1579 			"in highp vec4 a_pos;\n"
1580 			"in highp vec2 a_attr;\n";
1581 
1582 	if (m_testType != TEST_TEX_COORD_CUBE)
1583 		buf <<	"uniform highp sampler2D u_sampler;\n";
1584 	else
1585 		buf <<	"uniform highp samplerCube u_sampler;\n";
1586 
1587 	buf <<	"out mediump vec4 v_out;\n"
1588 			"void main ()\n"
1589 			"{\n";
1590 
1591 	if (m_testType == TEST_TEX_COORD)
1592 		buf <<	"	v_out = textureLod(u_sampler, a_attr, 0.0);\n";
1593 	else if (m_testType == TEST_LOD)
1594 		buf <<	"	v_out = textureLod(u_sampler, a_attr, a_attr.x);\n";
1595 	else if (m_testType == TEST_GRAD)
1596 		buf <<	"	v_out = textureGrad(u_sampler, a_attr, a_attr, a_attr.yx);\n";
1597 	else if (m_testType == TEST_TEX_COORD_CUBE)
1598 		buf <<	"	v_out = textureLod(u_sampler, vec3(a_attr, a_attr.x + a_attr.y), 0.0);\n";
1599 	else
1600 		DE_ASSERT(DE_FALSE);
1601 
1602 	buf <<	"\n"
1603 			"	gl_Position = a_pos;\n"
1604 			"}\n";
1605 
1606 	return buf.str();
1607 }
1608 
genFragmentSource(void) const1609 std::string TextureSamplerCase::genFragmentSource (void) const
1610 {
1611 	// fragment shader is passthrough
1612 	if (m_type == TYPE_VERTEX)
1613 		return s_colorPassthroughFragmentShaderSource;
1614 
1615 	// fragment shader does the calculations
1616 	std::ostringstream buf;
1617 	buf <<	"#version 300 es\n"
1618 			"layout(location = 0) out mediump vec4 fragColor;\n";
1619 
1620 	if (m_testType != TEST_TEX_COORD_CUBE)
1621 		buf <<	"uniform highp sampler2D u_sampler;\n";
1622 	else
1623 		buf <<	"uniform highp samplerCube u_sampler;\n";
1624 
1625 	buf <<	"in highp vec4 v_attr;\n"
1626 			"void main ()\n"
1627 			"{\n";
1628 
1629 	if (m_testType == TEST_TEX_COORD)
1630 		buf << "	fragColor = texture(u_sampler, v_attr.xy);\n";
1631 	else if (m_testType == TEST_LOD)
1632 		buf << "	fragColor = texture(u_sampler, v_attr.xy, v_attr.x);\n";
1633 	else if (m_testType == TEST_GRAD)
1634 		buf <<	"	fragColor = textureGrad(u_sampler, v_attr.xy, v_attr.xy, v_attr.yx);\n";
1635 	else if (m_testType == TEST_TEX_COORD_CUBE)
1636 		buf <<	"	fragColor = texture(u_sampler, vec3(v_attr.xy,v_attr.x + v_attr.y));\n";
1637 	else
1638 		DE_ASSERT(DE_FALSE);
1639 
1640 	buf <<	"}\n";
1641 
1642 	return buf.str();
1643 }
1644 
1645 /*--------------------------------------------------------------------*//*!
1646  * \brief Tests special floats as fragment shader outputs
1647  *
1648  * Tests that outputting special floats from a fragment shader does not change
1649  * the normal floating point values of outputted from a fragment shader. Special
1650  * floats are outputted in the green component, normal floating point values
1651  * in the red and blue component. Potential changes are tested by rendering
1652  * test pattern two times with different floating point values. The resulting
1653  * images' red and blue channels should be equal.
1654  *//*--------------------------------------------------------------------*/
1655 class OutputCase : public FramebufferRenderCase
1656 {
1657 public:
1658 						OutputCase				(Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
1659 						~OutputCase				(void);
1660 
1661 	void				testFBO					(void);
1662 
1663 private:
1664 	std::string			genVertexSource			(void) const;
1665 	std::string			genFragmentSource		(void) const;
1666 };
1667 
OutputCase(Context & context,const char * name,const char * desc,FramebufferRenderCase::FrameBufferType type)1668 OutputCase::OutputCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
1669 	: FramebufferRenderCase	(context, name, desc, type)
1670 {
1671 }
1672 
~OutputCase(void)1673 OutputCase::~OutputCase (void)
1674 {
1675 	deinit();
1676 }
1677 
testFBO(void)1678 void OutputCase::testFBO (void)
1679 {
1680 	// Create a 1 X [s_specialFloats] grid of tiles (stripes).
1681 	std::vector<tcu::Vec4>	gridVertices	((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * 2);
1682 	std::vector<deUint16>	indices			(DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1683 	tcu::TextureFormat		textureFormat	(tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16 || m_fboType == FBO_RGBA_FLOAT32) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8));
1684 	tcu::TextureLevel		specialImage	(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1685 	tcu::TextureLevel		normalImage		(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1686 
1687 	// vertices
1688 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
1689 	{
1690 		const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
1691 
1692 		gridVertices[y * 2 + 0] = tcu::Vec4(-1.0, posY, 0.0f, 1.0f);
1693 		gridVertices[y * 2 + 1] = tcu::Vec4( 1.0, posY, 0.0f, 1.0f);
1694 	}
1695 
1696 	// tiles
1697 	for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1698 	{
1699 		const int baseNdx = y * 6;
1700 
1701 		indices[baseNdx + 0] = (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 
genVertexSource(void) const1797 std::string OutputCase::genVertexSource (void) const
1798 {
1799 	return
1800 		"#version 300 es\n"
1801 		"in highp vec4 a_pos;\n"
1802 		"out highp vec2 v_pos;\n"
1803 		"void main ()\n"
1804 		"{\n"
1805 		"	gl_Position = a_pos;\n"
1806 		"	v_pos = a_pos.xy;\n"
1807 		"}\n";
1808 }
1809 
genFragmentSource(void) const1810 std::string OutputCase::genFragmentSource (void) const
1811 {
1812 	return
1813 		"#version 300 es\n"
1814 		"layout(location = 0) out highp vec4 fragColor;\n"
1815 		"uniform highp float u_special;\n"
1816 		"in highp vec2 v_pos;\n"
1817 		"void main ()\n"
1818 		"{\n"
1819 		"	fragColor = vec4((v_pos.x + 1.0) * 0.5, u_special, (v_pos.y + 1.0) * 0.5, 1.0);\n"
1820 		"}\n";
1821 }
1822 
1823 /*--------------------------------------------------------------------*//*!
1824  * \brief Tests special floats in blending
1825  *
1826  * Tests special floats as alpha and color components with various blending
1827  * modes. Test draws a test pattern and then does various blend operations
1828  * with special float values. After the blending test another test pattern
1829  * is drawn to detect possible blending anomalies. Test patterns should be
1830  * identical.
1831  *//*--------------------------------------------------------------------*/
1832 class BlendingCase : public FramebufferRenderCase
1833 {
1834 public:
1835 						BlendingCase			(Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
1836 						~BlendingCase			(void);
1837 
1838 	void				testFBO					(void);
1839 
1840 private:
1841 	void				drawTestImage			(tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex);
1842 
1843 	std::string			genVertexSource			(void) const;
1844 	std::string			genFragmentSource		(void) const;
1845 };
1846 
BlendingCase(Context & context,const char * name,const char * desc,FramebufferRenderCase::FrameBufferType type)1847 BlendingCase::BlendingCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
1848 	: FramebufferRenderCase	(context, name, desc, type)
1849 {
1850 }
1851 
~BlendingCase(void)1852 BlendingCase::~BlendingCase (void)
1853 {
1854 	deinit();
1855 }
1856 
testFBO(void)1857 void BlendingCase::testFBO (void)
1858 {
1859 	static const GLenum equations[] =
1860 	{
1861 		GL_FUNC_ADD,
1862 		GL_FUNC_SUBTRACT,
1863 		GL_FUNC_REVERSE_SUBTRACT,
1864 		GL_MIN,
1865 		GL_MAX
1866 	};
1867 	static const GLenum functions[] =
1868 	{
1869 		GL_ZERO,
1870 		GL_ONE,
1871 		GL_SRC_COLOR,
1872 		GL_ONE_MINUS_SRC_COLOR,
1873 		GL_SRC_ALPHA,
1874 		GL_ONE_MINUS_SRC_ALPHA,
1875 	};
1876 
1877 	// Create a [BlendFuncs] X [s_specialFloats] grid of tiles. ( BlendFuncs = equations x functions )
1878 
1879 	const int						numBlendFuncs	= DE_LENGTH_OF_ARRAY(equations) * DE_LENGTH_OF_ARRAY(functions);
1880 	std::vector<tcu::Vec4>			gridVertices	((numBlendFuncs + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
1881 	std::vector<deUint16>			indices			(numBlendFuncs * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1882 	tcu::TextureFormat				textureFormat	(tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16 || m_fboType == FBO_RGBA_FLOAT32) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8));
1883 	tcu::TextureLevel				beforeImage		(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1884 	tcu::TextureLevel				afterImage		(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1885 
1886 	// vertices
1887 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
1888 	for (int y = 0; y < numBlendFuncs + 1; ++y)
1889 	{
1890 		const float		posX	= (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats)] to [-1, 1]
1891 		const float		posY	= (float)y / (float)numBlendFuncs * 2.0f - 1.0f;
1892 
1893 		gridVertices[x * (numBlendFuncs + 1) + y]	= tcu::Vec4(posX, posY, 0.0f, 1.0f);
1894 	}
1895 
1896 	// tiles
1897 	for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1898 	for (int y = 0; y < numBlendFuncs; ++y)
1899 	{
1900 		const int baseNdx = (x * numBlendFuncs + y) * 6;
1901 
1902 		indices[baseNdx + 0] = (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 
drawTestImage(tcu::PixelBufferAccess dst,GLuint uColorLoc,int maxVertexIndex)2022 void BlendingCase::drawTestImage (tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex)
2023 {
2024 	const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
2025 	de::Random				rnd	(123);
2026 
2027 	gl.clear(GL_COLOR_BUFFER_BIT);
2028 	gl.blendEquation(GL_FUNC_ADD);
2029 	gl.blendFunc(GL_ONE, GL_ONE);
2030 
2031 	for (int tri = 0; tri < 20; ++tri)
2032 	{
2033 		tcu::Vec4 color;
2034 		color.x() = rnd.getFloat();
2035 		color.y() = rnd.getFloat();
2036 		color.z() = rnd.getFloat();
2037 		color.w() = rnd.getFloat();
2038 		gl.uniform4fv(uColorLoc, 1, color.getPtr());
2039 
2040 		deUint16 indices[3];
2041 		indices[0] = (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 
genVertexSource(void) const2052 std::string BlendingCase::genVertexSource (void) const
2053 {
2054 	return
2055 		"#version 300 es\n"
2056 		"in highp vec4 a_pos;\n"
2057 		"void main ()\n"
2058 		"{\n"
2059 		"	gl_Position = a_pos;\n"
2060 		"}\n";
2061 }
2062 
genFragmentSource(void) const2063 std::string BlendingCase::genFragmentSource (void) const
2064 {
2065 	return
2066 		"#version 300 es\n"
2067 		"layout(location = 0) out highp vec4 fragColor;\n"
2068 		"uniform highp vec4 u_special;\n"
2069 		"void main ()\n"
2070 		"{\n"
2071 		"	fragColor = u_special;\n"
2072 		"}\n";
2073 }
2074 
2075 } //anonymous
2076 
SpecialFloatTests(Context & context)2077 SpecialFloatTests::SpecialFloatTests (Context& context)
2078 	: TestCaseGroup(context, "special_float", "Special float tests")
2079 {
2080 }
2081 
~SpecialFloatTests(void)2082 SpecialFloatTests::~SpecialFloatTests (void)
2083 {
2084 }
2085 
init(void)2086 void SpecialFloatTests::init (void)
2087 {
2088 	tcu::TestCaseGroup* const vertexGroup		= new tcu::TestCaseGroup(m_testCtx, "vertex",		"Run vertex shader with special float values");
2089 	tcu::TestCaseGroup* const fragmentGroup		= new tcu::TestCaseGroup(m_testCtx, "fragment",		"Run fragment shader with special float values");
2090 	tcu::TestCaseGroup* const framebufferGroup	= new tcu::TestCaseGroup(m_testCtx, "framebuffer",	"Test framebuffers containing special float values");
2091 
2092 	// .vertex
2093 	{
2094 		vertexGroup->addChild(new VertexAttributeCase	(m_context, "attribute_buffer",			"special attribute values in a buffer",					VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_VERTEX));
2095 		vertexGroup->addChild(new VertexAttributeCase	(m_context, "attribute_client",			"special attribute values in a client storage",			VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_VERTEX));
2096 		vertexGroup->addChild(new UniformCase			(m_context, "uniform",					"special uniform values",								UniformCase::TYPE_VERTEX));
2097 		vertexGroup->addChild(new TextureCase			(m_context, "texture",					"texture with special floating point values",			TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_CLIENT));
2098 		vertexGroup->addChild(new TextureCase			(m_context, "texture_pbo",				"texture (via pbo) with special floating point values",	TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_PBO));
2099 		vertexGroup->addChild(new TextureCase			(m_context, "texture_shadow",			"shadow texture with special floating point values",	TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_DEPTH, TextureCase::UPLOAD_CLIENT));
2100 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord",		"special texture coords",								TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD));
2101 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord_cube",	"special texture coords to cubemap",					TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD_CUBE));
2102 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_lod",				"special texture lod",									TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_LOD));
2103 		vertexGroup->addChild(new TextureSamplerCase	(m_context, "sampler_grad",				"special texture grad",									TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_GRAD));
2104 
2105 		addChild(vertexGroup);
2106 	}
2107 
2108 	// .fragment
2109 	{
2110 		fragmentGroup->addChild(new VertexAttributeCase	(m_context, "attribute_buffer",			"special attribute values in a buffer",					VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_FRAGMENT));
2111 		fragmentGroup->addChild(new VertexAttributeCase	(m_context, "attribute_client",			"special attribute values in a client storage",			VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_FRAGMENT));
2112 		fragmentGroup->addChild(new UniformCase			(m_context, "uniform",					"special uniform values",								UniformCase::TYPE_FRAGMENT));
2113 		fragmentGroup->addChild(new TextureCase			(m_context, "texture",					"texture with special floating point values",			TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_CLIENT));
2114 		fragmentGroup->addChild(new TextureCase			(m_context, "texture_pbo",				"texture (via pbo) with special floating point values",	TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_PBO));
2115 		fragmentGroup->addChild(new TextureCase			(m_context, "texture_shadow",			"shadow texture with special floating point values",	TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_DEPTH, TextureCase::UPLOAD_CLIENT));
2116 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord",		"special texture coords",								TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD));
2117 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_tex_coord_cube",	"special texture coords to cubemap",					TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD_CUBE));
2118 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_lod",				"special texture lod",									TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_LOD));
2119 		fragmentGroup->addChild(new TextureSamplerCase	(m_context, "sampler_grad",				"special texture grad",									TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_GRAD));
2120 
2121 		addChild(fragmentGroup);
2122 	}
2123 
2124 	// .framebuffer
2125 	{
2126 		framebufferGroup->addChild(new OutputCase		(m_context, "write_default",			"write special floating point values to default framebuffer",	FramebufferRenderCase::FBO_DEFAULT));
2127 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgba4",				"write special floating point values to RGBA4 framebuffer",		FramebufferRenderCase::FBO_RGBA4));
2128 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgb5_a1",			"write special floating point values to RGB5_A1 framebuffer",	FramebufferRenderCase::FBO_RGB5_A1));
2129 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgb565",				"write special floating point values to RGB565 framebuffer",	FramebufferRenderCase::FBO_RGB565));
2130 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgba8",				"write special floating point values to RGBA8 framebuffer",		FramebufferRenderCase::FBO_RGBA8));
2131 		framebufferGroup->addChild(new OutputCase		(m_context, "write_rgb10_a2",			"write special floating point values to RGB10_A2 framebuffer",	FramebufferRenderCase::FBO_RGB10_A2));
2132 		framebufferGroup->addChild(new OutputCase		(m_context, "write_float16",			"write special floating point values to float16 framebuffer",	FramebufferRenderCase::FBO_RGBA_FLOAT16));
2133 		framebufferGroup->addChild(new OutputCase		(m_context, "write_float32",			"write special floating point values to float32 framebuffer",	FramebufferRenderCase::FBO_RGBA_FLOAT32));
2134 
2135 		framebufferGroup->addChild(new BlendingCase		(m_context, "blend_default",			"blend special floating point values in a default framebuffer",	FramebufferRenderCase::FBO_DEFAULT));
2136 		framebufferGroup->addChild(new BlendingCase		(m_context, "blend_rgba8",				"blend special floating point values in a RGBA8 framebuffer",	FramebufferRenderCase::FBO_RGBA8));
2137 		framebufferGroup->addChild(new BlendingCase		(m_context, "blend_float16",			"blend special floating point values in a float16 framebuffer",	FramebufferRenderCase::FBO_RGBA_FLOAT16));
2138 
2139 		addChild(framebufferGroup);
2140 	}
2141 }
2142 
2143 } // Stress
2144 } // gles3
2145 } // deqp
2146