Home | History | Annotate | Download | only in functional
      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 Screen clearing test.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3fColorClearTest.hpp"
     25 #include "tcuRGBA.hpp"
     26 #include "tcuSurface.hpp"
     27 #include "tcuTestLog.hpp"
     28 #include "gluRenderContext.hpp"
     29 #include "gluPixelTransfer.hpp"
     30 #include "tcuVector.hpp"
     31 #include "tcuRenderTarget.hpp"
     32 #include "deRandom.hpp"
     33 #include "deInt32.h"
     34 
     35 #include "glwFunctions.hpp"
     36 #include "glwEnums.hpp"
     37 
     38 #include <vector>
     39 
     40 using tcu::RGBA;
     41 using tcu::Surface;
     42 using tcu::TestLog;
     43 
     44 using namespace std;
     45 
     46 namespace deqp
     47 {
     48 namespace gles3
     49 {
     50 namespace Functional
     51 {
     52 
     53 class ColorClearCase : public TestCase
     54 {
     55 public:
     56 	ColorClearCase(Context& context, const char* name, int numIters, int numClearsMin, int numClearsMax, bool testAlpha, bool testScissoring, bool testColorMasks, bool firstClearFull)
     57 		: TestCase			(context, name, name)
     58 		, m_numIters		(numIters)
     59 		, m_numClearsMin	(numClearsMin)
     60 		, m_numClearsMax	(numClearsMax)
     61 		, m_testAlpha		(testAlpha)
     62 		, m_testScissoring	(testScissoring)
     63 		, m_testColorMasks	(testColorMasks)
     64 		, m_firstClearFull	(firstClearFull)
     65 	{
     66 		m_curIter = 0;
     67 	}
     68 
     69 	virtual ~ColorClearCase (void)
     70 	{
     71 	}
     72 
     73 	virtual IterateResult iterate (void);
     74 
     75 private:
     76 	const int		m_numIters;
     77 	const int		m_numClearsMin;
     78 	const int		m_numClearsMax;
     79 	const bool		m_testAlpha;
     80 	const bool		m_testScissoring;
     81 	const bool		m_testColorMasks;
     82 	const bool		m_firstClearFull;
     83 
     84 	int				m_curIter;
     85 };
     86 
     87 class ClearInfo
     88 {
     89 public:
     90 	ClearInfo (const tcu::IVec4& rect, deUint8 colorMask, tcu::RGBA color)
     91 		: m_rect(rect), m_colorMask(colorMask), m_color(color)
     92 	{
     93 	}
     94 
     95 	tcu::IVec4		m_rect;
     96 	deUint8			m_colorMask;
     97 	tcu::RGBA		m_color;
     98 };
     99 
    100 TestCase::IterateResult ColorClearCase::iterate (void)
    101 {
    102 	TestLog&					log						= m_testCtx.getLog();
    103 	const glw::Functions&		gl						= m_context.getRenderContext().getFunctions();
    104 	const tcu::RenderTarget&	renderTarget			= m_context.getRenderTarget();
    105 	const tcu::PixelFormat&		pixelFormat				= renderTarget.getPixelFormat();
    106 	const int					targetWidth				= renderTarget.getWidth();
    107 	const int					targetHeight			= renderTarget.getHeight();
    108 	const int					numPixels				= targetWidth * targetHeight;
    109 
    110 	de::Random					rnd						(deInt32Hash(m_curIter));
    111 	vector<deUint8>				pixelKnownChannelMask	(numPixels, 0);
    112 	Surface						refImage				(targetWidth, targetHeight);
    113 	Surface						resImage				(targetWidth, targetHeight);
    114 	Surface						diffImage				(targetWidth, targetHeight);
    115 	int							numClears				= rnd.getUint32() % (m_numClearsMax + 1 - m_numClearsMin) + m_numClearsMin;
    116 	std::vector<ClearInfo>		clearOps;
    117 
    118 	if (m_testScissoring)
    119 		gl.enable(GL_SCISSOR_TEST);
    120 
    121 	for (int clearNdx = 0; clearNdx < numClears; clearNdx++)
    122 	{
    123 		// Rectangle.
    124 		int clearX;
    125 		int clearY;
    126 		int clearWidth;
    127 		int clearHeight;
    128 		if (!m_testScissoring || (clearNdx == 0 && m_firstClearFull))
    129 		{
    130 			clearX		= 0;
    131 			clearY		= 0;
    132 			clearWidth	= targetWidth;
    133 			clearHeight	= targetHeight;
    134 		}
    135 		else
    136 		{
    137 			clearX		= (rnd.getUint32() % (2*targetWidth)) - targetWidth;
    138 			clearY		= (rnd.getUint32() % (2*targetHeight)) - targetHeight;
    139 			clearWidth	= (rnd.getUint32() % targetWidth);
    140 			clearHeight	= (rnd.getUint32() % targetHeight);
    141 		}
    142 		gl.scissor(clearX, clearY, clearWidth, clearHeight);
    143 
    144 		// Color.
    145 		int		r = (int)(rnd.getUint32() & 0xFF);
    146 		int		g = (int)(rnd.getUint32() & 0xFF);
    147 		int		b = (int)(rnd.getUint32() & 0xFF);
    148 		int		a = m_testAlpha ? (int)(rnd.getUint32() & 0xFF) : 0xFF;
    149 		RGBA	clearCol(r, g, b, a);
    150 		gl.clearColor(float(r)/255.0f, float(g)/255.0f, float(b)/255.0f, float(a)/255.0f);
    151 
    152 		// Mask.
    153 		deUint8	clearMask;
    154 		if (!m_testColorMasks || (clearNdx == 0 && m_firstClearFull))
    155 			clearMask = 0xF;
    156 		else
    157 			clearMask = (rnd.getUint32() & 0xF);
    158 		gl.colorMask((clearMask&0x1) != 0, (clearMask&0x2) != 0, (clearMask&0x4) != 0, (clearMask&0x8) != 0);
    159 
    160 		// Clear & store op.
    161 		gl.clear(GL_COLOR_BUFFER_BIT);
    162 		clearOps.push_back(ClearInfo(tcu::IVec4(clearX, clearY, clearWidth, clearHeight), clearMask, clearCol));
    163 
    164 		// Let watchdog know we're alive.
    165 		m_testCtx.touchWatchdog();
    166 	}
    167 
    168 	// Compute reference image.
    169 	{
    170 		for (int y = 0; y < targetHeight; y++)
    171 		{
    172 			std::vector<ClearInfo>	scanlineClearOps;
    173 
    174 			// Find all rectangles affecting this scanline.
    175 			for (int opNdx = 0; opNdx < (int)clearOps.size(); opNdx++)
    176 			{
    177 				ClearInfo& op = clearOps[opNdx];
    178 				if (de::inBounds(y, op.m_rect.y(), op.m_rect.y()+op.m_rect.w()))
    179 					scanlineClearOps.push_back(op);
    180 			}
    181 
    182 			// Compute reference for scanline.
    183 			int x = 0;
    184 			while (x < targetWidth)
    185 			{
    186 				tcu::RGBA	spanColor;
    187 				deUint8		spanKnownMask	= 0;
    188 				int			spanLength		= (targetWidth - x);
    189 
    190 				for (int opNdx = (int)scanlineClearOps.size() - 1; opNdx >= 0; opNdx--)
    191 				{
    192 					const ClearInfo& op = scanlineClearOps[opNdx];
    193 
    194 					if (de::inBounds(x, op.m_rect.x(), op.m_rect.x()+op.m_rect.z()) &&
    195 						de::inBounds(y, op.m_rect.y(), op.m_rect.y()+op.m_rect.w()))
    196 					{
    197 						// Compute span length until end of given rectangle.
    198 						spanLength = deMin32(spanLength, op.m_rect.x() + op.m_rect.z() - x);
    199 
    200 						tcu::RGBA	clearCol	= op.m_color;
    201 						deUint8		clearMask	= op.m_colorMask;
    202 						if ((clearMask & 0x1) && !(spanKnownMask & 0x1)) spanColor.setRed(clearCol.getRed());
    203 						if ((clearMask & 0x2) && !(spanKnownMask & 0x2)) spanColor.setGreen(clearCol.getGreen());
    204 						if ((clearMask & 0x4) && !(spanKnownMask & 0x4)) spanColor.setBlue(clearCol.getBlue());
    205 						if ((clearMask & 0x8) && !(spanKnownMask & 0x8)) spanColor.setAlpha(clearCol.getAlpha());
    206 						spanKnownMask |= clearMask;
    207 
    208 						// Break if have all colors.
    209 						if (spanKnownMask == 0xF)
    210 							break;
    211 					}
    212 					else if (op.m_rect.x() > x)
    213 						spanLength = deMin32(spanLength, op.m_rect.x() - x);
    214 				}
    215 
    216 				// Set reference alpha channel to 0xFF, if no alpha in target.
    217 				if (pixelFormat.alphaBits == 0)
    218 					spanColor.setAlpha(0xFF);
    219 
    220 				// Fill the span.
    221 				for (int ndx = 0; ndx < spanLength; ndx++)
    222 				{
    223 					refImage.setPixel(x + ndx, y, spanColor);
    224 					pixelKnownChannelMask[y*targetWidth + x + ndx] |= spanKnownMask;
    225 				}
    226 
    227 				x += spanLength;
    228 			}
    229 		}
    230 	}
    231 
    232 	glu::readPixels(m_context.getRenderContext(), 0, 0, resImage.getAccess());
    233 	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels");
    234 
    235 	// Compute difference image.
    236 	RGBA colorThreshold = pixelFormat.getColorThreshold();
    237 	RGBA matchColor(0, 255, 0, 255);
    238 	RGBA diffColor(255, 0, 0, 255);
    239 	RGBA maxDiff(0, 0, 0, 0);
    240 	bool isImageOk = true;
    241 
    242 	if (gl.isEnabled(GL_DITHER))
    243 	{
    244 		colorThreshold.setRed(colorThreshold.getRed() + 1);
    245 		colorThreshold.setGreen(colorThreshold.getGreen() + 1);
    246 		colorThreshold.setBlue(colorThreshold.getBlue() + 1);
    247 		colorThreshold.setAlpha(colorThreshold.getAlpha() + 1);
    248 	}
    249 
    250 	for (int y = 0; y < targetHeight; y++)
    251 	for (int x = 0; x < targetWidth; x++)
    252 	{
    253 		int			offset		= (y*targetWidth + x);
    254 		RGBA		refRGBA		= refImage.getPixel(x, y);
    255 		RGBA		resRGBA		= resImage.getPixel(x, y);
    256 		deUint8		colMask		= pixelKnownChannelMask[offset];
    257 		RGBA		diff		= computeAbsDiffMasked(refRGBA, resRGBA, colMask);
    258 		bool		isPixelOk	= diff.isBelowThreshold(colorThreshold);
    259 
    260 		diffImage.setPixel(x, y, isPixelOk ? matchColor : diffColor);
    261 
    262 		isImageOk	= isImageOk && isPixelOk;
    263 		maxDiff		= max(maxDiff, diff);
    264 	}
    265 
    266 	if (isImageOk)
    267 	{
    268 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    269 	}
    270 	else
    271 	{
    272 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    273 
    274 		m_testCtx.getLog() << tcu::TestLog::Message << "Image comparison failed, max diff = " << maxDiff << ", threshold = " << colorThreshold << tcu::TestLog::EndMessage;
    275 
    276 		log << TestLog::ImageSet("Result", "Resulting framebuffer")
    277 			<< TestLog::Image("Result",		"Resulting framebuffer",	resImage)
    278 			<< TestLog::Image("Reference",	"Reference image",			refImage)
    279 			<< TestLog::Image("DiffMask",	"Failing pixels",			diffImage)
    280 			<< TestLog::EndImageSet;
    281 		return TestCase::STOP;
    282 	}
    283 
    284 	bool isFinal = (++m_curIter == m_numIters);
    285 
    286 	// On final frame, dump images.
    287 	if (isFinal)
    288 	{
    289 		log << TestLog::ImageSet("Result", "Resulting framebuffer")
    290 			<< TestLog::Image("Result",		"Resulting framebuffer",	resImage)
    291 			<< TestLog::EndImageSet;
    292 	}
    293 
    294 	return isFinal ? TestCase::STOP : TestCase::CONTINUE;
    295 }
    296 
    297 ColorClearTest::ColorClearTest (Context& context) : TestCaseGroup(context, "color_clear", "Color Clear Tests")
    298 {
    299 }
    300 
    301 ColorClearTest::~ColorClearTest (void)
    302 {
    303 }
    304 
    305 void ColorClearTest::init (void)
    306 {
    307 	//										name					iters,	#..#,		alpha?,	scissor,masks,	1stfull?
    308 	addChild(new ColorClearCase(m_context, "single_rgb",			30,		1,3,		false,	false,	false,	true	));
    309 	addChild(new ColorClearCase(m_context, "single_rgba",			30,		1,3,		true,	false,	false,	true	));
    310 	addChild(new ColorClearCase(m_context, "multiple_rgb",			15,		4,20,		false,	false,	false,	true	));
    311 	addChild(new ColorClearCase(m_context, "multiple_rgba",			15,		4,20,		true,	false,	false,	true	));
    312 	addChild(new ColorClearCase(m_context, "long_rgb",				2,		100,500,	false,	false,	false,	true	));
    313 	addChild(new ColorClearCase(m_context, "long_rgba",				2,		100,500,	true,	false,	false,	true	));
    314 	addChild(new ColorClearCase(m_context, "subclears_rgb",			15,		4,30,		false,	false,	false,	false	));
    315 	addChild(new ColorClearCase(m_context, "subclears_rgba",		15,		4,30,		true,	false,	false,	false	));
    316 	addChild(new ColorClearCase(m_context, "short_scissored_rgb",	30,		2,4,		false,	true,	false,	true	));
    317 	addChild(new ColorClearCase(m_context, "scissored_rgb",			15,		4,30,		false,	true,	false,	true	));
    318 	addChild(new ColorClearCase(m_context, "scissored_rgba",		15,		4,30,		true,	true,	false,	true	));
    319 	addChild(new ColorClearCase(m_context, "masked_rgb",			15,		4,30,		false,	true,	false,	true	));
    320 	addChild(new ColorClearCase(m_context, "masked_rgba",			15,		4,30,		true,	true,	false,	true	));
    321 	addChild(new ColorClearCase(m_context, "masked_scissored_rgb",	15,		4,30,		false,	true,	true,	true	));
    322 	addChild(new ColorClearCase(m_context, "masked_scissored_rgba",	15,		4,30,		true,	true,	true,	true	));
    323 	addChild(new ColorClearCase(m_context, "complex_rgb",			15,		5,50,		false,	true,	true,	false	));
    324 	addChild(new ColorClearCase(m_context, "complex_rgba",			15,		5,50,		true,	true,	true,	false	));
    325 	addChild(new ColorClearCase(m_context, "long_masked_rgb",		2,		100,500,	false,	true,	true,	true	));
    326 	addChild(new ColorClearCase(m_context, "long_masked_rgba",		2,		100,500,	true,	true,	true,	true	));
    327 }
    328 
    329 } // Functional
    330 } // gles3
    331 } // deqp
    332