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