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