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