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 FBO stencilbuffer tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fFramebufferBlitTests.hpp"
25#include "es3fFboTestCase.hpp"
26#include "es3fFboTestUtil.hpp"
27#include "gluTextureUtil.hpp"
28#include "gluContextInfo.hpp"
29#include "tcuTextureUtil.hpp"
30#include "tcuVectorUtil.hpp"
31#include "tcuTestLog.hpp"
32#include "tcuImageCompare.hpp"
33#include "tcuRenderTarget.hpp"
34#include "sglrContextUtil.hpp"
35#include "glwEnums.hpp"
36#include "deStringUtil.hpp"
37
38namespace deqp
39{
40namespace gles3
41{
42namespace Functional
43{
44
45using std::string;
46using tcu::TestLog;
47using tcu::Vec2;
48using tcu::Vec3;
49using tcu::Vec4;
50using tcu::IVec2;
51using tcu::IVec3;
52using tcu::IVec4;
53using tcu::UVec4;
54using namespace FboTestUtil;
55
56class BlitRectCase : public FboTestCase
57{
58public:
59	BlitRectCase (Context& context, const char* name, const char* desc, deUint32 filter, const IVec2& srcSize, const IVec4& srcRect, const IVec2& dstSize, const IVec4& dstRect, int cellSize = 8)
60		: FboTestCase		(context, name, desc)
61		, m_filter			(filter)
62		, m_srcSize			(srcSize)
63		, m_srcRect			(srcRect)
64		, m_dstSize			(dstSize)
65		, m_dstRect			(dstRect)
66		, m_cellSize		(cellSize)
67		, m_gridCellColorA	(0.2f, 0.7f, 0.1f, 1.0f)
68		, m_gridCellColorB	(0.7f, 0.1f, 0.5f, 0.8f)
69	{
70	}
71
72	void render (tcu::Surface& dst)
73	{
74		const deUint32			colorFormat		= GL_RGBA8;
75
76		GradientShader			gradShader		(glu::TYPE_FLOAT_VEC4);
77		Texture2DShader			texShader		(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
78		deUint32				gradShaderID	= getCurrentContext()->createProgram(&gradShader);
79		deUint32				texShaderID		= getCurrentContext()->createProgram(&texShader);
80
81		deUint32				srcFbo = 0;
82		deUint32				dstFbo = 0;
83		deUint32				srcRbo = 0;
84		deUint32				dstRbo = 0;
85
86		// Setup shaders
87		gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
88		texShader.setUniforms(*getCurrentContext(), texShaderID);
89
90		// Create framebuffers.
91		for (int ndx = 0; ndx < 2; ndx++)
92		{
93			deUint32&		fbo		= ndx ? dstFbo : srcFbo;
94			deUint32&		rbo		= ndx ? dstRbo : srcRbo;
95			const IVec2&	size	= ndx ? m_dstSize : m_srcSize;
96
97			glGenFramebuffers(1, &fbo);
98			glGenRenderbuffers(1, &rbo);
99
100			glBindRenderbuffer(GL_RENDERBUFFER, rbo);
101			glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, size.x(), size.y());
102
103			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
104			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
105			checkError();
106			checkFramebufferStatus(GL_FRAMEBUFFER);
107		}
108
109		// Fill destination with gradient.
110		glBindFramebuffer(GL_FRAMEBUFFER, dstFbo);
111		glViewport(0, 0, m_dstSize.x(), m_dstSize.y());
112
113		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
114
115		// Fill source with grid pattern.
116		{
117			const deUint32		format		= GL_RGBA;
118			const deUint32		dataType	= GL_UNSIGNED_BYTE;
119			const int			texW		= m_srcSize.x();
120			const int			texH		= m_srcSize.y();
121			deUint32			gridTex		= 0;
122			tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
123
124			tcu::fillWithGrid(data.getAccess(), m_cellSize, m_gridCellColorA, m_gridCellColorB);
125
126			glGenTextures(1, &gridTex);
127			glBindTexture(GL_TEXTURE_2D, gridTex);
128			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
129			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
130			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
131			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
132			glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
133
134			glBindFramebuffer(GL_FRAMEBUFFER, srcFbo);
135			glViewport(0, 0, m_srcSize.x(), m_srcSize.y());
136			sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
137		}
138
139		// Perform copy.
140		glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
141		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
142		glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(), m_dstRect.z(), m_dstRect.w(), GL_COLOR_BUFFER_BIT, m_filter);
143
144		// Read back results.
145		glBindFramebuffer(GL_READ_FRAMEBUFFER, dstFbo);
146		readPixels(dst, 0, 0, m_dstSize.x(), m_dstSize.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f));
147	}
148
149	virtual bool compare (const tcu::Surface& reference, const tcu::Surface& result)
150	{
151		// Use pixel-threshold compare for rect cases since 1px off will mean failure.
152		tcu::RGBA threshold = TestCase::m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7,7,7,7);
153		return tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, tcu::COMPARE_LOG_RESULT);
154	}
155
156protected:
157	const deUint32	m_filter;
158	const IVec2		m_srcSize;
159	const IVec4		m_srcRect;
160	const IVec2		m_dstSize;
161	const IVec4		m_dstRect;
162	const int		m_cellSize;
163	const Vec4		m_gridCellColorA;
164	const Vec4		m_gridCellColorB;
165};
166
167class BlitNearestFilterConsistencyCase : public BlitRectCase
168{
169public:
170			BlitNearestFilterConsistencyCase	(Context& context, const char* name, const char* desc, const IVec2& srcSize, const IVec4& srcRect, const IVec2& dstSize, const IVec4& dstRect);
171
172	bool	compare								(const tcu::Surface& reference, const tcu::Surface& result);
173};
174
175BlitNearestFilterConsistencyCase::BlitNearestFilterConsistencyCase (Context& context, const char* name, const char* desc, const IVec2& srcSize, const IVec4& srcRect, const IVec2& dstSize, const IVec4& dstRect)
176	: BlitRectCase(context, name, desc, GL_NEAREST, srcSize, srcRect, dstSize, dstRect, 1)
177{
178}
179
180bool BlitNearestFilterConsistencyCase::compare (const tcu::Surface& reference, const tcu::Surface& result)
181{
182	DE_ASSERT(reference.getWidth() == result.getWidth());
183	DE_ASSERT(reference.getHeight() == result.getHeight());
184	DE_UNREF(reference);
185
186	// Image origin must be visible (for baseColor)
187	DE_ASSERT(de::min(m_dstRect.x(), m_dstRect.z()) >= 0);
188	DE_ASSERT(de::min(m_dstRect.y(), m_dstRect.w()) >= 0);
189
190	const tcu::RGBA		cellColorA		(m_gridCellColorA);
191	const tcu::RGBA		cellColorB		(m_gridCellColorB);
192	const tcu::RGBA		threshold		= TestCase::m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7,7,7,7);
193	const tcu::IVec4	destinationArea	= tcu::IVec4(de::clamp(de::min(m_dstRect.x(), m_dstRect.z()), 0, result.getWidth()),
194													 de::clamp(de::min(m_dstRect.y(), m_dstRect.w()), 0, result.getHeight()),
195													 de::clamp(de::max(m_dstRect.x(), m_dstRect.z()), 0, result.getWidth()),
196													 de::clamp(de::max(m_dstRect.y(), m_dstRect.w()), 0, result.getHeight()));
197	const tcu::RGBA		baseColor		= result.getPixel(destinationArea.x(), destinationArea.y());
198	const bool			signConfig		= tcu::compareThreshold(baseColor, cellColorA, threshold);
199
200	bool				error			= false;
201	tcu::Surface		errorMask		(result.getWidth(), result.getHeight());
202	std::vector<bool>	horisontalSign	(destinationArea.z() - destinationArea.x());
203	std::vector<bool>	verticalSign	(destinationArea.w() - destinationArea.y());
204
205	tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
206
207	// Checking only area in our destination rect
208
209	m_testCtx.getLog()
210		<< tcu::TestLog::Message
211		<< "Verifying consistency of NEAREST filtering. Verifying rect " << m_dstRect << ".\n"
212		<< "Rounding direction of the NEAREST filter at the horisontal texel edge (x = n + 0.5) should not depend on the y-coordinate.\n"
213		<< "Rounding direction of the NEAREST filter at the vertical texel edge (y = n + 0.5) should not depend on the x-coordinate.\n"
214		<< "Blitting a grid (with uniform sized cells) should result in a grid (with non-uniform sized cells)."
215		<< tcu::TestLog::EndMessage;
216
217	// Verify that destination only contains valid colors
218
219	for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy)
220	for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx)
221	{
222		const tcu::RGBA	color	= result.getPixel(destinationArea.x() + dx, destinationArea.y() + dy);
223		const bool isValidColor = tcu::compareThreshold(color, cellColorA, threshold) || tcu::compareThreshold(color, cellColorB, threshold);
224
225		if (!isValidColor)
226		{
227			errorMask.setPixel(destinationArea.x() + dx, destinationArea.y() + dy, tcu::RGBA::red());
228			error = true;
229		}
230	}
231	if (error)
232	{
233		m_testCtx.getLog()
234			<< tcu::TestLog::Message
235			<< "Image verification failed, destination rect contains unexpected values. "
236			<< "Expected either " << cellColorA << " or " << cellColorB << "."
237			<< tcu::TestLog::EndMessage
238			<< tcu::TestLog::ImageSet("Result", "Image verification result")
239			<< tcu::TestLog::Image("Result",	"Result",		result)
240			<< tcu::TestLog::Image("ErrorMask",	"Error mask",	errorMask)
241			<< tcu::TestLog::EndImageSet;
242		return false;
243	}
244
245	// Detect result edges by reading the first row and first column of the blitted area.
246	// Blitting a grid should result in a grid-like image. ("sign changes" should be consistent)
247
248	for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx)
249	{
250		const tcu::RGBA color = result.getPixel(destinationArea.x() + dx, destinationArea.y());
251
252		if (tcu::compareThreshold(color, cellColorA, threshold))
253			horisontalSign[dx] = true;
254		else if (tcu::compareThreshold(color, cellColorB, threshold))
255			horisontalSign[dx] = false;
256		else
257			DE_ASSERT(DE_FALSE);
258	}
259	for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy)
260	{
261		const tcu::RGBA color = result.getPixel(destinationArea.x(), destinationArea.y() + dy);
262
263		if (tcu::compareThreshold(color, cellColorA, threshold))
264			verticalSign[dy] = true;
265		else if (tcu::compareThreshold(color, cellColorB, threshold))
266			verticalSign[dy] = false;
267		else
268			DE_ASSERT(DE_FALSE);
269	}
270
271	// Verify grid-like image
272
273	for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy)
274	for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx)
275	{
276		const tcu::RGBA	color		= result.getPixel(destinationArea.x() + dx, destinationArea.y() + dy);
277		const bool		resultSign	= tcu::compareThreshold(cellColorA, color, threshold);
278		const bool		correctSign	= (horisontalSign[dx] == verticalSign[dy]) == signConfig;
279
280		if (resultSign != correctSign)
281		{
282			errorMask.setPixel(destinationArea.x() + dx, destinationArea.y() + dy, tcu::RGBA::red());
283			error = true;
284		}
285	}
286
287	// Report result
288
289	if (error)
290	{
291		m_testCtx.getLog()
292			<< tcu::TestLog::Message
293			<< "Image verification failed, nearest filter is not consistent."
294			<< tcu::TestLog::EndMessage
295			<< tcu::TestLog::ImageSet("Result", "Image verification result")
296			<< tcu::TestLog::Image("Result",	"Result",		result)
297			<< tcu::TestLog::Image("ErrorMask",	"Error mask",	errorMask)
298			<< tcu::TestLog::EndImageSet;
299	}
300	else
301	{
302		m_testCtx.getLog()
303			<< tcu::TestLog::Message
304			<< "Image verification passed."
305			<< tcu::TestLog::EndMessage
306			<< tcu::TestLog::ImageSet("Result", "Image verification result")
307			<< tcu::TestLog::Image("Result", "Result", result)
308			<< tcu::TestLog::EndImageSet;
309	}
310
311	return !error;
312}
313
314static tcu::BVec4 getChannelMask (tcu::TextureFormat::ChannelOrder order)
315{
316	switch (order)
317	{
318		case tcu::TextureFormat::R:		return tcu::BVec4(true,	false,	false,	false);
319		case tcu::TextureFormat::RG:	return tcu::BVec4(true,	true,	false,	false);
320		case tcu::TextureFormat::RGB:	return tcu::BVec4(true,	true,	true,	false);
321		case tcu::TextureFormat::RGBA:	return tcu::BVec4(true,	true,	true,	true);
322		case tcu::TextureFormat::sRGB:	return tcu::BVec4(true,	true,	true,	false);
323		case tcu::TextureFormat::sRGBA:	return tcu::BVec4(true,	true,	true,	true);
324		default:
325			DE_ASSERT(false);
326			return tcu::BVec4(false);
327	}
328}
329
330class BlitColorConversionCase : public FboTestCase
331{
332public:
333	BlitColorConversionCase (Context& context, const char* name, const char* desc, deUint32 srcFormat, deUint32 dstFormat, const IVec2& size)
334		: FboTestCase	(context, name, desc)
335		, m_srcFormat	(srcFormat)
336		, m_dstFormat	(dstFormat)
337		, m_size		(size)
338	{
339	}
340
341protected:
342	void preCheck (void)
343	{
344		checkFormatSupport(m_srcFormat);
345		checkFormatSupport(m_dstFormat);
346	}
347
348	void render (tcu::Surface& dst)
349	{
350		tcu::TextureFormat		srcFormat			= glu::mapGLInternalFormat(m_srcFormat);
351		tcu::TextureFormat		dstFormat			= glu::mapGLInternalFormat(m_dstFormat);
352		glu::DataType			srcOutputType		= getFragmentOutputType(srcFormat);
353		glu::DataType			dstOutputType		= getFragmentOutputType(dstFormat);
354
355		// Compute ranges \note Doesn't handle case where src or dest is not subset of the another!
356		tcu::TextureFormatInfo	srcFmtRangeInfo		= tcu::getTextureFormatInfo(srcFormat);
357		tcu::TextureFormatInfo	dstFmtRangeInfo		= tcu::getTextureFormatInfo(dstFormat);
358		tcu::BVec4				copyMask			= tcu::logicalAnd(getChannelMask(srcFormat.order), getChannelMask(dstFormat.order));
359		tcu::BVec4				srcIsGreater		= tcu::greaterThan(srcFmtRangeInfo.valueMax-srcFmtRangeInfo.valueMin, dstFmtRangeInfo.valueMax-dstFmtRangeInfo.valueMin);
360		tcu::TextureFormatInfo	srcRangeInfo		(tcu::select(dstFmtRangeInfo.valueMin,		srcFmtRangeInfo.valueMin,		tcu::logicalAnd(copyMask, srcIsGreater)),
361													 tcu::select(dstFmtRangeInfo.valueMax,		srcFmtRangeInfo.valueMax,		tcu::logicalAnd(copyMask, srcIsGreater)),
362													 tcu::select(dstFmtRangeInfo.lookupScale,	srcFmtRangeInfo.lookupScale,	tcu::logicalAnd(copyMask, srcIsGreater)),
363													 tcu::select(dstFmtRangeInfo.lookupBias,	srcFmtRangeInfo.lookupBias,		tcu::logicalAnd(copyMask, srcIsGreater)));
364		tcu::TextureFormatInfo	dstRangeInfo		(tcu::select(dstFmtRangeInfo.valueMin,		srcFmtRangeInfo.valueMin,		tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)),
365													 tcu::select(dstFmtRangeInfo.valueMax,		srcFmtRangeInfo.valueMax,		tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)),
366													 tcu::select(dstFmtRangeInfo.lookupScale,	srcFmtRangeInfo.lookupScale,	tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)),
367													 tcu::select(dstFmtRangeInfo.lookupBias,	srcFmtRangeInfo.lookupBias,		tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)));
368
369		// Shaders.
370		GradientShader			gradientToSrcShader	(srcOutputType);
371		GradientShader			gradientToDstShader	(dstOutputType);
372
373		deUint32				gradShaderSrcID		= getCurrentContext()->createProgram(&gradientToSrcShader);
374		deUint32				gradShaderDstID		= getCurrentContext()->createProgram(&gradientToDstShader);
375
376		deUint32				srcFbo, dstFbo;
377		deUint32				srcRbo, dstRbo;
378
379		// Create framebuffers.
380		for (int ndx = 0; ndx < 2; ndx++)
381		{
382			deUint32&	fbo		= ndx ? dstFbo : srcFbo;
383			deUint32&	rbo		= ndx ? dstRbo : srcRbo;
384			deUint32	format	= ndx ? m_dstFormat : m_srcFormat;
385
386			glGenFramebuffers(1, &fbo);
387			glGenRenderbuffers(1, &rbo);
388
389			glBindRenderbuffer(GL_RENDERBUFFER, rbo);
390			glRenderbufferStorage(GL_RENDERBUFFER, format, m_size.x(), m_size.y());
391
392			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
393			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
394			checkError();
395			checkFramebufferStatus(GL_FRAMEBUFFER);
396		}
397
398		glViewport(0, 0, m_size.x(), m_size.y());
399
400		// Render gradients.
401		for (int ndx = 0; ndx < 2; ndx++)
402		{
403			glBindFramebuffer(GL_FRAMEBUFFER, ndx ? dstFbo : srcFbo);
404
405			if (ndx)
406			{
407				gradientToDstShader.setGradient(*getCurrentContext(), gradShaderDstID, dstRangeInfo.valueMax, dstRangeInfo.valueMin);
408				sglr::drawQuad(*getCurrentContext(), gradShaderDstID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
409			}
410			else
411			{
412				gradientToSrcShader.setGradient(*getCurrentContext(), gradShaderSrcID, srcRangeInfo.valueMin, dstRangeInfo.valueMax);
413				sglr::drawQuad(*getCurrentContext(), gradShaderSrcID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
414			}
415		}
416
417		// Execute copy.
418		glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
419		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
420		glBlitFramebuffer(0, 0, m_size.x(), m_size.y(), 0, 0, m_size.x(), m_size.y(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
421		checkError();
422
423		// Read results.
424		glBindFramebuffer(GL_READ_FRAMEBUFFER, dstFbo);
425		readPixels(dst, 0, 0, m_size.x(), m_size.y(), dstFormat, dstRangeInfo.lookupScale, dstRangeInfo.lookupBias);
426	}
427
428	bool compare (const tcu::Surface& reference, const tcu::Surface& result)
429	{
430		const tcu::TextureFormat	srcFormat	= glu::mapGLInternalFormat(m_srcFormat);
431		const tcu::TextureFormat	dstFormat	= glu::mapGLInternalFormat(m_dstFormat);
432		const bool					srcIsSRGB	= tcu::isSRGB(srcFormat);
433		const bool					dstIsSRGB	= tcu::isSRGB(dstFormat);
434
435		tcu::RGBA					threshold;
436
437		if (dstIsSRGB)
438		{
439			threshold = getToSRGBConversionThreshold(srcFormat, dstFormat);
440		}
441		else
442		{
443			const tcu::RGBA	srcMaxDiff	= getFormatThreshold(srcFormat) * (srcIsSRGB ? 2 : 1);
444			const tcu::RGBA	dstMaxDiff	= getFormatThreshold(dstFormat);
445
446			threshold = tcu::max(srcMaxDiff, dstMaxDiff);
447		}
448
449		m_testCtx.getLog() << tcu::TestLog::Message << "threshold = " << threshold << tcu::TestLog::EndMessage;
450		return tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, tcu::COMPARE_LOG_RESULT);
451	}
452
453private:
454	deUint32		m_srcFormat;
455	deUint32		m_dstFormat;
456	IVec2			m_size;
457};
458
459class BlitDepthStencilCase : public FboTestCase
460{
461public:
462	BlitDepthStencilCase (Context& context, const char* name, const char* desc, deUint32 depthFormat, deUint32 stencilFormat, deUint32 srcBuffers, const IVec2& srcSize, const IVec4& srcRect, deUint32 dstBuffers, const IVec2& dstSize, const IVec4& dstRect, deUint32 copyBuffers)
463		: FboTestCase	(context, name, desc)
464		, m_depthFormat	(depthFormat)
465		, m_stencilFormat(stencilFormat)
466		, m_srcBuffers	(srcBuffers)
467		, m_srcSize		(srcSize)
468		, m_srcRect		(srcRect)
469		, m_dstBuffers	(dstBuffers)
470		, m_dstSize		(dstSize)
471		, m_dstRect		(dstRect)
472		, m_copyBuffers	(copyBuffers)
473	{
474	}
475
476protected:
477	void preCheck (void)
478	{
479		if (m_depthFormat != GL_NONE)
480			checkFormatSupport(m_depthFormat);
481		if (m_stencilFormat != GL_NONE)
482			checkFormatSupport(m_stencilFormat);
483		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_separate_depth_stencil")
484				&& m_depthFormat != GL_NONE && m_stencilFormat != GL_NONE)
485			throw tcu::NotSupportedError("Separate depth and stencil buffers not supported");
486	}
487
488	void render (tcu::Surface& dst)
489	{
490		const deUint32			colorFormat			= GL_RGBA8;
491
492		GradientShader			gradShader			(glu::TYPE_FLOAT_VEC4);
493		Texture2DShader			texShader			(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
494		FlatColorShader			flatShader			(glu::TYPE_FLOAT_VEC4);
495
496		deUint32				flatShaderID		= getCurrentContext()->createProgram(&flatShader);
497		deUint32				texShaderID			= getCurrentContext()->createProgram(&texShader);
498		deUint32				gradShaderID		= getCurrentContext()->createProgram(&gradShader);
499
500		deUint32				srcFbo				= 0;
501		deUint32				dstFbo				= 0;
502		deUint32				srcColorRbo			= 0;
503		deUint32				dstColorRbo			= 0;
504		deUint32				srcDepthRbo			= 0;
505		deUint32				srcStencilRbo		= 0;
506		deUint32				dstDepthRbo			= 0;
507		deUint32				dstStencilRbo		= 0;
508
509		// setup shaders
510		gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
511		texShader.setUniforms(*getCurrentContext(), texShaderID);
512
513		// Create framebuffers.
514		for (int ndx = 0; ndx < 2; ndx++)
515		{
516			deUint32&		fbo				= ndx ? dstFbo : srcFbo;
517			deUint32&		colorRbo		= ndx ? dstColorRbo : srcColorRbo;
518			deUint32&		depthRbo		= ndx ? dstDepthRbo : srcDepthRbo;
519			deUint32&		stencilRbo		= ndx ? dstStencilRbo : srcStencilRbo;
520			deUint32		bufs			= ndx ? m_dstBuffers : m_srcBuffers;
521			const IVec2&	size			= ndx ? m_dstSize : m_srcSize;
522
523			glGenFramebuffers(1, &fbo);
524			glGenRenderbuffers(1, &colorRbo);
525
526			glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
527			glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, size.x(), size.y());
528
529			if (m_depthFormat != GL_NONE) {
530				glGenRenderbuffers(1, &depthRbo);
531				glBindRenderbuffer(GL_RENDERBUFFER, depthRbo);
532				glRenderbufferStorage(GL_RENDERBUFFER, m_depthFormat, size.x(), size.y());
533			}
534
535			if (m_stencilFormat != GL_NONE) {
536				glGenRenderbuffers(1, &stencilRbo);
537				glBindRenderbuffer(GL_RENDERBUFFER, stencilRbo);
538				glRenderbufferStorage(GL_RENDERBUFFER, m_stencilFormat, size.x(), size.y());
539			}
540
541			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
542			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
543
544			if (bufs & GL_DEPTH_BUFFER_BIT)
545				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRbo);
546			if (bufs & GL_STENCIL_BUFFER_BIT)
547				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
548					m_stencilFormat == GL_NONE? depthRbo : stencilRbo);
549
550			checkError();
551			checkFramebufferStatus(GL_FRAMEBUFFER);
552
553			// Clear depth to 1 and stencil to 0.
554			glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
555		}
556
557		// Fill source with gradient, depth = [-1..1], stencil = 7
558		glBindFramebuffer(GL_FRAMEBUFFER, srcFbo);
559		glViewport(0, 0, m_srcSize.x(), m_srcSize.y());
560		glEnable(GL_DEPTH_TEST);
561		glEnable(GL_STENCIL_TEST);
562		glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
563		glStencilFunc(GL_ALWAYS, 7, 0xffu);
564
565		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
566
567		// Fill destination with grid pattern, depth = 0 and stencil = 1
568		{
569			const deUint32		format		= GL_RGBA;
570			const deUint32		dataType	= GL_UNSIGNED_BYTE;
571			const int			texW		= m_srcSize.x();
572			const int			texH		= m_srcSize.y();
573			deUint32			gridTex		= 0;
574			tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
575
576			tcu::fillWithGrid(data.getAccess(), 8, Vec4(0.2f, 0.7f, 0.1f, 1.0f), Vec4(0.7f, 0.1f, 0.5f, 0.8f));
577
578			glGenTextures(1, &gridTex);
579			glBindTexture(GL_TEXTURE_2D, gridTex);
580			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
581			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
582			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
583			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
584			glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
585
586			glBindFramebuffer(GL_FRAMEBUFFER, dstFbo);
587			glViewport(0, 0, m_dstSize.x(), m_dstSize.y());
588			glStencilFunc(GL_ALWAYS, 1, 0xffu);
589			sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
590		}
591
592		// Perform copy.
593		glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
594		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
595		glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(), m_dstRect.z(), m_dstRect.w(), m_copyBuffers, GL_NEAREST);
596
597		// Render blue color where depth < 0, decrement on depth failure.
598		glBindFramebuffer(GL_FRAMEBUFFER, dstFbo);
599		glViewport(0, 0, m_dstSize.x(), m_dstSize.y());
600		glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
601		glStencilFunc(GL_ALWAYS, 0, 0xffu);
602
603		flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
604		sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
605
606		if (m_dstBuffers & GL_STENCIL_BUFFER_BIT)
607		{
608			// Render green color where stencil == 6.
609			glDisable(GL_DEPTH_TEST);
610			glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
611			glStencilFunc(GL_EQUAL, 6, 0xffu);
612
613			flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
614			sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
615		}
616
617		readPixels(dst, 0, 0, m_dstSize.x(), m_dstSize.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f));
618	}
619
620private:
621	deUint32	m_depthFormat;
622	deUint32	m_stencilFormat;
623	deUint32	m_srcBuffers;
624	IVec2		m_srcSize;
625	IVec4		m_srcRect;
626	deUint32	m_dstBuffers;
627	IVec2		m_dstSize;
628	IVec4		m_dstRect;
629	deUint32	m_copyBuffers;
630};
631
632class BlitDefaultFramebufferCase : public FboTestCase
633{
634public:
635	BlitDefaultFramebufferCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 filter)
636		: FboTestCase	(context, name, desc)
637		, m_format		(format)
638		, m_filter		(filter)
639	{
640	}
641
642protected:
643	void preCheck (void)
644	{
645		if (m_context.getRenderTarget().getNumSamples() > 0)
646			throw tcu::NotSupportedError("Not supported in MSAA config");
647
648		checkFormatSupport(m_format);
649	}
650
651	virtual void render (tcu::Surface& dst)
652	{
653		tcu::TextureFormat		colorFormat		= glu::mapGLInternalFormat(m_format);
654		glu::TransferFormat		transferFmt		= glu::getTransferFormat(colorFormat);
655		GradientShader			gradShader		(glu::TYPE_FLOAT_VEC4);
656		Texture2DShader			texShader		(DataTypes() << glu::getSampler2DType(colorFormat), glu::TYPE_FLOAT_VEC4);
657		deUint32				gradShaderID	= getCurrentContext()->createProgram(&gradShader);
658		deUint32				texShaderID		= getCurrentContext()->createProgram(&texShader);
659		deUint32				fbo				= 0;
660		deUint32				tex				= 0;
661		const int				texW			= 128;
662		const int				texH			= 128;
663
664		// Setup shaders
665		gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
666		texShader.setUniforms(*getCurrentContext(), texShaderID);
667
668		// FBO
669		glGenFramebuffers(1, &fbo);
670		glGenTextures(1, &tex);
671
672		glBindTexture(GL_TEXTURE_2D, tex);
673		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
674		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
675		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	m_filter);
676		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	m_filter);
677		glTexImage2D(GL_TEXTURE_2D, 0, m_format, texW, texH, 0, transferFmt.format, transferFmt.dataType, DE_NULL);
678
679		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
680		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
681		checkError();
682		checkFramebufferStatus(GL_FRAMEBUFFER);
683
684		// Render gradient to screen.
685		glBindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
686
687		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
688
689		// Blit gradient from screen to fbo.
690		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
691		glBlitFramebuffer(0, 0, getWidth(), getHeight(), 0, 0, texW, texH, GL_COLOR_BUFFER_BIT, m_filter);
692
693		// Fill left half of viewport with quad that uses texture.
694		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
695		glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr());
696		sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f));
697
698		// Blit fbo to right half.
699		glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
700		glBlitFramebuffer(0, 0, texW, texH, getWidth()/2, 0, getWidth(), getHeight(), GL_COLOR_BUFFER_BIT, m_filter);
701
702		glBindFramebuffer(GL_READ_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
703		readPixels(dst, 0, 0, getWidth(), getHeight());
704	}
705
706	bool compare (const tcu::Surface& reference, const tcu::Surface& result)
707	{
708		const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_format), tcu::RGBA(12, 12, 12, 12)));
709
710		m_testCtx.getLog() << TestLog::Message << "Comparing images, threshold: " << threshold << TestLog::EndMessage;
711
712		return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
713	}
714
715protected:
716	const deUint32	m_format;
717	const deUint32	m_filter;
718};
719
720class DefaultFramebufferBlitCase : public BlitDefaultFramebufferCase
721{
722public:
723	enum BlitDirection
724	{
725		BLIT_DEFAULT_TO_TARGET,
726		BLIT_TO_DEFAULT_FROM_TARGET,
727
728		BLIT_LAST
729	};
730	enum BlitArea
731	{
732		AREA_SCALE,
733		AREA_OUT_OF_BOUNDS,
734
735		AREA_LAST
736	};
737
738	DefaultFramebufferBlitCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 filter, BlitDirection dir, BlitArea area)
739		: BlitDefaultFramebufferCase	(context, name, desc, format, filter)
740		, m_blitDir						(dir)
741		, m_blitArea					(area)
742		, m_srcRect						(-1, -1, -1, -1)
743		, m_dstRect						(-1, -1, -1, -1)
744		, m_interestingArea				(-1, -1, -1, -1)
745	{
746		DE_ASSERT(dir < BLIT_LAST);
747		DE_ASSERT(area < AREA_LAST);
748	}
749
750	void init (void)
751	{
752		// requirements
753		const int minViewportSize = 128;
754		if (m_context.getRenderTarget().getWidth() < minViewportSize || m_context.getRenderTarget().getHeight() < minViewportSize)
755			throw tcu::NotSupportedError("Viewport size " + de::toString(minViewportSize) + "x" + de::toString(minViewportSize) + " required");
756
757		// prevent viewport randoming
758		m_viewportWidth = m_context.getRenderTarget().getWidth();
759		m_viewportHeight = m_context.getRenderTarget().getHeight();
760
761		// set proper areas
762		if (m_blitArea == AREA_SCALE)
763		{
764			m_srcRect = IVec4( 10,  20,  65, 100);
765			m_dstRect = IVec4( 25,  30, 125,  94);
766			m_interestingArea = IVec4(0, 0, 128, 128);
767		}
768		else if (m_blitArea == AREA_OUT_OF_BOUNDS)
769		{
770			const tcu::IVec2 ubound = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (tcu::IVec2(128, 128)) : (tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight()));
771
772			m_srcRect = IVec4(-10, -15, 100,  63);
773			m_dstRect = ubound.swizzle(0, 1, 0, 1) + IVec4(-75, -99, 8, 16);
774			m_interestingArea = IVec4(ubound.x() - 128, ubound.y() - 128, ubound.x(), ubound.y());
775		}
776		else
777			DE_ASSERT(false);
778	}
779
780	void render (tcu::Surface& dst)
781	{
782		const tcu::TextureFormat		colorFormat		= glu::mapGLInternalFormat(m_format);
783		const glu::TransferFormat		transferFmt		= glu::getTransferFormat(colorFormat);
784		const tcu::TextureChannelClass	targetClass		= (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (tcu::getTextureChannelClass(colorFormat.type)) : (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT);
785		deUint32						fbo				= 0;
786		deUint32						fboTex			= 0;
787		const int						fboTexW			= 128;
788		const int						fboTexH			= 128;
789		const int						sourceWidth		= (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (getWidth()) : (fboTexW);
790		const int						sourceHeight	= (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (getHeight()) : (fboTexH);
791		const int						gridRenderWidth	= de::min(256, sourceWidth);
792		const int						gridRenderHeight= de::min(256, sourceHeight);
793
794		int								targetFbo		= -1;
795		int								sourceFbo		= -1;
796
797		// FBO
798		glGenFramebuffers(1, &fbo);
799		glGenTextures(1, &fboTex);
800
801		glBindTexture(GL_TEXTURE_2D, fboTex);
802		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
803		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
804		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	m_filter);
805		glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	m_filter);
806		glTexImage2D(GL_TEXTURE_2D, 0, m_format, fboTexW, fboTexH, 0, transferFmt.format, transferFmt.dataType, DE_NULL);
807
808		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
809		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
810		checkError();
811		checkFramebufferStatus(GL_FRAMEBUFFER);
812
813		targetFbo = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (fbo) : (m_context.getRenderContext().getDefaultFramebuffer());
814		sourceFbo = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (m_context.getRenderContext().getDefaultFramebuffer()) : (fbo);
815
816		// Render grid to source framebuffer
817		{
818			Texture2DShader		texShader		(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
819			const deUint32		texShaderID		= getCurrentContext()->createProgram(&texShader);
820			const deUint32		internalFormat	= GL_RGBA8;
821			const deUint32		format			= GL_RGBA;
822			const deUint32		dataType		= GL_UNSIGNED_BYTE;
823			const int			gridTexW		= 128;
824			const int			gridTexH		= 128;
825			deUint32			gridTex			= 0;
826			tcu::TextureLevel	data			(glu::mapGLTransferFormat(format, dataType), gridTexW, gridTexH, 1);
827
828			tcu::fillWithGrid(data.getAccess(), 9, tcu::Vec4(0.9f, 0.5f, 0.1f, 0.9f), tcu::Vec4(0.2f, 0.8f, 0.2f, 0.7f));
829
830			glGenTextures(1, &gridTex);
831			glBindTexture(GL_TEXTURE_2D, gridTex);
832			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
833			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
834			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
835			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
836			glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, gridTexW, gridTexH, 0, format, dataType, data.getAccess().getDataPtr());
837
838			glBindFramebuffer(GL_FRAMEBUFFER, sourceFbo);
839			glViewport(0, 0, gridRenderWidth, gridRenderHeight);
840			glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr());
841
842			texShader.setUniforms(*getCurrentContext(), texShaderID);
843			sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
844			glUseProgram(0);
845		}
846
847		// Blit source framebuffer to destination
848
849		glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFbo);
850		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFbo);
851		checkError();
852
853		if (targetClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || targetClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || targetClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
854			glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 1.0f, 0.0f, 1.0f).getPtr());
855		else if (targetClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
856			glClearBufferiv(GL_COLOR, 0, IVec4(0, 0, 0, 0).getPtr());
857		else if (targetClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
858			glClearBufferuiv(GL_COLOR, 0, UVec4(0, 0, 0, 0).getPtr());
859		else
860			DE_ASSERT(false);
861
862		glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(), m_dstRect.z(), m_dstRect.w(), GL_COLOR_BUFFER_BIT, m_filter);
863		checkError();
864
865		// Read target
866
867		glBindFramebuffer(GL_FRAMEBUFFER, targetFbo);
868
869		if (m_blitDir == BLIT_TO_DEFAULT_FROM_TARGET)
870			readPixels(dst, m_interestingArea.x(), m_interestingArea.y(), m_interestingArea.z() - m_interestingArea.x(), m_interestingArea.w() - m_interestingArea.y());
871		else
872			readPixels(dst, m_interestingArea.x(), m_interestingArea.y(), m_interestingArea.z() - m_interestingArea.x(), m_interestingArea.w() - m_interestingArea.y(), colorFormat, tcu::Vec4(1.0f), tcu::Vec4(0.0f));
873
874		checkError();
875	}
876
877private:
878	const BlitDirection	m_blitDir;
879	const BlitArea		m_blitArea;
880	tcu::IVec4			m_srcRect;
881	tcu::IVec4			m_dstRect;
882	tcu::IVec4			m_interestingArea;
883};
884
885FramebufferBlitTests::FramebufferBlitTests (Context& context)
886	: TestCaseGroup(context, "blit", "Framebuffer blit tests")
887{
888}
889
890FramebufferBlitTests::~FramebufferBlitTests (void)
891{
892}
893
894void FramebufferBlitTests::init (void)
895{
896	static const deUint32 colorFormats[] =
897	{
898		// RGBA formats
899		GL_RGBA32I,
900		GL_RGBA32UI,
901		GL_RGBA16I,
902		GL_RGBA16UI,
903		GL_RGBA8,
904		GL_RGBA8I,
905		GL_RGBA8UI,
906		GL_SRGB8_ALPHA8,
907		GL_RGB10_A2,
908		GL_RGB10_A2UI,
909		GL_RGBA4,
910		GL_RGB5_A1,
911
912		// RGB formats
913		GL_RGB8,
914		GL_RGB565,
915
916		// RG formats
917		GL_RG32I,
918		GL_RG32UI,
919		GL_RG16I,
920		GL_RG16UI,
921		GL_RG8,
922		GL_RG8I,
923		GL_RG8UI,
924
925		// R formats
926		GL_R32I,
927		GL_R32UI,
928		GL_R16I,
929		GL_R16UI,
930		GL_R8,
931		GL_R8I,
932		GL_R8UI,
933
934		// GL_EXT_color_buffer_float
935		GL_RGBA32F,
936		GL_RGBA16F,
937		GL_R11F_G11F_B10F,
938		GL_RG32F,
939		GL_RG16F,
940		GL_R32F,
941		GL_R16F
942	};
943
944	static const deUint32 depthStencilFormats[] =
945	{
946		GL_NONE,
947		GL_DEPTH_COMPONENT32F,
948		GL_DEPTH_COMPONENT24,
949		GL_DEPTH_COMPONENT16,
950		GL_DEPTH32F_STENCIL8,
951		GL_DEPTH24_STENCIL8
952	};
953
954	static const deUint32 stencilFormats[] =
955	{
956		GL_NONE,
957		GL_STENCIL_INDEX8
958	};
959
960	// .rect
961	{
962		static const struct
963		{
964			const char*	name;
965			IVec4		srcRect;
966			IVec4		dstRect;
967		} copyRects[] =
968		{
969			{ "basic",						IVec4( 10,  20,  65, 100),		IVec4( 45,   5, 100,  85) },
970			{ "scale",						IVec4( 10,  20,  65, 100),		IVec4( 25,  30, 125,  94) },
971			{ "out_of_bounds",				IVec4(-10, -15, 100,  63),		IVec4( 50,  30, 136, 144) },
972		};
973
974		static const struct
975		{
976			const char*	name;
977			IVec4		srcRect;
978			IVec4		dstRect;
979		} filterConsistencyRects[] =
980		{
981			{ "mag",						IVec4( 20,  10,  74, 88),		IVec4( 10,  10,  91, 101) },
982			{ "min",						IVec4( 10,  20,  78, 100),		IVec4( 20,  20,  71,  80) },
983			{ "out_of_bounds_mag",			IVec4( 21,  10,  73, 82),		IVec4( 11,  43, 141, 151) },
984			{ "out_of_bounds_min",			IVec4( 11,  21,  77, 97),		IVec4( 80,  82, 135, 139) },
985		};
986
987		static const struct
988		{
989			const char* name;
990			IVec4		srcSwizzle;
991			IVec4		dstSwizzle;
992		} swizzles[] =
993		{
994			{ DE_NULL,				IVec4(0,1,2,3),	IVec4(0,1,2,3) },
995			{ "reverse_src_x",		IVec4(2,1,0,3), IVec4(0,1,2,3) },
996			{ "reverse_src_y",		IVec4(0,3,2,1), IVec4(0,1,2,3) },
997			{ "reverse_dst_x",		IVec4(0,1,2,3), IVec4(2,1,0,3) },
998			{ "reverse_dst_y",		IVec4(0,1,2,3), IVec4(0,3,2,1) },
999			{ "reverse_src_dst_x",	IVec4(2,1,0,3), IVec4(2,1,0,3) },
1000			{ "reverse_src_dst_y",	IVec4(0,3,2,1), IVec4(0,3,2,1) }
1001		};
1002
1003		const IVec2 srcSize(127, 119);
1004		const IVec2 dstSize(132, 128);
1005
1006		// Blit rectangle tests.
1007		tcu::TestCaseGroup* rectGroup = new tcu::TestCaseGroup(m_testCtx, "rect", "Blit rectangle tests");
1008		addChild(rectGroup);
1009		for (int rectNdx = 0; rectNdx < DE_LENGTH_OF_ARRAY(copyRects); rectNdx++)
1010		{
1011			for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++)
1012			{
1013				string		name	= string(copyRects[rectNdx].name) + (swizzles[swzNdx].name ? (string("_") + swizzles[swzNdx].name) : string());
1014				IVec4		srcSwz	= swizzles[swzNdx].srcSwizzle;
1015				IVec4		dstSwz	= swizzles[swzNdx].dstSwizzle;
1016				IVec4		srcRect	= copyRects[rectNdx].srcRect.swizzle(srcSwz[0], srcSwz[1], srcSwz[2], srcSwz[3]);
1017				IVec4		dstRect	= copyRects[rectNdx].dstRect.swizzle(dstSwz[0], dstSwz[1], dstSwz[2], dstSwz[3]);
1018
1019				rectGroup->addChild(new BlitRectCase(m_context, (name + "_nearest").c_str(),	"", GL_NEAREST,	srcSize, srcRect, dstSize, dstRect));
1020				rectGroup->addChild(new BlitRectCase(m_context, (name + "_linear").c_str(),		"", GL_LINEAR,	srcSize, srcRect, dstSize, dstRect));
1021			}
1022		}
1023
1024		// Nearest filter tests
1025		for (int rectNdx = 0; rectNdx < DE_LENGTH_OF_ARRAY(filterConsistencyRects); rectNdx++)
1026		{
1027			for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++)
1028			{
1029				string		name	= string("nearest_consistency_") + filterConsistencyRects[rectNdx].name + (swizzles[swzNdx].name ? (string("_") + swizzles[swzNdx].name) : string());
1030				IVec4		srcSwz	= swizzles[swzNdx].srcSwizzle;
1031				IVec4		dstSwz	= swizzles[swzNdx].dstSwizzle;
1032				IVec4		srcRect	= filterConsistencyRects[rectNdx].srcRect.swizzle(srcSwz[0], srcSwz[1], srcSwz[2], srcSwz[3]);
1033				IVec4		dstRect	= filterConsistencyRects[rectNdx].dstRect.swizzle(dstSwz[0], dstSwz[1], dstSwz[2], dstSwz[3]);
1034
1035				rectGroup->addChild(new BlitNearestFilterConsistencyCase(m_context, name.c_str(), "Test consistency of the nearest filter", srcSize, srcRect, dstSize, dstRect));
1036			}
1037		}
1038	}
1039
1040	// .conversion
1041	{
1042		tcu::TestCaseGroup* conversionGroup = new tcu::TestCaseGroup(m_testCtx, "conversion", "Color conversion tests");
1043		addChild(conversionGroup);
1044
1045		for (int srcFmtNdx = 0; srcFmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); srcFmtNdx++)
1046		{
1047			for (int dstFmtNdx = 0; dstFmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); dstFmtNdx++)
1048			{
1049				deUint32					srcFormat	= colorFormats[srcFmtNdx];
1050				tcu::TextureFormat			srcTexFmt	= glu::mapGLInternalFormat(srcFormat);
1051				tcu::TextureChannelClass	srcType		= tcu::getTextureChannelClass(srcTexFmt.type);
1052				deUint32					dstFormat	= colorFormats[dstFmtNdx];
1053				tcu::TextureFormat			dstTexFmt	= glu::mapGLInternalFormat(dstFormat);
1054				tcu::TextureChannelClass	dstType		= tcu::getTextureChannelClass(dstTexFmt.type);
1055
1056				if (((srcType == tcu::TEXTURECHANNELCLASS_FLOATING_POINT || srcType == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) !=
1057					 (dstType == tcu::TEXTURECHANNELCLASS_FLOATING_POINT || dstType == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)) ||
1058					((srcType == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER) != (dstType == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)) ||
1059					((srcType == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) != (dstType == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)))
1060					continue; // Conversion not supported.
1061
1062				string						name		= string(getFormatName(srcFormat)) + "_to_" + getFormatName(dstFormat);
1063
1064				conversionGroup->addChild(new BlitColorConversionCase(m_context, name.c_str(), "", srcFormat, dstFormat, IVec2(127, 113)));
1065			}
1066		}
1067	}
1068
1069	// .depth_stencil
1070	{
1071		tcu::TestCaseGroup* depthStencilGroup = new tcu::TestCaseGroup(m_testCtx, "depth_stencil", "Depth and stencil blits");
1072		addChild(depthStencilGroup);
1073
1074		for (int dFmtNdx = 0; dFmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); dFmtNdx++)
1075		{
1076			for (int sFmtNdx = 0; sFmtNdx < DE_LENGTH_OF_ARRAY(stencilFormats); sFmtNdx++)
1077			{
1078				deUint32	depthFormat		= depthStencilFormats[dFmtNdx];
1079				deUint32	stencilFormat	= stencilFormats[sFmtNdx];
1080				bool		depth			= false;
1081				bool		stencil			= false;
1082				string		fmtName;
1083
1084				if (depthFormat != GL_NONE)
1085				{
1086					tcu::TextureFormat info = glu::mapGLInternalFormat(depthFormat);
1087
1088					fmtName += getFormatName(depthFormat);
1089					if (info.order == tcu::TextureFormat::D || info.order == tcu::TextureFormat::DS)
1090						depth = true;
1091					if (info.order == tcu::TextureFormat::DS)
1092						stencil = true;
1093				}
1094
1095				if (stencilFormat != GL_NONE)
1096				{
1097					// Do not try separate stencil along with a combined depth/stencil
1098					if (stencil)
1099						continue;
1100
1101					if (depthFormat != GL_NONE)
1102						fmtName += "_";
1103					fmtName += getFormatName(stencilFormat);
1104					stencil = true;
1105				}
1106
1107				if (!stencil && !depth)
1108					continue;
1109
1110				deUint32 buffers = (depth ? GL_DEPTH_BUFFER_BIT : 0) | (stencil ? GL_STENCIL_BUFFER_BIT : 0);
1111
1112				depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_basic").c_str(), "", depthFormat, stencilFormat, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers));
1113				depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_scale").c_str(), "", depthFormat, stencilFormat, buffers, IVec2(127, 119), IVec4(10, 30, 100, 70), buffers, IVec2(111, 130), IVec4(20, 5, 80, 130), buffers));
1114
1115				if (depth && stencil)
1116				{
1117					depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_depth_only").c_str(),		"", depthFormat, stencilFormat, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), GL_DEPTH_BUFFER_BIT));
1118					depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_stencil_only").c_str(),	"", depthFormat, stencilFormat, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), GL_STENCIL_BUFFER_BIT));
1119				}
1120			}
1121		}
1122	}
1123
1124	// .default_framebuffer
1125	{
1126		static const struct
1127		{
1128			const char*								name;
1129			DefaultFramebufferBlitCase::BlitArea	area;
1130		} areas[] =
1131		{
1132			{ "scale",						DefaultFramebufferBlitCase::AREA_SCALE			},
1133			{ "out_of_bounds",				DefaultFramebufferBlitCase::AREA_OUT_OF_BOUNDS	},
1134		};
1135
1136		tcu::TestCaseGroup* defaultFbGroup = new tcu::TestCaseGroup(m_testCtx, "default_framebuffer", "Blits with default framebuffer");
1137		addChild(defaultFbGroup);
1138
1139		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1140		{
1141			const deUint32					format		= colorFormats[fmtNdx];
1142			const tcu::TextureFormat		texFmt		= glu::mapGLInternalFormat(format);
1143			const tcu::TextureChannelClass	fmtClass	= tcu::getTextureChannelClass(texFmt.type);
1144			const deUint32					filter		= glu::isGLInternalColorFormatFilterable(format) ? GL_LINEAR : GL_NEAREST;
1145			const bool						filterable	= glu::isGLInternalColorFormatFilterable(format);
1146
1147			if (fmtClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT &&
1148				fmtClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT &&
1149				fmtClass != tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT)
1150				continue; // Conversion not supported.
1151
1152			defaultFbGroup->addChild(new BlitDefaultFramebufferCase(m_context, getFormatName(format), "", format, filter));
1153
1154			for (int areaNdx = 0; areaNdx < DE_LENGTH_OF_ARRAY(areas); areaNdx++)
1155			{
1156				const string	name				= string(areas[areaNdx].name);
1157				const bool		addLinear			= filterable;
1158				const bool		addNearest			= !addLinear || (areas[areaNdx].area != DefaultFramebufferBlitCase::AREA_OUT_OF_BOUNDS); // No need to check out-of-bounds with different filtering
1159
1160				if (addNearest)
1161				{
1162					defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_nearest_" + name + "_blit_from_default").c_str(), "", format, GL_NEAREST, DefaultFramebufferBlitCase::BLIT_DEFAULT_TO_TARGET, areas[areaNdx].area));
1163					defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_nearest_" + name + "_blit_to_default").c_str(), "", format, GL_NEAREST, DefaultFramebufferBlitCase::BLIT_TO_DEFAULT_FROM_TARGET, areas[areaNdx].area));
1164				}
1165
1166				if (addLinear)
1167				{
1168					defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_linear_" + name + "_blit_from_default").c_str(), "", format, GL_LINEAR, DefaultFramebufferBlitCase::BLIT_DEFAULT_TO_TARGET, areas[areaNdx].area));
1169					defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_linear_" + name + "_blit_to_default").c_str(), "", format, GL_LINEAR, DefaultFramebufferBlitCase::BLIT_TO_DEFAULT_FROM_TARGET, areas[areaNdx].area));
1170				}
1171			}
1172		}
1173	}
1174}
1175
1176} // Functional
1177} // gles3
1178} // deqp
1179