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