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 Fragment shader output tests.
22e5c31af7Sopenharmony_ci *
23e5c31af7Sopenharmony_ci * \todo [2012-04-10 pyry] Missing:
24e5c31af7Sopenharmony_ci *  + non-contiguous attachments in framebuffer
25e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
26e5c31af7Sopenharmony_ci
27e5c31af7Sopenharmony_ci#include "es3fFragmentOutputTests.hpp"
28e5c31af7Sopenharmony_ci#include "gluShaderUtil.hpp"
29e5c31af7Sopenharmony_ci#include "gluShaderProgram.hpp"
30e5c31af7Sopenharmony_ci#include "gluTextureUtil.hpp"
31e5c31af7Sopenharmony_ci#include "gluStrUtil.hpp"
32e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
33e5c31af7Sopenharmony_ci#include "tcuTexture.hpp"
34e5c31af7Sopenharmony_ci#include "tcuTextureUtil.hpp"
35e5c31af7Sopenharmony_ci#include "tcuVector.hpp"
36e5c31af7Sopenharmony_ci#include "tcuVectorUtil.hpp"
37e5c31af7Sopenharmony_ci#include "tcuImageCompare.hpp"
38e5c31af7Sopenharmony_ci#include "deRandom.hpp"
39e5c31af7Sopenharmony_ci#include "deStringUtil.hpp"
40e5c31af7Sopenharmony_ci#include "deMath.h"
41e5c31af7Sopenharmony_ci
42e5c31af7Sopenharmony_ci// For getFormatName() \todo [pyry] Move to glu?
43e5c31af7Sopenharmony_ci#include "es3fFboTestUtil.hpp"
44e5c31af7Sopenharmony_ci
45e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
46e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
47e5c31af7Sopenharmony_ci
48e5c31af7Sopenharmony_cinamespace deqp
49e5c31af7Sopenharmony_ci{
50e5c31af7Sopenharmony_cinamespace gles3
51e5c31af7Sopenharmony_ci{
52e5c31af7Sopenharmony_cinamespace Functional
53e5c31af7Sopenharmony_ci{
54e5c31af7Sopenharmony_ci
55e5c31af7Sopenharmony_ciusing std::vector;
56e5c31af7Sopenharmony_ciusing std::string;
57e5c31af7Sopenharmony_ciusing tcu::IVec2;
58e5c31af7Sopenharmony_ciusing tcu::IVec4;
59e5c31af7Sopenharmony_ciusing tcu::UVec2;
60e5c31af7Sopenharmony_ciusing tcu::UVec4;
61e5c31af7Sopenharmony_ciusing tcu::Vec2;
62e5c31af7Sopenharmony_ciusing tcu::Vec3;
63e5c31af7Sopenharmony_ciusing tcu::Vec4;
64e5c31af7Sopenharmony_ciusing tcu::BVec4;
65e5c31af7Sopenharmony_ciusing tcu::TestLog;
66e5c31af7Sopenharmony_ciusing FboTestUtil::getFormatName;
67e5c31af7Sopenharmony_ciusing FboTestUtil::getFramebufferReadFormat;
68e5c31af7Sopenharmony_ci
69e5c31af7Sopenharmony_cistruct BufferSpec
70e5c31af7Sopenharmony_ci{
71e5c31af7Sopenharmony_ci	BufferSpec (void)
72e5c31af7Sopenharmony_ci		: format	(GL_NONE)
73e5c31af7Sopenharmony_ci		, width		(0)
74e5c31af7Sopenharmony_ci		, height	(0)
75e5c31af7Sopenharmony_ci		, samples	(0)
76e5c31af7Sopenharmony_ci	{
77e5c31af7Sopenharmony_ci	}
78e5c31af7Sopenharmony_ci
79e5c31af7Sopenharmony_ci	BufferSpec (deUint32 format_, int width_, int height_, int samples_)
80e5c31af7Sopenharmony_ci		: format	(format_)
81e5c31af7Sopenharmony_ci		, width		(width_)
82e5c31af7Sopenharmony_ci		, height	(height_)
83e5c31af7Sopenharmony_ci		, samples	(samples_)
84e5c31af7Sopenharmony_ci	{
85e5c31af7Sopenharmony_ci	}
86e5c31af7Sopenharmony_ci
87e5c31af7Sopenharmony_ci	deUint32	format;
88e5c31af7Sopenharmony_ci	int			width;
89e5c31af7Sopenharmony_ci	int			height;
90e5c31af7Sopenharmony_ci	int			samples;
91e5c31af7Sopenharmony_ci};
92e5c31af7Sopenharmony_ci
93e5c31af7Sopenharmony_cistruct FragmentOutput
94e5c31af7Sopenharmony_ci{
95e5c31af7Sopenharmony_ci	FragmentOutput (void)
96e5c31af7Sopenharmony_ci		: type			(glu::TYPE_LAST)
97e5c31af7Sopenharmony_ci		, precision		(glu::PRECISION_LAST)
98e5c31af7Sopenharmony_ci		, location		(0)
99e5c31af7Sopenharmony_ci		, arrayLength	(0)
100e5c31af7Sopenharmony_ci	{
101e5c31af7Sopenharmony_ci	}
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_ci	FragmentOutput (glu::DataType type_, glu::Precision precision_, int location_, int arrayLength_ = 0)
104e5c31af7Sopenharmony_ci		: type			(type_)
105e5c31af7Sopenharmony_ci		, precision		(precision_)
106e5c31af7Sopenharmony_ci		, location		(location_)
107e5c31af7Sopenharmony_ci		, arrayLength	(arrayLength_)
108e5c31af7Sopenharmony_ci	{
109e5c31af7Sopenharmony_ci	}
110e5c31af7Sopenharmony_ci
111e5c31af7Sopenharmony_ci	glu::DataType	type;
112e5c31af7Sopenharmony_ci	glu::Precision	precision;
113e5c31af7Sopenharmony_ci	int				location;
114e5c31af7Sopenharmony_ci	int				arrayLength;	//!< 0 if not an array.
115e5c31af7Sopenharmony_ci};
116e5c31af7Sopenharmony_ci
117e5c31af7Sopenharmony_cistruct OutputVec
118e5c31af7Sopenharmony_ci{
119e5c31af7Sopenharmony_ci	vector<FragmentOutput> outputs;
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_ci	OutputVec& operator<< (const FragmentOutput& output)
122e5c31af7Sopenharmony_ci	{
123e5c31af7Sopenharmony_ci		outputs.push_back(output);
124e5c31af7Sopenharmony_ci		return *this;
125e5c31af7Sopenharmony_ci	}
126e5c31af7Sopenharmony_ci
127e5c31af7Sopenharmony_ci	vector<FragmentOutput> toVec (void) const
128e5c31af7Sopenharmony_ci	{
129e5c31af7Sopenharmony_ci		return outputs;
130e5c31af7Sopenharmony_ci	}
131e5c31af7Sopenharmony_ci};
132e5c31af7Sopenharmony_ci
133e5c31af7Sopenharmony_ciclass FragmentOutputCase : public TestCase
134e5c31af7Sopenharmony_ci{
135e5c31af7Sopenharmony_cipublic:
136e5c31af7Sopenharmony_ci								FragmentOutputCase			(Context& context, const char* name, const char* desc, const vector<BufferSpec>& fboSpec, const vector<FragmentOutput>& outputs);
137e5c31af7Sopenharmony_ci								~FragmentOutputCase			(void);
138e5c31af7Sopenharmony_ci
139e5c31af7Sopenharmony_ci	void						init						(void);
140e5c31af7Sopenharmony_ci	void						deinit						(void);
141e5c31af7Sopenharmony_ci	IterateResult				iterate						(void);
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ciprivate:
144e5c31af7Sopenharmony_ci								FragmentOutputCase			(const FragmentOutputCase& other);
145e5c31af7Sopenharmony_ci	FragmentOutputCase&			operator=					(const FragmentOutputCase& other);
146e5c31af7Sopenharmony_ci
147e5c31af7Sopenharmony_ci	vector<BufferSpec>			m_fboSpec;
148e5c31af7Sopenharmony_ci	vector<FragmentOutput>		m_outputs;
149e5c31af7Sopenharmony_ci
150e5c31af7Sopenharmony_ci	glu::ShaderProgram*			m_program;
151e5c31af7Sopenharmony_ci	deUint32					m_framebuffer;
152e5c31af7Sopenharmony_ci	vector<deUint32>			m_renderbuffers;
153e5c31af7Sopenharmony_ci};
154e5c31af7Sopenharmony_ci
155e5c31af7Sopenharmony_ciFragmentOutputCase::FragmentOutputCase (Context& context, const char* name, const char* desc, const vector<BufferSpec>& fboSpec, const vector<FragmentOutput>& outputs)
156e5c31af7Sopenharmony_ci	: TestCase		(context, name, desc)
157e5c31af7Sopenharmony_ci	, m_fboSpec		(fboSpec)
158e5c31af7Sopenharmony_ci	, m_outputs		(outputs)
159e5c31af7Sopenharmony_ci	, m_program		(DE_NULL)
160e5c31af7Sopenharmony_ci	, m_framebuffer	(0)
161e5c31af7Sopenharmony_ci{
162e5c31af7Sopenharmony_ci}
163e5c31af7Sopenharmony_ci
164e5c31af7Sopenharmony_ciFragmentOutputCase::~FragmentOutputCase (void)
165e5c31af7Sopenharmony_ci{
166e5c31af7Sopenharmony_ci	deinit();
167e5c31af7Sopenharmony_ci}
168e5c31af7Sopenharmony_ci
169e5c31af7Sopenharmony_cistatic glu::ShaderProgram* createProgram (const glu::RenderContext& context, const vector<FragmentOutput>& outputs)
170e5c31af7Sopenharmony_ci{
171e5c31af7Sopenharmony_ci	std::ostringstream	vtx;
172e5c31af7Sopenharmony_ci	std::ostringstream	frag;
173e5c31af7Sopenharmony_ci
174e5c31af7Sopenharmony_ci	vtx << "#version 300 es\n"
175e5c31af7Sopenharmony_ci		<< "in highp vec4 a_position;\n";
176e5c31af7Sopenharmony_ci	frag << "#version 300 es\n";
177e5c31af7Sopenharmony_ci
178e5c31af7Sopenharmony_ci	// Input-output declarations.
179e5c31af7Sopenharmony_ci	for (int outNdx = 0; outNdx < (int)outputs.size(); outNdx++)
180e5c31af7Sopenharmony_ci	{
181e5c31af7Sopenharmony_ci		const FragmentOutput&	output		= outputs[outNdx];
182e5c31af7Sopenharmony_ci		bool					isArray		= output.arrayLength > 0;
183e5c31af7Sopenharmony_ci		const char*				typeName	= glu::getDataTypeName(output.type);
184e5c31af7Sopenharmony_ci		const char*				outputPrec	= glu::getPrecisionName(output.precision);
185e5c31af7Sopenharmony_ci		bool					isFloat		= glu::isDataTypeFloatOrVec(output.type);
186e5c31af7Sopenharmony_ci		const char*				interp		= isFloat ? "smooth" : "flat";
187e5c31af7Sopenharmony_ci		const char*				interpPrec	= isFloat ? "highp" : outputPrec;
188e5c31af7Sopenharmony_ci
189e5c31af7Sopenharmony_ci		if (isArray)
190e5c31af7Sopenharmony_ci		{
191e5c31af7Sopenharmony_ci			for (int elemNdx = 0; elemNdx < output.arrayLength; elemNdx++)
192e5c31af7Sopenharmony_ci			{
193e5c31af7Sopenharmony_ci				vtx << "in " << interpPrec << " " << typeName << " in" << outNdx << "_" << elemNdx << ";\n"
194e5c31af7Sopenharmony_ci					<< interp << " out " << interpPrec << " " << typeName << " var" << outNdx << "_" << elemNdx << ";\n";
195e5c31af7Sopenharmony_ci				frag << interp << " in " << interpPrec << " " << typeName << " var" << outNdx << "_" << elemNdx << ";\n";
196e5c31af7Sopenharmony_ci			}
197e5c31af7Sopenharmony_ci			frag << "layout(location = " << output.location << ") out " << outputPrec << " " << typeName << " out" << outNdx << "[" << output.arrayLength << "];\n";
198e5c31af7Sopenharmony_ci		}
199e5c31af7Sopenharmony_ci		else
200e5c31af7Sopenharmony_ci		{
201e5c31af7Sopenharmony_ci			vtx << "in " << interpPrec << " " << typeName << " in" << outNdx << ";\n"
202e5c31af7Sopenharmony_ci				<< interp << " out " << interpPrec << " " << typeName << " var" << outNdx << ";\n";
203e5c31af7Sopenharmony_ci			frag << interp << " in " << interpPrec << " " << typeName << " var" << outNdx << ";\n"
204e5c31af7Sopenharmony_ci				 << "layout(location = " << output.location << ") out " << outputPrec << " " << typeName << " out" << outNdx << ";\n";
205e5c31af7Sopenharmony_ci		}
206e5c31af7Sopenharmony_ci	}
207e5c31af7Sopenharmony_ci
208e5c31af7Sopenharmony_ci	vtx << "\nvoid main()\n{\n";
209e5c31af7Sopenharmony_ci	frag << "\nvoid main()\n{\n";
210e5c31af7Sopenharmony_ci
211e5c31af7Sopenharmony_ci	vtx << "	gl_Position = a_position;\n";
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_ci	// Copy body
214e5c31af7Sopenharmony_ci	for (int outNdx = 0; outNdx < (int)outputs.size(); outNdx++)
215e5c31af7Sopenharmony_ci	{
216e5c31af7Sopenharmony_ci		const FragmentOutput&	output		= outputs[outNdx];
217e5c31af7Sopenharmony_ci		bool					isArray		= output.arrayLength > 0;
218e5c31af7Sopenharmony_ci
219e5c31af7Sopenharmony_ci		if (isArray)
220e5c31af7Sopenharmony_ci		{
221e5c31af7Sopenharmony_ci			for (int elemNdx = 0; elemNdx < output.arrayLength; elemNdx++)
222e5c31af7Sopenharmony_ci			{
223e5c31af7Sopenharmony_ci				vtx << "\tvar" << outNdx << "_" << elemNdx << " = in" << outNdx << "_" << elemNdx << ";\n";
224e5c31af7Sopenharmony_ci				frag << "\tout" << outNdx << "[" << elemNdx << "] = var" << outNdx << "_" << elemNdx << ";\n";
225e5c31af7Sopenharmony_ci			}
226e5c31af7Sopenharmony_ci		}
227e5c31af7Sopenharmony_ci		else
228e5c31af7Sopenharmony_ci		{
229e5c31af7Sopenharmony_ci			vtx << "\tvar" << outNdx << " = in" << outNdx << ";\n";
230e5c31af7Sopenharmony_ci			frag << "\tout" << outNdx << " = var" << outNdx << ";\n";
231e5c31af7Sopenharmony_ci		}
232e5c31af7Sopenharmony_ci	}
233e5c31af7Sopenharmony_ci
234e5c31af7Sopenharmony_ci	vtx << "}\n";
235e5c31af7Sopenharmony_ci	frag << "}\n";
236e5c31af7Sopenharmony_ci
237e5c31af7Sopenharmony_ci	return new glu::ShaderProgram(context, glu::makeVtxFragSources(vtx.str(), frag.str()));
238e5c31af7Sopenharmony_ci}
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_civoid FragmentOutputCase::init (void)
241e5c31af7Sopenharmony_ci{
242e5c31af7Sopenharmony_ci	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
243e5c31af7Sopenharmony_ci	TestLog&				log		= m_testCtx.getLog();
244e5c31af7Sopenharmony_ci
245e5c31af7Sopenharmony_ci	// Check that all attachments are supported
246e5c31af7Sopenharmony_ci	for (std::vector<BufferSpec>::const_iterator bufIter = m_fboSpec.begin(); bufIter != m_fboSpec.end(); ++bufIter)
247e5c31af7Sopenharmony_ci	{
248e5c31af7Sopenharmony_ci		if (!glu::isSizedFormatColorRenderable(m_context.getRenderContext(), m_context.getContextInfo(), bufIter->format))
249e5c31af7Sopenharmony_ci			throw tcu::NotSupportedError("Unsupported attachment format");
250e5c31af7Sopenharmony_ci	}
251e5c31af7Sopenharmony_ci
252e5c31af7Sopenharmony_ci	DE_ASSERT(!m_program);
253e5c31af7Sopenharmony_ci	m_program = createProgram(m_context.getRenderContext(), m_outputs);
254e5c31af7Sopenharmony_ci
255e5c31af7Sopenharmony_ci	log << *m_program;
256e5c31af7Sopenharmony_ci	if (!m_program->isOk())
257e5c31af7Sopenharmony_ci		TCU_FAIL("Compile failed");
258e5c31af7Sopenharmony_ci
259e5c31af7Sopenharmony_ci	// Print render target info to log.
260e5c31af7Sopenharmony_ci	log << TestLog::Section("Framebuffer", "Framebuffer configuration");
261e5c31af7Sopenharmony_ci
262e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < (int)m_fboSpec.size(); ndx++)
263e5c31af7Sopenharmony_ci		log << TestLog::Message << "COLOR_ATTACHMENT" << ndx << ": "
264e5c31af7Sopenharmony_ci								<< glu::getTextureFormatStr(m_fboSpec[ndx].format) << ", "
265e5c31af7Sopenharmony_ci								<< m_fboSpec[ndx].width << "x" << m_fboSpec[ndx].height << ", "
266e5c31af7Sopenharmony_ci								<< m_fboSpec[ndx].samples << " samples"
267e5c31af7Sopenharmony_ci			<< TestLog::EndMessage;
268e5c31af7Sopenharmony_ci
269e5c31af7Sopenharmony_ci	log << TestLog::EndSection;
270e5c31af7Sopenharmony_ci
271e5c31af7Sopenharmony_ci	// Create framebuffer.
272e5c31af7Sopenharmony_ci	m_renderbuffers.resize(m_fboSpec.size(), 0);
273e5c31af7Sopenharmony_ci	gl.genFramebuffers(1, &m_framebuffer);
274e5c31af7Sopenharmony_ci	gl.genRenderbuffers((int)m_renderbuffers.size(), &m_renderbuffers[0]);
275e5c31af7Sopenharmony_ci
276e5c31af7Sopenharmony_ci	gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
277e5c31af7Sopenharmony_ci
278e5c31af7Sopenharmony_ci	for (int bufNdx = 0; bufNdx < (int)m_renderbuffers.size(); bufNdx++)
279e5c31af7Sopenharmony_ci	{
280e5c31af7Sopenharmony_ci		deUint32			rbo			= m_renderbuffers[bufNdx];
281e5c31af7Sopenharmony_ci		const BufferSpec&	bufSpec		= m_fboSpec[bufNdx];
282e5c31af7Sopenharmony_ci		deUint32			attachment	= GL_COLOR_ATTACHMENT0+bufNdx;
283e5c31af7Sopenharmony_ci
284e5c31af7Sopenharmony_ci		gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
285e5c31af7Sopenharmony_ci		gl.renderbufferStorageMultisample(GL_RENDERBUFFER, bufSpec.samples, bufSpec.format, bufSpec.width, bufSpec.height);
286e5c31af7Sopenharmony_ci		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbo);
287e5c31af7Sopenharmony_ci	}
288e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "After framebuffer setup");
289e5c31af7Sopenharmony_ci
290e5c31af7Sopenharmony_ci	deUint32 fboStatus = gl.checkFramebufferStatus(GL_FRAMEBUFFER);
291e5c31af7Sopenharmony_ci	if (fboStatus == GL_FRAMEBUFFER_UNSUPPORTED)
292e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("Framebuffer not supported", "", __FILE__, __LINE__);
293e5c31af7Sopenharmony_ci	else if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
294e5c31af7Sopenharmony_ci		throw tcu::TestError((string("Incomplete framebuffer: ") + glu::getFramebufferStatusStr(fboStatus).toString()).c_str(), "", __FILE__, __LINE__);
295e5c31af7Sopenharmony_ci
296e5c31af7Sopenharmony_ci	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
297e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "After init");
298e5c31af7Sopenharmony_ci}
299e5c31af7Sopenharmony_ci
300e5c31af7Sopenharmony_civoid FragmentOutputCase::deinit (void)
301e5c31af7Sopenharmony_ci{
302e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
303e5c31af7Sopenharmony_ci
304e5c31af7Sopenharmony_ci	if (m_framebuffer)
305e5c31af7Sopenharmony_ci	{
306e5c31af7Sopenharmony_ci		gl.deleteFramebuffers(1, &m_framebuffer);
307e5c31af7Sopenharmony_ci		m_framebuffer = 0;
308e5c31af7Sopenharmony_ci	}
309e5c31af7Sopenharmony_ci
310e5c31af7Sopenharmony_ci	if (!m_renderbuffers.empty())
311e5c31af7Sopenharmony_ci	{
312e5c31af7Sopenharmony_ci		gl.deleteRenderbuffers((int)m_renderbuffers.size(), &m_renderbuffers[0]);
313e5c31af7Sopenharmony_ci		m_renderbuffers.clear();
314e5c31af7Sopenharmony_ci	}
315e5c31af7Sopenharmony_ci
316e5c31af7Sopenharmony_ci	delete m_program;
317e5c31af7Sopenharmony_ci	m_program = DE_NULL;
318e5c31af7Sopenharmony_ci}
319e5c31af7Sopenharmony_ci
320e5c31af7Sopenharmony_cistatic IVec2 getMinSize (const vector<BufferSpec>& fboSpec)
321e5c31af7Sopenharmony_ci{
322e5c31af7Sopenharmony_ci	IVec2 minSize(0x7fffffff, 0x7fffffff);
323e5c31af7Sopenharmony_ci	for (vector<BufferSpec>::const_iterator i = fboSpec.begin(); i != fboSpec.end(); i++)
324e5c31af7Sopenharmony_ci	{
325e5c31af7Sopenharmony_ci		minSize.x() = de::min(minSize.x(), i->width);
326e5c31af7Sopenharmony_ci		minSize.y() = de::min(minSize.y(), i->height);
327e5c31af7Sopenharmony_ci	}
328e5c31af7Sopenharmony_ci	return minSize;
329e5c31af7Sopenharmony_ci}
330e5c31af7Sopenharmony_ci
331e5c31af7Sopenharmony_cistatic int getNumInputVectors (const vector<FragmentOutput>& outputs)
332e5c31af7Sopenharmony_ci{
333e5c31af7Sopenharmony_ci	int numVecs = 0;
334e5c31af7Sopenharmony_ci	for (vector<FragmentOutput>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
335e5c31af7Sopenharmony_ci		numVecs += (i->arrayLength > 0 ? i->arrayLength : 1);
336e5c31af7Sopenharmony_ci	return numVecs;
337e5c31af7Sopenharmony_ci}
338e5c31af7Sopenharmony_ci
339e5c31af7Sopenharmony_cistatic Vec2 getFloatRange (glu::Precision precision)
340e5c31af7Sopenharmony_ci{
341e5c31af7Sopenharmony_ci	// \todo [2012-04-09 pyry] Not quite the full ranges.
342e5c31af7Sopenharmony_ci	static const Vec2 ranges[] =
343e5c31af7Sopenharmony_ci	{
344e5c31af7Sopenharmony_ci		Vec2(-2.0f, 2.0f),
345e5c31af7Sopenharmony_ci		Vec2(-16000.0f, 16000.0f),
346e5c31af7Sopenharmony_ci		Vec2(-1e35f, 1e35f)
347e5c31af7Sopenharmony_ci	};
348e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST);
349e5c31af7Sopenharmony_ci	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges)));
350e5c31af7Sopenharmony_ci	return ranges[precision];
351e5c31af7Sopenharmony_ci}
352e5c31af7Sopenharmony_ci
353e5c31af7Sopenharmony_cistatic IVec2 getIntRange (glu::Precision precision)
354e5c31af7Sopenharmony_ci{
355e5c31af7Sopenharmony_ci	static const IVec2 ranges[] =
356e5c31af7Sopenharmony_ci	{
357e5c31af7Sopenharmony_ci		IVec2(-(1<< 7), (1<< 7)-1),
358e5c31af7Sopenharmony_ci		IVec2(-(1<<15), (1<<15)-1),
359e5c31af7Sopenharmony_ci		IVec2(0x80000000, 0x7fffffff)
360e5c31af7Sopenharmony_ci	};
361e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST);
362e5c31af7Sopenharmony_ci	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges)));
363e5c31af7Sopenharmony_ci	return ranges[precision];
364e5c31af7Sopenharmony_ci}
365e5c31af7Sopenharmony_ci
366e5c31af7Sopenharmony_cistatic UVec2 getUintRange (glu::Precision precision)
367e5c31af7Sopenharmony_ci{
368e5c31af7Sopenharmony_ci	static const UVec2 ranges[] =
369e5c31af7Sopenharmony_ci	{
370e5c31af7Sopenharmony_ci		UVec2(0, (1<< 8)-1),
371e5c31af7Sopenharmony_ci		UVec2(0, (1<<16)-1),
372e5c31af7Sopenharmony_ci		UVec2(0, 0xffffffffu)
373e5c31af7Sopenharmony_ci	};
374e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST);
375e5c31af7Sopenharmony_ci	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges)));
376e5c31af7Sopenharmony_ci	return ranges[precision];
377e5c31af7Sopenharmony_ci}
378e5c31af7Sopenharmony_ci
379e5c31af7Sopenharmony_cistatic inline Vec4 readVec4 (const float* ptr, int numComponents)
380e5c31af7Sopenharmony_ci{
381e5c31af7Sopenharmony_ci	DE_ASSERT(numComponents >= 1);
382e5c31af7Sopenharmony_ci	return Vec4(ptr[0],
383e5c31af7Sopenharmony_ci				numComponents >= 2 ? ptr[1] : 0.0f,
384e5c31af7Sopenharmony_ci				numComponents >= 3 ? ptr[2] : 0.0f,
385e5c31af7Sopenharmony_ci				numComponents >= 4 ? ptr[3] : 0.0f);
386e5c31af7Sopenharmony_ci}
387e5c31af7Sopenharmony_ci
388e5c31af7Sopenharmony_cistatic inline IVec4 readIVec4 (const int* ptr, int numComponents)
389e5c31af7Sopenharmony_ci{
390e5c31af7Sopenharmony_ci	DE_ASSERT(numComponents >= 1);
391e5c31af7Sopenharmony_ci	return IVec4(ptr[0],
392e5c31af7Sopenharmony_ci				 numComponents >= 2 ? ptr[1] : 0,
393e5c31af7Sopenharmony_ci				 numComponents >= 3 ? ptr[2] : 0,
394e5c31af7Sopenharmony_ci				 numComponents >= 4 ? ptr[3] : 0);
395e5c31af7Sopenharmony_ci}
396e5c31af7Sopenharmony_ci
397e5c31af7Sopenharmony_cistatic void renderFloatReference (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight, int numComponents, const float* vertices)
398e5c31af7Sopenharmony_ci{
399e5c31af7Sopenharmony_ci	const bool	isSRGB		= tcu::isSRGB(dst.getFormat());
400e5c31af7Sopenharmony_ci	const float	cellW		= (float)dst.getWidth() / (float)(gridWidth-1);
401e5c31af7Sopenharmony_ci	const float	cellH		= (float)dst.getHeight() / (float)(gridHeight-1);
402e5c31af7Sopenharmony_ci
403e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
404e5c31af7Sopenharmony_ci	{
405e5c31af7Sopenharmony_ci		for (int x = 0; x < dst.getWidth(); x++)
406e5c31af7Sopenharmony_ci		{
407e5c31af7Sopenharmony_ci			const int		cellX	= de::clamp(deFloorFloatToInt32((float)x / cellW), 0, gridWidth-2);
408e5c31af7Sopenharmony_ci			const int		cellY	= de::clamp(deFloorFloatToInt32((float)y / cellH), 0, gridHeight-2);
409e5c31af7Sopenharmony_ci			const float		xf		= ((float)x - (float)cellX*cellW + 0.5f) / cellW;
410e5c31af7Sopenharmony_ci			const float		yf		= ((float)y - (float)cellY*cellH + 0.5f) / cellH;
411e5c31af7Sopenharmony_ci			const Vec4		v00		= readVec4(vertices + ((cellY+0)*gridWidth + cellX+0)*numComponents, numComponents);
412e5c31af7Sopenharmony_ci			const Vec4		v01		= readVec4(vertices + ((cellY+1)*gridWidth + cellX+0)*numComponents, numComponents);
413e5c31af7Sopenharmony_ci			const Vec4		v10		= readVec4(vertices + ((cellY+0)*gridWidth + cellX+1)*numComponents, numComponents);
414e5c31af7Sopenharmony_ci			const Vec4		v11		= readVec4(vertices + ((cellY+1)*gridWidth + cellX+1)*numComponents, numComponents);
415e5c31af7Sopenharmony_ci			const bool		tri		= xf + yf >= 1.0f;
416e5c31af7Sopenharmony_ci			const Vec4&		v0		= tri ? v11 : v00;
417e5c31af7Sopenharmony_ci			const Vec4&		v1		= tri ? v01 : v10;
418e5c31af7Sopenharmony_ci			const Vec4&		v2		= tri ? v10 : v01;
419e5c31af7Sopenharmony_ci			const float		s		= tri ? 1.0f-xf : xf;
420e5c31af7Sopenharmony_ci			const float		t		= tri ? 1.0f-yf : yf;
421e5c31af7Sopenharmony_ci			const Vec4		color	= v0 + (v1-v0)*s + (v2-v0)*t;
422e5c31af7Sopenharmony_ci
423e5c31af7Sopenharmony_ci			dst.setPixel(isSRGB ? tcu::linearToSRGB(color) : color, x, y);
424e5c31af7Sopenharmony_ci		}
425e5c31af7Sopenharmony_ci	}
426e5c31af7Sopenharmony_ci}
427e5c31af7Sopenharmony_ci
428e5c31af7Sopenharmony_cistatic void renderIntReference (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight, int numComponents, const int* vertices)
429e5c31af7Sopenharmony_ci{
430e5c31af7Sopenharmony_ci	float	cellW		= (float)dst.getWidth() / (float)(gridWidth-1);
431e5c31af7Sopenharmony_ci	float	cellH		= (float)dst.getHeight() / (float)(gridHeight-1);
432e5c31af7Sopenharmony_ci
433e5c31af7Sopenharmony_ci	for (int y = 0; y < dst.getHeight(); y++)
434e5c31af7Sopenharmony_ci	{
435e5c31af7Sopenharmony_ci		for (int x = 0; x < dst.getWidth(); x++)
436e5c31af7Sopenharmony_ci		{
437e5c31af7Sopenharmony_ci			int			cellX	= de::clamp(deFloorFloatToInt32((float)x / cellW), 0, gridWidth-2);
438e5c31af7Sopenharmony_ci			int			cellY	= de::clamp(deFloorFloatToInt32((float)y / cellH), 0, gridHeight-2);
439e5c31af7Sopenharmony_ci			IVec4		c		= readIVec4(vertices + (cellY*gridWidth + cellX+1)*numComponents, numComponents);
440e5c31af7Sopenharmony_ci
441e5c31af7Sopenharmony_ci			dst.setPixel(c, x, y);
442e5c31af7Sopenharmony_ci		}
443e5c31af7Sopenharmony_ci	}
444e5c31af7Sopenharmony_ci}
445e5c31af7Sopenharmony_ci
446e5c31af7Sopenharmony_cistatic const IVec4 s_swizzles[] =
447e5c31af7Sopenharmony_ci{
448e5c31af7Sopenharmony_ci	IVec4(0,1,2,3),
449e5c31af7Sopenharmony_ci	IVec4(1,2,3,0),
450e5c31af7Sopenharmony_ci	IVec4(2,3,0,1),
451e5c31af7Sopenharmony_ci	IVec4(3,0,1,2),
452e5c31af7Sopenharmony_ci	IVec4(3,2,1,0),
453e5c31af7Sopenharmony_ci	IVec4(2,1,0,3),
454e5c31af7Sopenharmony_ci	IVec4(1,0,3,2),
455e5c31af7Sopenharmony_ci	IVec4(0,3,2,1)
456e5c31af7Sopenharmony_ci};
457e5c31af7Sopenharmony_ci
458e5c31af7Sopenharmony_citemplate <typename T>
459e5c31af7Sopenharmony_ciinline tcu::Vector<T, 4> swizzleVec (const tcu::Vector<T, 4>& vec, int swzNdx)
460e5c31af7Sopenharmony_ci{
461e5c31af7Sopenharmony_ci	const IVec4& swz = s_swizzles[swzNdx % DE_LENGTH_OF_ARRAY(s_swizzles)];
462e5c31af7Sopenharmony_ci	return vec.swizzle(swz[0], swz[1], swz[2], swz[3]);
463e5c31af7Sopenharmony_ci}
464e5c31af7Sopenharmony_ci
465e5c31af7Sopenharmony_cinamespace
466e5c31af7Sopenharmony_ci{
467e5c31af7Sopenharmony_ci
468e5c31af7Sopenharmony_cistruct AttachmentData
469e5c31af7Sopenharmony_ci{
470e5c31af7Sopenharmony_ci	tcu::TextureFormat		format;					//!< Actual format of attachment.
471e5c31af7Sopenharmony_ci	tcu::TextureFormat		referenceFormat;		//!< Used for reference rendering.
472e5c31af7Sopenharmony_ci	tcu::TextureFormat		readFormat;
473e5c31af7Sopenharmony_ci	int						numWrittenChannels;
474e5c31af7Sopenharmony_ci	glu::Precision			outPrecision;
475e5c31af7Sopenharmony_ci	vector<deUint8>			renderedData;
476e5c31af7Sopenharmony_ci	vector<deUint8>			referenceData;
477e5c31af7Sopenharmony_ci};
478e5c31af7Sopenharmony_ci
479e5c31af7Sopenharmony_citemplate<typename Type>
480e5c31af7Sopenharmony_cistring valueRangeToString (int numValidChannels, const tcu::Vector<Type, 4>& minValue, const tcu::Vector<Type, 4>& maxValue)
481e5c31af7Sopenharmony_ci{
482e5c31af7Sopenharmony_ci	std::ostringstream stream;
483e5c31af7Sopenharmony_ci
484e5c31af7Sopenharmony_ci	stream << "(";
485e5c31af7Sopenharmony_ci
486e5c31af7Sopenharmony_ci	for (int i = 0; i < 4; i++)
487e5c31af7Sopenharmony_ci	{
488e5c31af7Sopenharmony_ci		if (i != 0)
489e5c31af7Sopenharmony_ci			stream << ", ";
490e5c31af7Sopenharmony_ci
491e5c31af7Sopenharmony_ci		if (i < numValidChannels)
492e5c31af7Sopenharmony_ci			stream << minValue[i] << " -> " << maxValue[i];
493e5c31af7Sopenharmony_ci		else
494e5c31af7Sopenharmony_ci			stream << "Undef";
495e5c31af7Sopenharmony_ci	}
496e5c31af7Sopenharmony_ci
497e5c31af7Sopenharmony_ci	stream << ")";
498e5c31af7Sopenharmony_ci
499e5c31af7Sopenharmony_ci	return stream.str();
500e5c31af7Sopenharmony_ci}
501e5c31af7Sopenharmony_ci
502e5c31af7Sopenharmony_civoid clearUndefined (const tcu::PixelBufferAccess& access, int numValidChannels)
503e5c31af7Sopenharmony_ci{
504e5c31af7Sopenharmony_ci	for (int y = 0; y < access.getHeight(); y++)
505e5c31af7Sopenharmony_ci	for (int x = 0; x < access.getWidth(); x++)
506e5c31af7Sopenharmony_ci	{
507e5c31af7Sopenharmony_ci		switch (tcu::getTextureChannelClass(access.getFormat().type))
508e5c31af7Sopenharmony_ci		{
509e5c31af7Sopenharmony_ci			case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
510e5c31af7Sopenharmony_ci			{
511e5c31af7Sopenharmony_ci				const Vec4	srcPixel	= access.getPixel(x, y);
512e5c31af7Sopenharmony_ci				Vec4		dstPixel	(0.0f, 0.0f, 0.0f, 1.0f);
513e5c31af7Sopenharmony_ci
514e5c31af7Sopenharmony_ci				for (int channelNdx = 0; channelNdx < numValidChannels; channelNdx++)
515e5c31af7Sopenharmony_ci					dstPixel[channelNdx] = srcPixel[channelNdx];
516e5c31af7Sopenharmony_ci
517e5c31af7Sopenharmony_ci				access.setPixel(dstPixel, x, y);
518e5c31af7Sopenharmony_ci				break;
519e5c31af7Sopenharmony_ci			}
520e5c31af7Sopenharmony_ci
521e5c31af7Sopenharmony_ci			case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
522e5c31af7Sopenharmony_ci			case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
523e5c31af7Sopenharmony_ci			case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
524e5c31af7Sopenharmony_ci			case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
525e5c31af7Sopenharmony_ci			{
526e5c31af7Sopenharmony_ci				const IVec4	bitDepth	= tcu::getTextureFormatBitDepth(access.getFormat());
527e5c31af7Sopenharmony_ci				const IVec4	srcPixel	= access.getPixelInt(x, y);
528e5c31af7Sopenharmony_ci				IVec4		dstPixel	(0, 0, 0, (int)(((deInt64)0x1u << bitDepth.w()) - 1));
529e5c31af7Sopenharmony_ci
530e5c31af7Sopenharmony_ci				for (int channelNdx = 0; channelNdx < numValidChannels; channelNdx++)
531e5c31af7Sopenharmony_ci					dstPixel[channelNdx] = srcPixel[channelNdx];
532e5c31af7Sopenharmony_ci
533e5c31af7Sopenharmony_ci				access.setPixel(dstPixel, x, y);
534e5c31af7Sopenharmony_ci				break;
535e5c31af7Sopenharmony_ci			}
536e5c31af7Sopenharmony_ci
537e5c31af7Sopenharmony_ci			default:
538e5c31af7Sopenharmony_ci				DE_ASSERT(false);
539e5c31af7Sopenharmony_ci		}
540e5c31af7Sopenharmony_ci	}
541e5c31af7Sopenharmony_ci}
542e5c31af7Sopenharmony_ci
543e5c31af7Sopenharmony_ci} // anonymous
544e5c31af7Sopenharmony_ci
545e5c31af7Sopenharmony_ciFragmentOutputCase::IterateResult FragmentOutputCase::iterate (void)
546e5c31af7Sopenharmony_ci{
547e5c31af7Sopenharmony_ci	TestLog&					log					= m_testCtx.getLog();
548e5c31af7Sopenharmony_ci	const glw::Functions&		gl					= m_context.getRenderContext().getFunctions();
549e5c31af7Sopenharmony_ci
550e5c31af7Sopenharmony_ci	// Compute grid size & index list.
551e5c31af7Sopenharmony_ci	const int					minCellSize			= 8;
552e5c31af7Sopenharmony_ci	const IVec2					minBufSize			= getMinSize(m_fboSpec);
553e5c31af7Sopenharmony_ci	const int					gridWidth			= de::clamp(minBufSize.x()/minCellSize, 1, 255)+1;
554e5c31af7Sopenharmony_ci	const int					gridHeight			= de::clamp(minBufSize.y()/minCellSize, 1, 255)+1;
555e5c31af7Sopenharmony_ci	const int					numVertices			= gridWidth*gridHeight;
556e5c31af7Sopenharmony_ci	const int					numQuads			= (gridWidth-1)*(gridHeight-1);
557e5c31af7Sopenharmony_ci	const int					numIndices			= numQuads*6;
558e5c31af7Sopenharmony_ci
559e5c31af7Sopenharmony_ci	const int					numInputVecs		= getNumInputVectors(m_outputs);
560e5c31af7Sopenharmony_ci	vector<vector<deUint32> >	inputs				(numInputVecs);
561e5c31af7Sopenharmony_ci	vector<float>				positions			(numVertices*4);
562e5c31af7Sopenharmony_ci	vector<deUint16>			indices				(numIndices);
563e5c31af7Sopenharmony_ci
564e5c31af7Sopenharmony_ci	const int					readAlignment		= 4;
565e5c31af7Sopenharmony_ci	const int					viewportW			= minBufSize.x();
566e5c31af7Sopenharmony_ci	const int					viewportH			= minBufSize.y();
567e5c31af7Sopenharmony_ci	const int					numAttachments		= (int)m_fboSpec.size();
568e5c31af7Sopenharmony_ci
569e5c31af7Sopenharmony_ci	vector<deUint32>			drawBuffers			(numAttachments);
570e5c31af7Sopenharmony_ci	vector<AttachmentData>		attachments			(numAttachments);
571e5c31af7Sopenharmony_ci
572e5c31af7Sopenharmony_ci	// Initialize attachment data.
573e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < numAttachments; ndx++)
574e5c31af7Sopenharmony_ci	{
575e5c31af7Sopenharmony_ci		const tcu::TextureFormat		texFmt			= glu::mapGLInternalFormat(m_fboSpec[ndx].format);
576e5c31af7Sopenharmony_ci		const tcu::TextureChannelClass	chnClass		= tcu::getTextureChannelClass(texFmt.type);
577e5c31af7Sopenharmony_ci		const bool						isFixedPoint	= chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
578e5c31af7Sopenharmony_ci														  chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
579e5c31af7Sopenharmony_ci
580e5c31af7Sopenharmony_ci		// \note Fixed-point formats use float reference to enable more accurate result verification.
581e5c31af7Sopenharmony_ci		const tcu::TextureFormat		refFmt			= isFixedPoint ? tcu::TextureFormat(texFmt.order, tcu::TextureFormat::FLOAT) : texFmt;
582e5c31af7Sopenharmony_ci		const tcu::TextureFormat		readFmt			= getFramebufferReadFormat(texFmt);
583e5c31af7Sopenharmony_ci		const int						attachmentW		= m_fboSpec[ndx].width;
584e5c31af7Sopenharmony_ci		const int						attachmentH		= m_fboSpec[ndx].height;
585e5c31af7Sopenharmony_ci
586e5c31af7Sopenharmony_ci		drawBuffers[ndx]					= GL_COLOR_ATTACHMENT0+ndx;
587e5c31af7Sopenharmony_ci		attachments[ndx].format				= texFmt;
588e5c31af7Sopenharmony_ci		attachments[ndx].readFormat			= readFmt;
589e5c31af7Sopenharmony_ci		attachments[ndx].referenceFormat	= refFmt;
590e5c31af7Sopenharmony_ci		attachments[ndx].renderedData.resize(readFmt.getPixelSize()*attachmentW*attachmentH);
591e5c31af7Sopenharmony_ci		attachments[ndx].referenceData.resize(refFmt.getPixelSize()*attachmentW*attachmentH);
592e5c31af7Sopenharmony_ci	}
593e5c31af7Sopenharmony_ci
594e5c31af7Sopenharmony_ci	// Initialize indices.
595e5c31af7Sopenharmony_ci	for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
596e5c31af7Sopenharmony_ci	{
597e5c31af7Sopenharmony_ci		int	quadY	= quadNdx / (gridWidth-1);
598e5c31af7Sopenharmony_ci		int quadX	= quadNdx - quadY*(gridWidth-1);
599e5c31af7Sopenharmony_ci
600e5c31af7Sopenharmony_ci		indices[quadNdx*6+0] = deUint16(quadX + quadY*gridWidth);
601e5c31af7Sopenharmony_ci		indices[quadNdx*6+1] = deUint16(quadX + (quadY+1)*gridWidth);
602e5c31af7Sopenharmony_ci		indices[quadNdx*6+2] = deUint16(quadX + quadY*gridWidth + 1);
603e5c31af7Sopenharmony_ci		indices[quadNdx*6+3] = indices[quadNdx*6+1];
604e5c31af7Sopenharmony_ci		indices[quadNdx*6+4] = deUint16(quadX + (quadY+1)*gridWidth + 1);
605e5c31af7Sopenharmony_ci		indices[quadNdx*6+5] = indices[quadNdx*6+2];
606e5c31af7Sopenharmony_ci	}
607e5c31af7Sopenharmony_ci
608e5c31af7Sopenharmony_ci	for (int y = 0; y < gridHeight; y++)
609e5c31af7Sopenharmony_ci	{
610e5c31af7Sopenharmony_ci		for (int x = 0; x < gridWidth; x++)
611e5c31af7Sopenharmony_ci		{
612e5c31af7Sopenharmony_ci			float	xf	= (float)x / (float)(gridWidth-1);
613e5c31af7Sopenharmony_ci			float	yf	= (float)y / (float)(gridHeight-1);
614e5c31af7Sopenharmony_ci
615e5c31af7Sopenharmony_ci			positions[(y*gridWidth + x)*4 + 0] = 2.0f*xf - 1.0f;
616e5c31af7Sopenharmony_ci			positions[(y*gridWidth + x)*4 + 1] = 2.0f*yf - 1.0f;
617e5c31af7Sopenharmony_ci			positions[(y*gridWidth + x)*4 + 2] = 0.0f;
618e5c31af7Sopenharmony_ci			positions[(y*gridWidth + x)*4 + 3] = 1.0f;
619e5c31af7Sopenharmony_ci		}
620e5c31af7Sopenharmony_ci	}
621e5c31af7Sopenharmony_ci
622e5c31af7Sopenharmony_ci	// Initialize input vectors.
623e5c31af7Sopenharmony_ci	{
624e5c31af7Sopenharmony_ci		int curInVec = 0;
625e5c31af7Sopenharmony_ci		for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++)
626e5c31af7Sopenharmony_ci		{
627e5c31af7Sopenharmony_ci			const FragmentOutput&	output		= m_outputs[outputNdx];
628e5c31af7Sopenharmony_ci			bool					isFloat		= glu::isDataTypeFloatOrVec(output.type);
629e5c31af7Sopenharmony_ci			bool					isInt		= glu::isDataTypeIntOrIVec(output.type);
630e5c31af7Sopenharmony_ci			bool					isUint		= glu::isDataTypeUintOrUVec(output.type);
631e5c31af7Sopenharmony_ci			int						numVecs		= output.arrayLength > 0 ? output.arrayLength : 1;
632e5c31af7Sopenharmony_ci			int						numScalars	= glu::getDataTypeScalarSize(output.type);
633e5c31af7Sopenharmony_ci
634e5c31af7Sopenharmony_ci			for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
635e5c31af7Sopenharmony_ci			{
636e5c31af7Sopenharmony_ci				inputs[curInVec].resize(numVertices*numScalars);
637e5c31af7Sopenharmony_ci
638e5c31af7Sopenharmony_ci				// Record how many outputs are written in attachment.
639e5c31af7Sopenharmony_ci				DE_ASSERT(output.location+vecNdx < (int)attachments.size());
640e5c31af7Sopenharmony_ci				attachments[output.location+vecNdx].numWrittenChannels	= numScalars;
641e5c31af7Sopenharmony_ci				attachments[output.location+vecNdx].outPrecision		= output.precision;
642e5c31af7Sopenharmony_ci
643e5c31af7Sopenharmony_ci				if (isFloat)
644e5c31af7Sopenharmony_ci				{
645e5c31af7Sopenharmony_ci					Vec2		range	= getFloatRange(output.precision);
646e5c31af7Sopenharmony_ci					Vec4		minVal	(range.x());
647e5c31af7Sopenharmony_ci					Vec4		maxVal	(range.y());
648e5c31af7Sopenharmony_ci					float*		dst		= (float*)&inputs[curInVec][0];
649e5c31af7Sopenharmony_ci
650e5c31af7Sopenharmony_ci					if (de::inBounds(output.location+vecNdx, 0, (int)attachments.size()))
651e5c31af7Sopenharmony_ci					{
652e5c31af7Sopenharmony_ci						// \note Floating-point precision conversion is not well-defined. For that reason we must
653e5c31af7Sopenharmony_ci						//       limit value range to intersection of both data type and render target value ranges.
654e5c31af7Sopenharmony_ci						const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(attachments[output.location+vecNdx].format);
655e5c31af7Sopenharmony_ci						minVal = tcu::max(minVal, fmtInfo.valueMin);
656e5c31af7Sopenharmony_ci						maxVal = tcu::min(maxVal, fmtInfo.valueMax);
657e5c31af7Sopenharmony_ci					}
658e5c31af7Sopenharmony_ci
659e5c31af7Sopenharmony_ci					m_testCtx.getLog() << TestLog::Message << "out" << curInVec << " value range: " << valueRangeToString(numScalars, minVal, maxVal) << TestLog::EndMessage;
660e5c31af7Sopenharmony_ci
661e5c31af7Sopenharmony_ci					for (int y = 0; y < gridHeight; y++)
662e5c31af7Sopenharmony_ci					{
663e5c31af7Sopenharmony_ci						for (int x = 0; x < gridWidth; x++)
664e5c31af7Sopenharmony_ci						{
665e5c31af7Sopenharmony_ci							float	xf	= (float)x / (float)(gridWidth-1);
666e5c31af7Sopenharmony_ci							float	yf	= (float)y / (float)(gridHeight-1);
667e5c31af7Sopenharmony_ci
668e5c31af7Sopenharmony_ci							float	f0	= (xf + yf) * 0.5f;
669e5c31af7Sopenharmony_ci							float	f1	= 0.5f + (xf - yf) * 0.5f;
670e5c31af7Sopenharmony_ci							Vec4	f	= swizzleVec(Vec4(f0, f1, 1.0f-f0, 1.0f-f1), curInVec);
671e5c31af7Sopenharmony_ci							Vec4	c	= minVal + (maxVal-minVal)*f;
672e5c31af7Sopenharmony_ci							float*	v	= dst + (y*gridWidth + x)*numScalars;
673e5c31af7Sopenharmony_ci
674e5c31af7Sopenharmony_ci							for (int ndx = 0; ndx < numScalars; ndx++)
675e5c31af7Sopenharmony_ci								v[ndx] = c[ndx];
676e5c31af7Sopenharmony_ci						}
677e5c31af7Sopenharmony_ci					}
678e5c31af7Sopenharmony_ci				}
679e5c31af7Sopenharmony_ci				else if (isInt)
680e5c31af7Sopenharmony_ci				{
681e5c31af7Sopenharmony_ci					const IVec2	range	= getIntRange(output.precision);
682e5c31af7Sopenharmony_ci					IVec4		minVal	(range.x());
683e5c31af7Sopenharmony_ci					IVec4		maxVal	(range.y());
684e5c31af7Sopenharmony_ci
685e5c31af7Sopenharmony_ci					if (de::inBounds(output.location+vecNdx, 0, (int)attachments.size()))
686e5c31af7Sopenharmony_ci					{
687e5c31af7Sopenharmony_ci						// Limit to range of output format as conversion mode is not specified.
688e5c31af7Sopenharmony_ci						const IVec4 fmtBits		= tcu::getTextureFormatBitDepth(attachments[output.location+vecNdx].format);
689e5c31af7Sopenharmony_ci						const BVec4	isZero		= lessThanEqual(fmtBits, IVec4(0));
690e5c31af7Sopenharmony_ci						const IVec4	shift		= tcu::clamp(fmtBits-1, tcu::IVec4(0), tcu::IVec4(256));
691e5c31af7Sopenharmony_ci						const IVec4	fmtMinVal	= (-(tcu::Vector<deInt64, 4>(1) << shift.cast<deInt64>())).asInt();
692e5c31af7Sopenharmony_ci						const IVec4	fmtMaxVal	= ((tcu::Vector<deInt64, 4>(1) << shift.cast<deInt64>())-deInt64(1)).asInt();
693e5c31af7Sopenharmony_ci
694e5c31af7Sopenharmony_ci						minVal = select(minVal, tcu::max(minVal, fmtMinVal), isZero);
695e5c31af7Sopenharmony_ci						maxVal = select(maxVal, tcu::min(maxVal, fmtMaxVal), isZero);
696e5c31af7Sopenharmony_ci					}
697e5c31af7Sopenharmony_ci
698e5c31af7Sopenharmony_ci					m_testCtx.getLog() << TestLog::Message << "out" << curInVec << " value range: " << valueRangeToString(numScalars, minVal, maxVal) << TestLog::EndMessage;
699e5c31af7Sopenharmony_ci
700e5c31af7Sopenharmony_ci					const IVec4	rangeDiv	= swizzleVec((IVec4(gridWidth, gridHeight, gridWidth, gridHeight)-1), curInVec);
701e5c31af7Sopenharmony_ci					const IVec4	step		= ((maxVal.cast<deInt64>() - minVal.cast<deInt64>()) / (rangeDiv.cast<deInt64>())).asInt();
702e5c31af7Sopenharmony_ci					deInt32*	dst			= (deInt32*)&inputs[curInVec][0];
703e5c31af7Sopenharmony_ci
704e5c31af7Sopenharmony_ci					for (int y = 0; y < gridHeight; y++)
705e5c31af7Sopenharmony_ci					{
706e5c31af7Sopenharmony_ci						for (int x = 0; x < gridWidth; x++)
707e5c31af7Sopenharmony_ci						{
708e5c31af7Sopenharmony_ci							int			ix	= gridWidth - x - 1;
709e5c31af7Sopenharmony_ci							int			iy	= gridHeight - y - 1;
710e5c31af7Sopenharmony_ci							IVec4		c	= minVal + step*swizzleVec(IVec4(x, y, ix, iy), curInVec);
711e5c31af7Sopenharmony_ci							deInt32*	v	= dst + (y*gridWidth + x)*numScalars;
712e5c31af7Sopenharmony_ci
713e5c31af7Sopenharmony_ci							DE_ASSERT(boolAll(logicalAnd(greaterThanEqual(c, minVal), lessThanEqual(c, maxVal))));
714e5c31af7Sopenharmony_ci
715e5c31af7Sopenharmony_ci							for (int ndx = 0; ndx < numScalars; ndx++)
716e5c31af7Sopenharmony_ci								v[ndx] = c[ndx];
717e5c31af7Sopenharmony_ci						}
718e5c31af7Sopenharmony_ci					}
719e5c31af7Sopenharmony_ci				}
720e5c31af7Sopenharmony_ci				else if (isUint)
721e5c31af7Sopenharmony_ci				{
722e5c31af7Sopenharmony_ci					const UVec2	range	= getUintRange(output.precision);
723e5c31af7Sopenharmony_ci					UVec4		maxVal	(range.y());
724e5c31af7Sopenharmony_ci
725e5c31af7Sopenharmony_ci					if (de::inBounds(output.location+vecNdx, 0, (int)attachments.size()))
726e5c31af7Sopenharmony_ci					{
727e5c31af7Sopenharmony_ci						// Limit to range of output format as conversion mode is not specified.
728e5c31af7Sopenharmony_ci						const IVec4	fmtBits		= tcu::getTextureFormatBitDepth(attachments[output.location+vecNdx].format);
729e5c31af7Sopenharmony_ci						const UVec4	fmtMaxVal	= ((tcu::Vector<deUint64, 4>(1) << fmtBits.cast<deUint64>())-deUint64(1)).asUint();
730e5c31af7Sopenharmony_ci
731e5c31af7Sopenharmony_ci						maxVal = tcu::min(maxVal, fmtMaxVal);
732e5c31af7Sopenharmony_ci					}
733e5c31af7Sopenharmony_ci
734e5c31af7Sopenharmony_ci					m_testCtx.getLog() << TestLog::Message << "out" << curInVec << " value range: "  << valueRangeToString(numScalars, UVec4(0), maxVal) << TestLog::EndMessage;
735e5c31af7Sopenharmony_ci
736e5c31af7Sopenharmony_ci					const IVec4	rangeDiv	= swizzleVec((IVec4(gridWidth, gridHeight, gridWidth, gridHeight)-1), curInVec);
737e5c31af7Sopenharmony_ci					const UVec4	step		= maxVal / rangeDiv.asUint();
738e5c31af7Sopenharmony_ci					deUint32*	dst			= &inputs[curInVec][0];
739e5c31af7Sopenharmony_ci
740e5c31af7Sopenharmony_ci					DE_ASSERT(range.x() == 0);
741e5c31af7Sopenharmony_ci
742e5c31af7Sopenharmony_ci					for (int y = 0; y < gridHeight; y++)
743e5c31af7Sopenharmony_ci					{
744e5c31af7Sopenharmony_ci						for (int x = 0; x < gridWidth; x++)
745e5c31af7Sopenharmony_ci						{
746e5c31af7Sopenharmony_ci							int			ix	= gridWidth - x - 1;
747e5c31af7Sopenharmony_ci							int			iy	= gridHeight - y - 1;
748e5c31af7Sopenharmony_ci							UVec4		c	= step*swizzleVec(IVec4(x, y, ix, iy).asUint(), curInVec);
749e5c31af7Sopenharmony_ci							deUint32*	v	= dst + (y*gridWidth + x)*numScalars;
750e5c31af7Sopenharmony_ci
751e5c31af7Sopenharmony_ci							DE_ASSERT(boolAll(lessThanEqual(c, maxVal)));
752e5c31af7Sopenharmony_ci
753e5c31af7Sopenharmony_ci							for (int ndx = 0; ndx < numScalars; ndx++)
754e5c31af7Sopenharmony_ci								v[ndx] = c[ndx];
755e5c31af7Sopenharmony_ci						}
756e5c31af7Sopenharmony_ci					}
757e5c31af7Sopenharmony_ci				}
758e5c31af7Sopenharmony_ci				else
759e5c31af7Sopenharmony_ci					DE_ASSERT(false);
760e5c31af7Sopenharmony_ci
761e5c31af7Sopenharmony_ci				curInVec += 1;
762e5c31af7Sopenharmony_ci			}
763e5c31af7Sopenharmony_ci		}
764e5c31af7Sopenharmony_ci	}
765e5c31af7Sopenharmony_ci
766e5c31af7Sopenharmony_ci	// Render using gl.
767e5c31af7Sopenharmony_ci	gl.useProgram(m_program->getProgram());
768e5c31af7Sopenharmony_ci	gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
769e5c31af7Sopenharmony_ci	gl.viewport(0, 0, viewportW, viewportH);
770e5c31af7Sopenharmony_ci	gl.drawBuffers((int)drawBuffers.size(), &drawBuffers[0]);
771e5c31af7Sopenharmony_ci	gl.disable(GL_DITHER); // Dithering causes issues with unorm formats. Those issues could be worked around in threshold, but it makes validation less accurate.
772e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "After program setup");
773e5c31af7Sopenharmony_ci
774e5c31af7Sopenharmony_ci	{
775e5c31af7Sopenharmony_ci		int curInVec = 0;
776e5c31af7Sopenharmony_ci		for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++)
777e5c31af7Sopenharmony_ci		{
778e5c31af7Sopenharmony_ci			const FragmentOutput&	output			= m_outputs[outputNdx];
779e5c31af7Sopenharmony_ci			bool					isArray			= output.arrayLength > 0;
780e5c31af7Sopenharmony_ci			bool					isFloat			= glu::isDataTypeFloatOrVec(output.type);
781e5c31af7Sopenharmony_ci			bool					isInt			= glu::isDataTypeIntOrIVec(output.type);
782e5c31af7Sopenharmony_ci			bool					isUint			= glu::isDataTypeUintOrUVec(output.type);
783e5c31af7Sopenharmony_ci			int						scalarSize		= glu::getDataTypeScalarSize(output.type);
784e5c31af7Sopenharmony_ci			deUint32				glScalarType	= isFloat	? GL_FLOAT			:
785e5c31af7Sopenharmony_ci													  isInt		? GL_INT			:
786e5c31af7Sopenharmony_ci													  isUint	? GL_UNSIGNED_INT	: GL_NONE;
787e5c31af7Sopenharmony_ci			int						numVecs			= isArray ? output.arrayLength : 1;
788e5c31af7Sopenharmony_ci
789e5c31af7Sopenharmony_ci			for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
790e5c31af7Sopenharmony_ci			{
791e5c31af7Sopenharmony_ci				string	name	= string("in") + de::toString(outputNdx) + (isArray ? string("_") + de::toString(vecNdx) : string());
792e5c31af7Sopenharmony_ci				int		loc		= gl.getAttribLocation(m_program->getProgram(), name.c_str());
793e5c31af7Sopenharmony_ci
794e5c31af7Sopenharmony_ci				if (loc >= 0)
795e5c31af7Sopenharmony_ci				{
796e5c31af7Sopenharmony_ci					gl.enableVertexAttribArray(loc);
797e5c31af7Sopenharmony_ci					if (isFloat)
798e5c31af7Sopenharmony_ci						gl.vertexAttribPointer(loc, scalarSize, glScalarType, GL_FALSE, 0, &inputs[curInVec][0]);
799e5c31af7Sopenharmony_ci					else
800e5c31af7Sopenharmony_ci						gl.vertexAttribIPointer(loc, scalarSize, glScalarType, 0, &inputs[curInVec][0]);
801e5c31af7Sopenharmony_ci				}
802e5c31af7Sopenharmony_ci				else
803e5c31af7Sopenharmony_ci					log << TestLog::Message << "Warning: No location for attribute '" << name << "' found." << TestLog::EndMessage;
804e5c31af7Sopenharmony_ci
805e5c31af7Sopenharmony_ci				curInVec += 1;
806e5c31af7Sopenharmony_ci			}
807e5c31af7Sopenharmony_ci		}
808e5c31af7Sopenharmony_ci	}
809e5c31af7Sopenharmony_ci	{
810e5c31af7Sopenharmony_ci		int posLoc = gl.getAttribLocation(m_program->getProgram(), "a_position");
811e5c31af7Sopenharmony_ci		TCU_CHECK(posLoc >= 0);
812e5c31af7Sopenharmony_ci		gl.enableVertexAttribArray(posLoc);
813e5c31af7Sopenharmony_ci		gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &positions[0]);
814e5c31af7Sopenharmony_ci	}
815e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "After attribute setup");
816e5c31af7Sopenharmony_ci
817e5c31af7Sopenharmony_ci	gl.drawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, &indices[0]);
818e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElements");
819e5c31af7Sopenharmony_ci
820e5c31af7Sopenharmony_ci	// Read all attachment points.
821e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < numAttachments; ndx++)
822e5c31af7Sopenharmony_ci	{
823e5c31af7Sopenharmony_ci		const glu::TransferFormat		transferFmt			= glu::getTransferFormat(attachments[ndx].readFormat);
824e5c31af7Sopenharmony_ci		void*							dst					= &attachments[ndx].renderedData[0];
825e5c31af7Sopenharmony_ci		const int						attachmentW			= m_fboSpec[ndx].width;
826e5c31af7Sopenharmony_ci		const int						attachmentH			= m_fboSpec[ndx].height;
827e5c31af7Sopenharmony_ci		const int						numValidChannels	= attachments[ndx].numWrittenChannels;
828e5c31af7Sopenharmony_ci		const tcu::PixelBufferAccess	rendered			(attachments[ndx].readFormat, attachmentW, attachmentH, 1, deAlign32(attachments[ndx].readFormat.getPixelSize()*attachmentW, readAlignment), 0, &attachments[ndx].renderedData[0]);
829e5c31af7Sopenharmony_ci
830e5c31af7Sopenharmony_ci		gl.readBuffer(GL_COLOR_ATTACHMENT0+ndx);
831e5c31af7Sopenharmony_ci		gl.readPixels(0, 0, minBufSize.x(), minBufSize.y(), transferFmt.format, transferFmt.dataType, dst);
832e5c31af7Sopenharmony_ci
833e5c31af7Sopenharmony_ci		clearUndefined(rendered, numValidChannels);
834e5c31af7Sopenharmony_ci	}
835e5c31af7Sopenharmony_ci
836e5c31af7Sopenharmony_ci	// Render reference images.
837e5c31af7Sopenharmony_ci	{
838e5c31af7Sopenharmony_ci		int curInNdx = 0;
839e5c31af7Sopenharmony_ci		for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++)
840e5c31af7Sopenharmony_ci		{
841e5c31af7Sopenharmony_ci			const FragmentOutput&	output			= m_outputs[outputNdx];
842e5c31af7Sopenharmony_ci			const bool				isArray			= output.arrayLength > 0;
843e5c31af7Sopenharmony_ci			const bool				isFloat			= glu::isDataTypeFloatOrVec(output.type);
844e5c31af7Sopenharmony_ci			const bool				isInt			= glu::isDataTypeIntOrIVec(output.type);
845e5c31af7Sopenharmony_ci			const bool				isUint			= glu::isDataTypeUintOrUVec(output.type);
846e5c31af7Sopenharmony_ci			const int				scalarSize		= glu::getDataTypeScalarSize(output.type);
847e5c31af7Sopenharmony_ci			const int				numVecs			= isArray ? output.arrayLength : 1;
848e5c31af7Sopenharmony_ci
849e5c31af7Sopenharmony_ci			for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
850e5c31af7Sopenharmony_ci			{
851e5c31af7Sopenharmony_ci				const int		location	= output.location+vecNdx;
852e5c31af7Sopenharmony_ci				const void*		inputData	= &inputs[curInNdx][0];
853e5c31af7Sopenharmony_ci
854e5c31af7Sopenharmony_ci				DE_ASSERT(de::inBounds(location, 0, (int)m_fboSpec.size()));
855e5c31af7Sopenharmony_ci
856e5c31af7Sopenharmony_ci				const int						bufW			= m_fboSpec[location].width;
857e5c31af7Sopenharmony_ci				const int						bufH			= m_fboSpec[location].height;
858e5c31af7Sopenharmony_ci				const tcu::PixelBufferAccess	buf				(attachments[location].referenceFormat, bufW, bufH, 1, &attachments[location].referenceData[0]);
859e5c31af7Sopenharmony_ci				const tcu::PixelBufferAccess	viewportBuf		= getSubregion(buf, 0, 0, 0, viewportW, viewportH, 1);
860e5c31af7Sopenharmony_ci
861e5c31af7Sopenharmony_ci				if (isInt || isUint)
862e5c31af7Sopenharmony_ci					renderIntReference(viewportBuf, gridWidth, gridHeight, scalarSize, (const int*)inputData);
863e5c31af7Sopenharmony_ci				else if (isFloat)
864e5c31af7Sopenharmony_ci					renderFloatReference(viewportBuf, gridWidth, gridHeight, scalarSize, (const float*)inputData);
865e5c31af7Sopenharmony_ci				else
866e5c31af7Sopenharmony_ci					DE_ASSERT(false);
867e5c31af7Sopenharmony_ci
868e5c31af7Sopenharmony_ci				curInNdx += 1;
869e5c31af7Sopenharmony_ci			}
870e5c31af7Sopenharmony_ci		}
871e5c31af7Sopenharmony_ci	}
872e5c31af7Sopenharmony_ci
873e5c31af7Sopenharmony_ci	// Compare all images.
874e5c31af7Sopenharmony_ci	bool allLevelsOk = true;
875e5c31af7Sopenharmony_ci	for (int attachNdx = 0; attachNdx < numAttachments; attachNdx++)
876e5c31af7Sopenharmony_ci	{
877e5c31af7Sopenharmony_ci		const int						attachmentW			= m_fboSpec[attachNdx].width;
878e5c31af7Sopenharmony_ci		const int						attachmentH			= m_fboSpec[attachNdx].height;
879e5c31af7Sopenharmony_ci		const int						numValidChannels	= attachments[attachNdx].numWrittenChannels;
880e5c31af7Sopenharmony_ci		const tcu::BVec4				cmpMask				(numValidChannels >= 1, numValidChannels >= 2, numValidChannels >= 3, numValidChannels >= 4);
881e5c31af7Sopenharmony_ci		const glu::Precision			outPrecision		= attachments[attachNdx].outPrecision;
882e5c31af7Sopenharmony_ci		const tcu::TextureFormat&		format				= attachments[attachNdx].format;
883e5c31af7Sopenharmony_ci		tcu::ConstPixelBufferAccess		rendered			(attachments[attachNdx].readFormat, attachmentW, attachmentH, 1, deAlign32(attachments[attachNdx].readFormat.getPixelSize()*attachmentW, readAlignment), 0, &attachments[attachNdx].renderedData[0]);
884e5c31af7Sopenharmony_ci		tcu::ConstPixelBufferAccess		reference			(attachments[attachNdx].referenceFormat, attachmentW, attachmentH, 1, &attachments[attachNdx].referenceData[0]);
885e5c31af7Sopenharmony_ci		tcu::TextureChannelClass		texClass			= tcu::getTextureChannelClass(format.type);
886e5c31af7Sopenharmony_ci		bool							isOk				= true;
887e5c31af7Sopenharmony_ci		const string					name				= string("Attachment") + de::toString(attachNdx);
888e5c31af7Sopenharmony_ci		const string					desc				= string("Color attachment ") + de::toString(attachNdx);
889e5c31af7Sopenharmony_ci
890e5c31af7Sopenharmony_ci		log << TestLog::Message << "Attachment " << attachNdx << ": " << numValidChannels << " channels have defined values and used for comparison" << TestLog::EndMessage;
891e5c31af7Sopenharmony_ci
892e5c31af7Sopenharmony_ci		switch (texClass)
893e5c31af7Sopenharmony_ci		{
894e5c31af7Sopenharmony_ci			case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
895e5c31af7Sopenharmony_ci			{
896e5c31af7Sopenharmony_ci				const deUint32	interpThreshold		= 4;	//!< 4 ULP interpolation threshold (interpolation always in highp)
897e5c31af7Sopenharmony_ci				deUint32		outTypeThreshold	= 0;	//!< Threshold based on output type
898e5c31af7Sopenharmony_ci				UVec4			formatThreshold;			//!< Threshold computed based on format.
899e5c31af7Sopenharmony_ci				UVec4			finalThreshold;
900e5c31af7Sopenharmony_ci
901e5c31af7Sopenharmony_ci				// 1 ULP rounding error is allowed for smaller floating-point formats
902e5c31af7Sopenharmony_ci				switch (format.type)
903e5c31af7Sopenharmony_ci				{
904e5c31af7Sopenharmony_ci					case tcu::TextureFormat::FLOAT:							formatThreshold = UVec4(0);											break;
905e5c31af7Sopenharmony_ci					case tcu::TextureFormat::HALF_FLOAT:					formatThreshold = UVec4((1<<(23-10)));								break;
906e5c31af7Sopenharmony_ci					case tcu::TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	formatThreshold = UVec4((1<<(23-6)), (1<<(23-6)), (1<<(23-5)), 0);	break;
907e5c31af7Sopenharmony_ci					default:
908e5c31af7Sopenharmony_ci						DE_ASSERT(false);
909e5c31af7Sopenharmony_ci						break;
910e5c31af7Sopenharmony_ci				}
911e5c31af7Sopenharmony_ci
912e5c31af7Sopenharmony_ci				// 1 ULP rounding error for highp -> output precision cast
913e5c31af7Sopenharmony_ci				switch (outPrecision)
914e5c31af7Sopenharmony_ci				{
915e5c31af7Sopenharmony_ci					case glu::PRECISION_LOWP:		outTypeThreshold	= (1<<(23-8));	break;
916e5c31af7Sopenharmony_ci					case glu::PRECISION_MEDIUMP:	outTypeThreshold	= (1<<(23-10));	break;
917e5c31af7Sopenharmony_ci					case glu::PRECISION_HIGHP:		outTypeThreshold	= 0;			break;
918e5c31af7Sopenharmony_ci					default:
919e5c31af7Sopenharmony_ci						DE_ASSERT(false);
920e5c31af7Sopenharmony_ci				}
921e5c31af7Sopenharmony_ci
922e5c31af7Sopenharmony_ci				finalThreshold = select(max(formatThreshold, UVec4(deMax32(interpThreshold, outTypeThreshold))), UVec4(~0u), cmpMask);
923e5c31af7Sopenharmony_ci
924e5c31af7Sopenharmony_ci				isOk = tcu::floatUlpThresholdCompare(log, name.c_str(), desc.c_str(), reference, rendered, finalThreshold, tcu::COMPARE_LOG_RESULT);
925e5c31af7Sopenharmony_ci				break;
926e5c31af7Sopenharmony_ci			}
927e5c31af7Sopenharmony_ci
928e5c31af7Sopenharmony_ci			case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
929e5c31af7Sopenharmony_ci			{
930e5c31af7Sopenharmony_ci				// \note glReadPixels() allows only 8 bits to be read. This means that RGB10_A2 will loose some
931e5c31af7Sopenharmony_ci				// bits in the process and it must be taken into account when computing threshold.
932e5c31af7Sopenharmony_ci				const IVec4		bits			= min(IVec4(8), tcu::getTextureFormatBitDepth(format));
933e5c31af7Sopenharmony_ci				const Vec4		baseThreshold	= 1.0f / ((IVec4(1) << bits)-1).asFloat();
934e5c31af7Sopenharmony_ci				const Vec4		threshold		= select(baseThreshold, Vec4(2.0f), cmpMask);
935e5c31af7Sopenharmony_ci
936e5c31af7Sopenharmony_ci				isOk = tcu::floatThresholdCompare(log, name.c_str(), desc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
937e5c31af7Sopenharmony_ci				break;
938e5c31af7Sopenharmony_ci			}
939e5c31af7Sopenharmony_ci
940e5c31af7Sopenharmony_ci			case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
941e5c31af7Sopenharmony_ci			case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
942e5c31af7Sopenharmony_ci			{
943e5c31af7Sopenharmony_ci				const tcu::UVec4 threshold = select(UVec4(0u), UVec4(~0u), cmpMask);
944e5c31af7Sopenharmony_ci				isOk = tcu::intThresholdCompare(log, name.c_str(), desc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
945e5c31af7Sopenharmony_ci				break;
946e5c31af7Sopenharmony_ci			}
947e5c31af7Sopenharmony_ci
948e5c31af7Sopenharmony_ci			default:
949e5c31af7Sopenharmony_ci				TCU_FAIL("Unsupported comparison");
950e5c31af7Sopenharmony_ci		}
951e5c31af7Sopenharmony_ci
952e5c31af7Sopenharmony_ci		if (!isOk)
953e5c31af7Sopenharmony_ci			allLevelsOk = false;
954e5c31af7Sopenharmony_ci	}
955e5c31af7Sopenharmony_ci
956e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(allLevelsOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
957e5c31af7Sopenharmony_ci							allLevelsOk ? "Pass"				: "Image comparison failed");
958e5c31af7Sopenharmony_ci	return STOP;
959e5c31af7Sopenharmony_ci}
960e5c31af7Sopenharmony_ci
961e5c31af7Sopenharmony_ciFragmentOutputTests::FragmentOutputTests (Context& context)
962e5c31af7Sopenharmony_ci	: TestCaseGroup(context, "fragment_out", "Fragment output tests")
963e5c31af7Sopenharmony_ci{
964e5c31af7Sopenharmony_ci}
965e5c31af7Sopenharmony_ci
966e5c31af7Sopenharmony_ciFragmentOutputTests::~FragmentOutputTests (void)
967e5c31af7Sopenharmony_ci{
968e5c31af7Sopenharmony_ci}
969e5c31af7Sopenharmony_ci
970e5c31af7Sopenharmony_cistatic FragmentOutputCase* createRandomCase (Context& context, int minRenderTargets, int maxRenderTargets, deUint32 seed)
971e5c31af7Sopenharmony_ci{
972e5c31af7Sopenharmony_ci	static const glu::DataType outputTypes[] =
973e5c31af7Sopenharmony_ci	{
974e5c31af7Sopenharmony_ci		glu::TYPE_FLOAT,
975e5c31af7Sopenharmony_ci		glu::TYPE_FLOAT_VEC2,
976e5c31af7Sopenharmony_ci		glu::TYPE_FLOAT_VEC3,
977e5c31af7Sopenharmony_ci		glu::TYPE_FLOAT_VEC4,
978e5c31af7Sopenharmony_ci		glu::TYPE_INT,
979e5c31af7Sopenharmony_ci		glu::TYPE_INT_VEC2,
980e5c31af7Sopenharmony_ci		glu::TYPE_INT_VEC3,
981e5c31af7Sopenharmony_ci		glu::TYPE_INT_VEC4,
982e5c31af7Sopenharmony_ci		glu::TYPE_UINT,
983e5c31af7Sopenharmony_ci		glu::TYPE_UINT_VEC2,
984e5c31af7Sopenharmony_ci		glu::TYPE_UINT_VEC3,
985e5c31af7Sopenharmony_ci		glu::TYPE_UINT_VEC4
986e5c31af7Sopenharmony_ci	};
987e5c31af7Sopenharmony_ci	static const glu::Precision precisions[] =
988e5c31af7Sopenharmony_ci	{
989e5c31af7Sopenharmony_ci		glu::PRECISION_LOWP,
990e5c31af7Sopenharmony_ci		glu::PRECISION_MEDIUMP,
991e5c31af7Sopenharmony_ci		glu::PRECISION_HIGHP
992e5c31af7Sopenharmony_ci	};
993e5c31af7Sopenharmony_ci	static const deUint32 floatFormats[] =
994e5c31af7Sopenharmony_ci	{
995e5c31af7Sopenharmony_ci		GL_RGBA32F,
996e5c31af7Sopenharmony_ci		GL_RGBA16F,
997e5c31af7Sopenharmony_ci		GL_R11F_G11F_B10F,
998e5c31af7Sopenharmony_ci		GL_RG32F,
999e5c31af7Sopenharmony_ci		GL_RG16F,
1000e5c31af7Sopenharmony_ci		GL_R32F,
1001e5c31af7Sopenharmony_ci		GL_R16F,
1002e5c31af7Sopenharmony_ci		GL_RGBA8,
1003e5c31af7Sopenharmony_ci		GL_SRGB8_ALPHA8,
1004e5c31af7Sopenharmony_ci		GL_RGB10_A2,
1005e5c31af7Sopenharmony_ci		GL_RGBA4,
1006e5c31af7Sopenharmony_ci		GL_RGB5_A1,
1007e5c31af7Sopenharmony_ci		GL_RGB8,
1008e5c31af7Sopenharmony_ci		GL_RGB565,
1009e5c31af7Sopenharmony_ci		GL_RG8,
1010e5c31af7Sopenharmony_ci		GL_R8
1011e5c31af7Sopenharmony_ci	};
1012e5c31af7Sopenharmony_ci	static const deUint32 intFormats[] =
1013e5c31af7Sopenharmony_ci	{
1014e5c31af7Sopenharmony_ci		GL_RGBA32I,
1015e5c31af7Sopenharmony_ci		GL_RGBA16I,
1016e5c31af7Sopenharmony_ci		GL_RGBA8I,
1017e5c31af7Sopenharmony_ci		GL_RG32I,
1018e5c31af7Sopenharmony_ci		GL_RG16I,
1019e5c31af7Sopenharmony_ci		GL_RG8I,
1020e5c31af7Sopenharmony_ci		GL_R32I,
1021e5c31af7Sopenharmony_ci		GL_R16I,
1022e5c31af7Sopenharmony_ci		GL_R8I
1023e5c31af7Sopenharmony_ci	};
1024e5c31af7Sopenharmony_ci	static const deUint32 uintFormats[] =
1025e5c31af7Sopenharmony_ci	{
1026e5c31af7Sopenharmony_ci		GL_RGBA32UI,
1027e5c31af7Sopenharmony_ci		GL_RGBA16UI,
1028e5c31af7Sopenharmony_ci		GL_RGBA8UI,
1029e5c31af7Sopenharmony_ci		GL_RGB10_A2UI,
1030e5c31af7Sopenharmony_ci		GL_RG32UI,
1031e5c31af7Sopenharmony_ci		GL_RG16UI,
1032e5c31af7Sopenharmony_ci		GL_RG8UI,
1033e5c31af7Sopenharmony_ci		GL_R32UI,
1034e5c31af7Sopenharmony_ci		GL_R16UI,
1035e5c31af7Sopenharmony_ci		GL_R8UI
1036e5c31af7Sopenharmony_ci	};
1037e5c31af7Sopenharmony_ci
1038e5c31af7Sopenharmony_ci	de::Random					rnd			(seed);
1039e5c31af7Sopenharmony_ci	vector<FragmentOutput>		outputs;
1040e5c31af7Sopenharmony_ci	vector<BufferSpec>			targets;
1041e5c31af7Sopenharmony_ci	vector<glu::DataType>		outTypes;
1042e5c31af7Sopenharmony_ci
1043e5c31af7Sopenharmony_ci	int							numTargets	= rnd.getInt(minRenderTargets, maxRenderTargets);
1044e5c31af7Sopenharmony_ci	const int					width		= 128; // \todo [2012-04-10 pyry] Separate randomized sizes per target?
1045e5c31af7Sopenharmony_ci	const int					height		= 64;
1046e5c31af7Sopenharmony_ci	const int					samples		= 0;
1047e5c31af7Sopenharmony_ci
1048e5c31af7Sopenharmony_ci	// Compute outputs.
1049e5c31af7Sopenharmony_ci	int curLoc = 0;
1050e5c31af7Sopenharmony_ci	while (curLoc < numTargets)
1051e5c31af7Sopenharmony_ci	{
1052e5c31af7Sopenharmony_ci		bool			useArray		= rnd.getFloat() < 0.3f;
1053e5c31af7Sopenharmony_ci		int				maxArrayLen		= numTargets-curLoc;
1054e5c31af7Sopenharmony_ci		int				arrayLen		= useArray ? rnd.getInt(1, maxArrayLen) : 0;
1055e5c31af7Sopenharmony_ci		glu::DataType	basicType		= rnd.choose<glu::DataType>(&outputTypes[0], &outputTypes[0] + DE_LENGTH_OF_ARRAY(outputTypes));
1056e5c31af7Sopenharmony_ci		glu::Precision	precision		= rnd.choose<glu::Precision>(&precisions[0], &precisions[0] + DE_LENGTH_OF_ARRAY(precisions));
1057e5c31af7Sopenharmony_ci		int				numLocations	= useArray ? arrayLen : 1;
1058e5c31af7Sopenharmony_ci
1059e5c31af7Sopenharmony_ci		outputs.push_back(FragmentOutput(basicType, precision, curLoc, arrayLen));
1060e5c31af7Sopenharmony_ci
1061e5c31af7Sopenharmony_ci		for (int ndx = 0; ndx < numLocations; ndx++)
1062e5c31af7Sopenharmony_ci			outTypes.push_back(basicType);
1063e5c31af7Sopenharmony_ci
1064e5c31af7Sopenharmony_ci		curLoc += numLocations;
1065e5c31af7Sopenharmony_ci	}
1066e5c31af7Sopenharmony_ci	DE_ASSERT(curLoc == numTargets);
1067e5c31af7Sopenharmony_ci	DE_ASSERT((int)outTypes.size() == numTargets);
1068e5c31af7Sopenharmony_ci
1069e5c31af7Sopenharmony_ci	// Compute buffers.
1070e5c31af7Sopenharmony_ci	while ((int)targets.size() < numTargets)
1071e5c31af7Sopenharmony_ci	{
1072e5c31af7Sopenharmony_ci		glu::DataType	outType		= outTypes[targets.size()];
1073e5c31af7Sopenharmony_ci		bool			isFloat		= glu::isDataTypeFloatOrVec(outType);
1074e5c31af7Sopenharmony_ci		bool			isInt		= glu::isDataTypeIntOrIVec(outType);
1075e5c31af7Sopenharmony_ci		bool			isUint		= glu::isDataTypeUintOrUVec(outType);
1076e5c31af7Sopenharmony_ci		deUint32		format		= 0;
1077e5c31af7Sopenharmony_ci
1078e5c31af7Sopenharmony_ci		if (isFloat)
1079e5c31af7Sopenharmony_ci			format = rnd.choose<deUint32>(&floatFormats[0], &floatFormats[0] + DE_LENGTH_OF_ARRAY(floatFormats));
1080e5c31af7Sopenharmony_ci		else if (isInt)
1081e5c31af7Sopenharmony_ci			format = rnd.choose<deUint32>(&intFormats[0], &intFormats[0] + DE_LENGTH_OF_ARRAY(intFormats));
1082e5c31af7Sopenharmony_ci		else if (isUint)
1083e5c31af7Sopenharmony_ci			format = rnd.choose<deUint32>(&uintFormats[0], &uintFormats[0] + DE_LENGTH_OF_ARRAY(uintFormats));
1084e5c31af7Sopenharmony_ci		else
1085e5c31af7Sopenharmony_ci			DE_ASSERT(false);
1086e5c31af7Sopenharmony_ci
1087e5c31af7Sopenharmony_ci		targets.push_back(BufferSpec(format, width, height, samples));
1088e5c31af7Sopenharmony_ci	}
1089e5c31af7Sopenharmony_ci
1090e5c31af7Sopenharmony_ci	return new FragmentOutputCase(context, de::toString(seed).c_str(), "", targets, outputs);
1091e5c31af7Sopenharmony_ci}
1092e5c31af7Sopenharmony_ci
1093e5c31af7Sopenharmony_civoid FragmentOutputTests::init (void)
1094e5c31af7Sopenharmony_ci{
1095e5c31af7Sopenharmony_ci	static const deUint32 requiredFloatFormats[] =
1096e5c31af7Sopenharmony_ci	{
1097e5c31af7Sopenharmony_ci		GL_RGBA32F,
1098e5c31af7Sopenharmony_ci		GL_RGBA16F,
1099e5c31af7Sopenharmony_ci		GL_R11F_G11F_B10F,
1100e5c31af7Sopenharmony_ci		GL_RG32F,
1101e5c31af7Sopenharmony_ci		GL_RG16F,
1102e5c31af7Sopenharmony_ci		GL_R32F,
1103e5c31af7Sopenharmony_ci		GL_R16F
1104e5c31af7Sopenharmony_ci	};
1105e5c31af7Sopenharmony_ci	static const deUint32 requiredFixedFormats[] =
1106e5c31af7Sopenharmony_ci	{
1107e5c31af7Sopenharmony_ci		GL_RGBA8,
1108e5c31af7Sopenharmony_ci		GL_SRGB8_ALPHA8,
1109e5c31af7Sopenharmony_ci		GL_RGB10_A2,
1110e5c31af7Sopenharmony_ci		GL_RGBA4,
1111e5c31af7Sopenharmony_ci		GL_RGB5_A1,
1112e5c31af7Sopenharmony_ci		GL_RGB8,
1113e5c31af7Sopenharmony_ci		GL_RGB565,
1114e5c31af7Sopenharmony_ci		GL_RG8,
1115e5c31af7Sopenharmony_ci		GL_R8
1116e5c31af7Sopenharmony_ci	};
1117e5c31af7Sopenharmony_ci	static const deUint32 requiredIntFormats[] =
1118e5c31af7Sopenharmony_ci	{
1119e5c31af7Sopenharmony_ci		GL_RGBA32I,
1120e5c31af7Sopenharmony_ci		GL_RGBA16I,
1121e5c31af7Sopenharmony_ci		GL_RGBA8I,
1122e5c31af7Sopenharmony_ci		GL_RG32I,
1123e5c31af7Sopenharmony_ci		GL_RG16I,
1124e5c31af7Sopenharmony_ci		GL_RG8I,
1125e5c31af7Sopenharmony_ci		GL_R32I,
1126e5c31af7Sopenharmony_ci		GL_R16I,
1127e5c31af7Sopenharmony_ci		GL_R8I
1128e5c31af7Sopenharmony_ci	};
1129e5c31af7Sopenharmony_ci	static const deUint32 requiredUintFormats[] =
1130e5c31af7Sopenharmony_ci	{
1131e5c31af7Sopenharmony_ci		GL_RGBA32UI,
1132e5c31af7Sopenharmony_ci		GL_RGBA16UI,
1133e5c31af7Sopenharmony_ci		GL_RGBA8UI,
1134e5c31af7Sopenharmony_ci		GL_RGB10_A2UI,
1135e5c31af7Sopenharmony_ci		GL_RG32UI,
1136e5c31af7Sopenharmony_ci		GL_RG16UI,
1137e5c31af7Sopenharmony_ci		GL_RG8UI,
1138e5c31af7Sopenharmony_ci		GL_R32UI,
1139e5c31af7Sopenharmony_ci		GL_R16UI,
1140e5c31af7Sopenharmony_ci		GL_R8UI
1141e5c31af7Sopenharmony_ci	};
1142e5c31af7Sopenharmony_ci
1143e5c31af7Sopenharmony_ci	static const glu::Precision precisions[] =
1144e5c31af7Sopenharmony_ci	{
1145e5c31af7Sopenharmony_ci		glu::PRECISION_LOWP,
1146e5c31af7Sopenharmony_ci		glu::PRECISION_MEDIUMP,
1147e5c31af7Sopenharmony_ci		glu::PRECISION_HIGHP
1148e5c31af7Sopenharmony_ci	};
1149e5c31af7Sopenharmony_ci
1150e5c31af7Sopenharmony_ci	// .basic.
1151e5c31af7Sopenharmony_ci	{
1152e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic fragment output tests");
1153e5c31af7Sopenharmony_ci		addChild(basicGroup);
1154e5c31af7Sopenharmony_ci
1155e5c31af7Sopenharmony_ci		const int	width	= 64;
1156e5c31af7Sopenharmony_ci		const int	height	= 64;
1157e5c31af7Sopenharmony_ci		const int	samples	= 0;
1158e5c31af7Sopenharmony_ci
1159e5c31af7Sopenharmony_ci		// .float
1160e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* floatGroup = new tcu::TestCaseGroup(m_testCtx, "float", "Floating-point output tests");
1161e5c31af7Sopenharmony_ci		basicGroup->addChild(floatGroup);
1162e5c31af7Sopenharmony_ci		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFloatFormats); fmtNdx++)
1163e5c31af7Sopenharmony_ci		{
1164e5c31af7Sopenharmony_ci			deUint32			format		= requiredFloatFormats[fmtNdx];
1165e5c31af7Sopenharmony_ci			string				fmtName		= getFormatName(format);
1166e5c31af7Sopenharmony_ci			vector<BufferSpec>	fboSpec;
1167e5c31af7Sopenharmony_ci
1168e5c31af7Sopenharmony_ci			fboSpec.push_back(BufferSpec(format, width, height, samples));
1169e5c31af7Sopenharmony_ci
1170e5c31af7Sopenharmony_ci			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1171e5c31af7Sopenharmony_ci			{
1172e5c31af7Sopenharmony_ci				glu::Precision	prec		= precisions[precNdx];
1173e5c31af7Sopenharmony_ci				string			precName	= glu::getPrecisionName(prec);
1174e5c31af7Sopenharmony_ci
1175e5c31af7Sopenharmony_ci				floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT,		prec, 0)).toVec()));
1176e5c31af7Sopenharmony_ci				floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2,	prec, 0)).toVec()));
1177e5c31af7Sopenharmony_ci				floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3,	prec, 0)).toVec()));
1178e5c31af7Sopenharmony_ci				floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4,	prec, 0)).toVec()));
1179e5c31af7Sopenharmony_ci			}
1180e5c31af7Sopenharmony_ci		}
1181e5c31af7Sopenharmony_ci
1182e5c31af7Sopenharmony_ci		// .fixed
1183e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* fixedGroup = new tcu::TestCaseGroup(m_testCtx, "fixed", "Fixed-point output tests");
1184e5c31af7Sopenharmony_ci		basicGroup->addChild(fixedGroup);
1185e5c31af7Sopenharmony_ci		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFixedFormats); fmtNdx++)
1186e5c31af7Sopenharmony_ci		{
1187e5c31af7Sopenharmony_ci			deUint32			format		= requiredFixedFormats[fmtNdx];
1188e5c31af7Sopenharmony_ci			string				fmtName		= getFormatName(format);
1189e5c31af7Sopenharmony_ci			vector<BufferSpec>	fboSpec;
1190e5c31af7Sopenharmony_ci
1191e5c31af7Sopenharmony_ci			fboSpec.push_back(BufferSpec(format, width, height, samples));
1192e5c31af7Sopenharmony_ci
1193e5c31af7Sopenharmony_ci			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1194e5c31af7Sopenharmony_ci			{
1195e5c31af7Sopenharmony_ci				glu::Precision	prec		= precisions[precNdx];
1196e5c31af7Sopenharmony_ci				string			precName	= glu::getPrecisionName(prec);
1197e5c31af7Sopenharmony_ci
1198e5c31af7Sopenharmony_ci				fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT,		prec, 0)).toVec()));
1199e5c31af7Sopenharmony_ci				fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2,	prec, 0)).toVec()));
1200e5c31af7Sopenharmony_ci				fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3,	prec, 0)).toVec()));
1201e5c31af7Sopenharmony_ci				fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4,	prec, 0)).toVec()));
1202e5c31af7Sopenharmony_ci			}
1203e5c31af7Sopenharmony_ci		}
1204e5c31af7Sopenharmony_ci
1205e5c31af7Sopenharmony_ci		// .int
1206e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "int", "Integer output tests");
1207e5c31af7Sopenharmony_ci		basicGroup->addChild(intGroup);
1208e5c31af7Sopenharmony_ci		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredIntFormats); fmtNdx++)
1209e5c31af7Sopenharmony_ci		{
1210e5c31af7Sopenharmony_ci			deUint32			format		= requiredIntFormats[fmtNdx];
1211e5c31af7Sopenharmony_ci			string				fmtName		= getFormatName(format);
1212e5c31af7Sopenharmony_ci			vector<BufferSpec>	fboSpec;
1213e5c31af7Sopenharmony_ci
1214e5c31af7Sopenharmony_ci			fboSpec.push_back(BufferSpec(format, width, height, samples));
1215e5c31af7Sopenharmony_ci
1216e5c31af7Sopenharmony_ci			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1217e5c31af7Sopenharmony_ci			{
1218e5c31af7Sopenharmony_ci				glu::Precision	prec		= precisions[precNdx];
1219e5c31af7Sopenharmony_ci				string			precName	= glu::getPrecisionName(prec);
1220e5c31af7Sopenharmony_ci
1221e5c31af7Sopenharmony_ci				intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_int").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT,		prec, 0)).toVec()));
1222e5c31af7Sopenharmony_ci				intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec2").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC2,	prec, 0)).toVec()));
1223e5c31af7Sopenharmony_ci				intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec3").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC3,	prec, 0)).toVec()));
1224e5c31af7Sopenharmony_ci				intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec4").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC4,	prec, 0)).toVec()));
1225e5c31af7Sopenharmony_ci			}
1226e5c31af7Sopenharmony_ci		}
1227e5c31af7Sopenharmony_ci
1228e5c31af7Sopenharmony_ci		// .uint
1229e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uint", "Usigned integer output tests");
1230e5c31af7Sopenharmony_ci		basicGroup->addChild(uintGroup);
1231e5c31af7Sopenharmony_ci		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredUintFormats); fmtNdx++)
1232e5c31af7Sopenharmony_ci		{
1233e5c31af7Sopenharmony_ci			deUint32			format		= requiredUintFormats[fmtNdx];
1234e5c31af7Sopenharmony_ci			string				fmtName		= getFormatName(format);
1235e5c31af7Sopenharmony_ci			vector<BufferSpec>	fboSpec;
1236e5c31af7Sopenharmony_ci
1237e5c31af7Sopenharmony_ci			fboSpec.push_back(BufferSpec(format, width, height, samples));
1238e5c31af7Sopenharmony_ci
1239e5c31af7Sopenharmony_ci			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1240e5c31af7Sopenharmony_ci			{
1241e5c31af7Sopenharmony_ci				glu::Precision	prec		= precisions[precNdx];
1242e5c31af7Sopenharmony_ci				string			precName	= glu::getPrecisionName(prec);
1243e5c31af7Sopenharmony_ci
1244e5c31af7Sopenharmony_ci				uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uint").c_str(),		"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT,			prec, 0)).toVec()));
1245e5c31af7Sopenharmony_ci				uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec2").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC2,	prec, 0)).toVec()));
1246e5c31af7Sopenharmony_ci				uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec3").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC3,	prec, 0)).toVec()));
1247e5c31af7Sopenharmony_ci				uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec4").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC4,	prec, 0)).toVec()));
1248e5c31af7Sopenharmony_ci			}
1249e5c31af7Sopenharmony_ci		}
1250e5c31af7Sopenharmony_ci	}
1251e5c31af7Sopenharmony_ci
1252e5c31af7Sopenharmony_ci	// .array
1253e5c31af7Sopenharmony_ci	{
1254e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* arrayGroup = new tcu::TestCaseGroup(m_testCtx, "array", "Array outputs");
1255e5c31af7Sopenharmony_ci		addChild(arrayGroup);
1256e5c31af7Sopenharmony_ci
1257e5c31af7Sopenharmony_ci		const int	width		= 64;
1258e5c31af7Sopenharmony_ci		const int	height		= 64;
1259e5c31af7Sopenharmony_ci		const int	samples		= 0;
1260e5c31af7Sopenharmony_ci		const int	numTargets	= 3;
1261e5c31af7Sopenharmony_ci
1262e5c31af7Sopenharmony_ci		// .float
1263e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* floatGroup = new tcu::TestCaseGroup(m_testCtx, "float", "Floating-point output tests");
1264e5c31af7Sopenharmony_ci		arrayGroup->addChild(floatGroup);
1265e5c31af7Sopenharmony_ci		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFloatFormats); fmtNdx++)
1266e5c31af7Sopenharmony_ci		{
1267e5c31af7Sopenharmony_ci			deUint32			format		= requiredFloatFormats[fmtNdx];
1268e5c31af7Sopenharmony_ci			string				fmtName		= getFormatName(format);
1269e5c31af7Sopenharmony_ci			vector<BufferSpec>	fboSpec;
1270e5c31af7Sopenharmony_ci
1271e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numTargets; ndx++)
1272e5c31af7Sopenharmony_ci				fboSpec.push_back(BufferSpec(format, width, height, samples));
1273e5c31af7Sopenharmony_ci
1274e5c31af7Sopenharmony_ci			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1275e5c31af7Sopenharmony_ci			{
1276e5c31af7Sopenharmony_ci				glu::Precision	prec		= precisions[precNdx];
1277e5c31af7Sopenharmony_ci				string			precName	= glu::getPrecisionName(prec);
1278e5c31af7Sopenharmony_ci
1279e5c31af7Sopenharmony_ci				floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT,		prec, 0, numTargets)).toVec()));
1280e5c31af7Sopenharmony_ci				floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2,	prec, 0, numTargets)).toVec()));
1281e5c31af7Sopenharmony_ci				floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3,	prec, 0, numTargets)).toVec()));
1282e5c31af7Sopenharmony_ci				floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4,	prec, 0, numTargets)).toVec()));
1283e5c31af7Sopenharmony_ci			}
1284e5c31af7Sopenharmony_ci		}
1285e5c31af7Sopenharmony_ci
1286e5c31af7Sopenharmony_ci		// .fixed
1287e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* fixedGroup = new tcu::TestCaseGroup(m_testCtx, "fixed", "Fixed-point output tests");
1288e5c31af7Sopenharmony_ci		arrayGroup->addChild(fixedGroup);
1289e5c31af7Sopenharmony_ci		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFixedFormats); fmtNdx++)
1290e5c31af7Sopenharmony_ci		{
1291e5c31af7Sopenharmony_ci			deUint32			format		= requiredFixedFormats[fmtNdx];
1292e5c31af7Sopenharmony_ci			string				fmtName		= getFormatName(format);
1293e5c31af7Sopenharmony_ci			vector<BufferSpec>	fboSpec;
1294e5c31af7Sopenharmony_ci
1295e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numTargets; ndx++)
1296e5c31af7Sopenharmony_ci				fboSpec.push_back(BufferSpec(format, width, height, samples));
1297e5c31af7Sopenharmony_ci
1298e5c31af7Sopenharmony_ci			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1299e5c31af7Sopenharmony_ci			{
1300e5c31af7Sopenharmony_ci				glu::Precision	prec		= precisions[precNdx];
1301e5c31af7Sopenharmony_ci				string			precName	= glu::getPrecisionName(prec);
1302e5c31af7Sopenharmony_ci
1303e5c31af7Sopenharmony_ci				fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT,		prec, 0, numTargets)).toVec()));
1304e5c31af7Sopenharmony_ci				fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2,	prec, 0, numTargets)).toVec()));
1305e5c31af7Sopenharmony_ci				fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3,	prec, 0, numTargets)).toVec()));
1306e5c31af7Sopenharmony_ci				fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4,	prec, 0, numTargets)).toVec()));
1307e5c31af7Sopenharmony_ci			}
1308e5c31af7Sopenharmony_ci		}
1309e5c31af7Sopenharmony_ci
1310e5c31af7Sopenharmony_ci		// .int
1311e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "int", "Integer output tests");
1312e5c31af7Sopenharmony_ci		arrayGroup->addChild(intGroup);
1313e5c31af7Sopenharmony_ci		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredIntFormats); fmtNdx++)
1314e5c31af7Sopenharmony_ci		{
1315e5c31af7Sopenharmony_ci			deUint32			format		= requiredIntFormats[fmtNdx];
1316e5c31af7Sopenharmony_ci			string				fmtName		= getFormatName(format);
1317e5c31af7Sopenharmony_ci			vector<BufferSpec>	fboSpec;
1318e5c31af7Sopenharmony_ci
1319e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numTargets; ndx++)
1320e5c31af7Sopenharmony_ci				fboSpec.push_back(BufferSpec(format, width, height, samples));
1321e5c31af7Sopenharmony_ci
1322e5c31af7Sopenharmony_ci			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1323e5c31af7Sopenharmony_ci			{
1324e5c31af7Sopenharmony_ci				glu::Precision	prec		= precisions[precNdx];
1325e5c31af7Sopenharmony_ci				string			precName	= glu::getPrecisionName(prec);
1326e5c31af7Sopenharmony_ci
1327e5c31af7Sopenharmony_ci				intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_int").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT,		prec, 0, numTargets)).toVec()));
1328e5c31af7Sopenharmony_ci				intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec2").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC2,	prec, 0, numTargets)).toVec()));
1329e5c31af7Sopenharmony_ci				intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec3").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC3,	prec, 0, numTargets)).toVec()));
1330e5c31af7Sopenharmony_ci				intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec4").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC4,	prec, 0, numTargets)).toVec()));
1331e5c31af7Sopenharmony_ci			}
1332e5c31af7Sopenharmony_ci		}
1333e5c31af7Sopenharmony_ci
1334e5c31af7Sopenharmony_ci		// .uint
1335e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uint", "Usigned integer output tests");
1336e5c31af7Sopenharmony_ci		arrayGroup->addChild(uintGroup);
1337e5c31af7Sopenharmony_ci		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredUintFormats); fmtNdx++)
1338e5c31af7Sopenharmony_ci		{
1339e5c31af7Sopenharmony_ci			deUint32			format		= requiredUintFormats[fmtNdx];
1340e5c31af7Sopenharmony_ci			string				fmtName		= getFormatName(format);
1341e5c31af7Sopenharmony_ci			vector<BufferSpec>	fboSpec;
1342e5c31af7Sopenharmony_ci
1343e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numTargets; ndx++)
1344e5c31af7Sopenharmony_ci				fboSpec.push_back(BufferSpec(format, width, height, samples));
1345e5c31af7Sopenharmony_ci
1346e5c31af7Sopenharmony_ci			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1347e5c31af7Sopenharmony_ci			{
1348e5c31af7Sopenharmony_ci				glu::Precision	prec		= precisions[precNdx];
1349e5c31af7Sopenharmony_ci				string			precName	= glu::getPrecisionName(prec);
1350e5c31af7Sopenharmony_ci
1351e5c31af7Sopenharmony_ci				uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uint").c_str(),		"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT,			prec, 0, numTargets)).toVec()));
1352e5c31af7Sopenharmony_ci				uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec2").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC2,	prec, 0, numTargets)).toVec()));
1353e5c31af7Sopenharmony_ci				uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec3").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC3,	prec, 0, numTargets)).toVec()));
1354e5c31af7Sopenharmony_ci				uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec4").c_str(),	"",	fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC4,	prec, 0, numTargets)).toVec()));
1355e5c31af7Sopenharmony_ci			}
1356e5c31af7Sopenharmony_ci		}
1357e5c31af7Sopenharmony_ci	}
1358e5c31af7Sopenharmony_ci
1359e5c31af7Sopenharmony_ci	// .random
1360e5c31af7Sopenharmony_ci	{
1361e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random fragment output cases");
1362e5c31af7Sopenharmony_ci		addChild(randomGroup);
1363e5c31af7Sopenharmony_ci
1364e5c31af7Sopenharmony_ci		for (deUint32 seed = 0; seed < 100; seed++)
1365e5c31af7Sopenharmony_ci			randomGroup->addChild(createRandomCase(m_context, 2, 4, seed));
1366e5c31af7Sopenharmony_ci	}
1367e5c31af7Sopenharmony_ci}
1368e5c31af7Sopenharmony_ci
1369e5c31af7Sopenharmony_ci} // Functional
1370e5c31af7Sopenharmony_ci} // gles3
1371e5c31af7Sopenharmony_ci} // deqp
1372