1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 Base class for FBO tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fFboTestCase.hpp"
25#include "es31fFboTestUtil.hpp"
26#include "tcuTestLog.hpp"
27#include "tcuImageCompare.hpp"
28#include "tcuRenderTarget.hpp"
29#include "sglrGLContext.hpp"
30#include "sglrReferenceContext.hpp"
31#include "gluStrUtil.hpp"
32#include "gluContextInfo.hpp"
33#include "deRandom.hpp"
34#include "glwEnums.hpp"
35#include "glwFunctions.hpp"
36
37#include <algorithm>
38
39namespace deqp
40{
41namespace gles31
42{
43namespace Functional
44{
45
46using tcu::TestLog;
47using std::string;
48
49FboTestCase::FboTestCase (Context& context, const char* name, const char* description, bool useScreenSizedViewport)
50	: TestCase			(context, name, description)
51	, m_viewportWidth	(useScreenSizedViewport ? context.getRenderTarget().getWidth() : 128)
52	, m_viewportHeight	(useScreenSizedViewport ? context.getRenderTarget().getHeight() : 128)
53{
54}
55
56FboTestCase::~FboTestCase (void)
57{
58}
59
60FboTestCase::IterateResult FboTestCase::iterate (void)
61{
62	glu::RenderContext&			renderCtx		= TestCase::m_context.getRenderContext();
63	const tcu::RenderTarget&	renderTarget	= renderCtx.getRenderTarget();
64	TestLog&					log				= m_testCtx.getLog();
65
66	// Viewport.
67	de::Random					rnd				(deStringHash(getName()));
68	int							width			= deMin32(renderTarget.getWidth(),	m_viewportWidth);
69	int							height			= deMin32(renderTarget.getHeight(),	m_viewportHeight);
70	int							x				= rnd.getInt(0, renderTarget.getWidth()		- width);
71	int							y				= rnd.getInt(0, renderTarget.getHeight()	- height);
72
73	// Surface format and storage is choosen by render().
74	tcu::Surface				reference;
75	tcu::Surface				result;
76
77	// Call preCheck() that can throw exception if some requirement is not met.
78	preCheck();
79
80	log << TestLog::Message << "Rendering with GL driver" << TestLog::EndMessage;
81
82	// Render using GLES3.1
83	try
84	{
85		sglr::GLContext context(renderCtx, log, 0, tcu::IVec4(x, y, width, height));
86		setContext(&context);
87		render(result);
88
89		// Check error.
90		deUint32 err = glGetError();
91		if (err != GL_NO_ERROR)
92			throw glu::Error(err, glu::getErrorStr(err).toString().c_str(), DE_NULL, __FILE__, __LINE__);
93
94		setContext(DE_NULL);
95	}
96	catch (const FboTestUtil::FboIncompleteException& e)
97	{
98		if (e.getReason() == GL_FRAMEBUFFER_UNSUPPORTED)
99		{
100			log << e;
101			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
102			return STOP;
103		}
104		else
105			throw;
106	}
107
108	log << TestLog::Message << "Rendering reference image" << TestLog::EndMessage;
109
110	// Render reference.
111	{
112		sglr::ReferenceContextBuffers	buffers	(tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), renderTarget.getDepthBits(), renderTarget.getStencilBits(), width, height);
113		sglr::ReferenceContext			context	(sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
114
115		setContext(&context);
116		render(reference);
117		setContext(DE_NULL);
118	}
119
120	bool isOk = compare(reference, result);
121	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
122							isOk ? "Pass"				: "Image comparison failed");
123	return STOP;
124}
125
126bool FboTestCase::compare (const tcu::Surface& reference, const tcu::Surface& result)
127{
128	return tcu::fuzzyCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, 0.05f, tcu::COMPARE_LOG_RESULT);
129}
130
131void FboTestCase::readPixels (tcu::Surface& dst, int x, int y, int width, int height, const tcu::TextureFormat& format, const tcu::Vec4& scale, const tcu::Vec4& bias)
132{
133	FboTestUtil::readPixels(*getCurrentContext(), dst, x, y, width, height, format, scale, bias);
134}
135
136void FboTestCase::readPixels (tcu::Surface& dst, int x, int y, int width, int height)
137{
138	getCurrentContext()->readPixels(dst, x, y, width, height);
139}
140
141void FboTestCase::checkFramebufferStatus (deUint32 target)
142{
143	deUint32 status = glCheckFramebufferStatus(target);
144	if (status != GL_FRAMEBUFFER_COMPLETE)
145		throw FboTestUtil::FboIncompleteException(status, __FILE__, __LINE__);
146}
147
148void FboTestCase::checkError (void)
149{
150	deUint32 err = glGetError();
151	if (err != GL_NO_ERROR)
152		throw glu::Error((int)err, (string("Got ") + glu::getErrorStr(err).toString()).c_str(), DE_NULL, __FILE__, __LINE__);
153}
154
155static bool isRequiredFormat (deUint32 format, glu::RenderContext& renderContext)
156{
157	const bool isES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
158	switch (format)
159	{
160		// Color-renderable formats
161		case GL_RGBA32I:
162		case GL_RGBA32UI:
163		case GL_RGBA16I:
164		case GL_RGBA16UI:
165		case GL_RGBA8:
166		case GL_RGBA8I:
167		case GL_RGBA8UI:
168		case GL_SRGB8_ALPHA8:
169		case GL_RGB10_A2:
170		case GL_RGB10_A2UI:
171		case GL_RGBA4:
172		case GL_RGB5_A1:
173		case GL_RGB8:
174		case GL_RGB565:
175		case GL_RG32I:
176		case GL_RG32UI:
177		case GL_RG16I:
178		case GL_RG16UI:
179		case GL_RG8:
180		case GL_RG8I:
181		case GL_RG8UI:
182		case GL_R32I:
183		case GL_R32UI:
184		case GL_R16I:
185		case GL_R16UI:
186		case GL_R8:
187		case GL_R8I:
188		case GL_R8UI:
189			return true;
190
191		// Depth formats
192		case GL_DEPTH_COMPONENT32F:
193		case GL_DEPTH_COMPONENT24:
194		case GL_DEPTH_COMPONENT16:
195			return true;
196
197		// Depth+stencil formats
198		case GL_DEPTH32F_STENCIL8:
199		case GL_DEPTH24_STENCIL8:
200			return true;
201
202		// Stencil formats
203		case GL_STENCIL_INDEX8:
204			return true;
205
206		// Float format
207		case GL_RGBA32F:
208		case GL_RGB32F:
209		case GL_R11F_G11F_B10F:
210		case GL_RG32F:
211		case GL_R32F:
212			return isES32;
213
214
215		default:
216			return false;
217	}
218}
219
220static std::vector<std::string> getEnablingExtensions (deUint32 format, glu::RenderContext& renderContext)
221{
222	const bool					isES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
223	std::vector<std::string>	out;
224
225	DE_ASSERT(!isRequiredFormat(format, renderContext));
226
227	switch (format)
228	{
229		case GL_RGB16F:
230			out.push_back("GL_EXT_color_buffer_half_float");
231			break;
232
233		case GL_RGBA16F:
234		case GL_RG16F:
235		case GL_R16F:
236			out.push_back("GL_EXT_color_buffer_half_float");
237
238		case GL_RGBA32F:
239		case GL_RGB32F:
240		case GL_R11F_G11F_B10F:
241		case GL_RG32F:
242		case GL_R32F:
243			if (!isES32)
244				out.push_back("GL_EXT_color_buffer_float");
245			break;
246
247		default:
248			break;
249	}
250
251	return out;
252}
253
254static bool isAnyExtensionSupported (Context& context, const std::vector<std::string>& requiredExts)
255{
256	for (std::vector<std::string>::const_iterator iter = requiredExts.begin(); iter != requiredExts.end(); iter++)
257	{
258		const std::string& extension = *iter;
259
260		if (context.getContextInfo().isExtensionSupported(extension.c_str()))
261			return true;
262	}
263
264	return false;
265}
266
267void FboTestCase::checkFormatSupport (deUint32 sizedFormat)
268{
269	const bool						isCoreFormat	= isRequiredFormat(sizedFormat, m_context.getRenderContext());
270	const std::vector<std::string>	requiredExts	= (!isCoreFormat) ? getEnablingExtensions(sizedFormat, m_context.getRenderContext()) : std::vector<std::string>();
271
272	// Check that we don't try to use invalid formats.
273	DE_ASSERT(isCoreFormat || !requiredExts.empty());
274
275	if (!requiredExts.empty() && !isAnyExtensionSupported(m_context, requiredExts))
276		throw tcu::NotSupportedError("Format not supported");
277}
278
279static int getMinimumSampleCount (deUint32 format)
280{
281	switch (format)
282	{
283		// Core formats
284		case GL_RGBA32I:
285		case GL_RGBA32UI:
286		case GL_RGBA16I:
287		case GL_RGBA16UI:
288		case GL_RGBA8:
289		case GL_RGBA8I:
290		case GL_RGBA8UI:
291		case GL_SRGB8_ALPHA8:
292		case GL_RGB10_A2:
293		case GL_RGB10_A2UI:
294		case GL_RGBA4:
295		case GL_RGB5_A1:
296		case GL_RGB8:
297		case GL_RGB565:
298		case GL_RG32I:
299		case GL_RG32UI:
300		case GL_RG16I:
301		case GL_RG16UI:
302		case GL_RG8:
303		case GL_RG8I:
304		case GL_RG8UI:
305		case GL_R32I:
306		case GL_R32UI:
307		case GL_R16I:
308		case GL_R16UI:
309		case GL_R8:
310		case GL_R8I:
311		case GL_R8UI:
312		case GL_DEPTH_COMPONENT32F:
313		case GL_DEPTH_COMPONENT24:
314		case GL_DEPTH_COMPONENT16:
315		case GL_DEPTH32F_STENCIL8:
316		case GL_DEPTH24_STENCIL8:
317		case GL_STENCIL_INDEX8:
318			return 4;
319
320		// GL_EXT_color_buffer_float
321		case GL_R11F_G11F_B10F:
322		case GL_RG16F:
323		case GL_R16F:
324			return 4;
325
326		case GL_RGBA32F:
327		case GL_RGBA16F:
328		case GL_RG32F:
329		case GL_R32F:
330			return 0;
331
332		// GL_EXT_color_buffer_half_float
333		case GL_RGB16F:
334			return 0;
335
336		default:
337			DE_FATAL("Unknown format");
338			return 0;
339	}
340}
341
342static std::vector<int> querySampleCounts (const glw::Functions& gl, deUint32 format)
343{
344	int					numSampleCounts		= 0;
345	std::vector<int>	sampleCounts;
346
347	gl.getInternalformativ(GL_RENDERBUFFER, format, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts);
348
349	if (numSampleCounts > 0)
350	{
351		sampleCounts.resize(numSampleCounts);
352		gl.getInternalformativ(GL_RENDERBUFFER, format, GL_SAMPLES, (glw::GLsizei)sampleCounts.size(), &sampleCounts[0]);
353	}
354
355	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to query sample counts for format");
356
357	return sampleCounts;
358}
359
360void FboTestCase::checkSampleCount (deUint32 sizedFormat, int numSamples)
361{
362	const int minSampleCount = getMinimumSampleCount(sizedFormat);
363
364	if (numSamples > minSampleCount)
365	{
366		// Exceeds spec-mandated minimum - need to check.
367		const std::vector<int> supportedSampleCounts = querySampleCounts(m_context.getRenderContext().getFunctions(), sizedFormat);
368
369		if (std::find(supportedSampleCounts.begin(), supportedSampleCounts.end(), numSamples) == supportedSampleCounts.end())
370			throw tcu::NotSupportedError("Sample count not supported");
371	}
372}
373
374void FboTestCase::clearColorBuffer (const tcu::TextureFormat& format, const tcu::Vec4& value)
375{
376	FboTestUtil::clearColorBuffer(*getCurrentContext(), format, value);
377}
378
379} // Functional
380} // gles31
381} // deqp
382