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