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 GLSL ES 1.0 gl_FragData[] tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3fShaderFragDataTests.hpp"
     25 
     26 #include "glsShaderLibrary.hpp"
     27 
     28 #include "gluRenderContext.hpp"
     29 #include "gluShaderProgram.hpp"
     30 #include "gluDrawUtil.hpp"
     31 #include "gluPixelTransfer.hpp"
     32 #include "gluObjectWrapper.hpp"
     33 
     34 #include "tcuRenderTarget.hpp"
     35 #include "tcuStringTemplate.hpp"
     36 #include "tcuTestLog.hpp"
     37 #include "tcuSurface.hpp"
     38 
     39 #include "glwFunctions.hpp"
     40 #include "glwEnums.hpp"
     41 
     42 namespace deqp
     43 {
     44 namespace gles3
     45 {
     46 namespace Functional
     47 {
     48 
     49 using std::string;
     50 using tcu::TestLog;
     51 
     52 namespace
     53 {
     54 
     55 enum IndexExprType
     56 {
     57 	INDEX_EXPR_STATIC	= 0,
     58 	INDEX_EXPR_UNIFORM,
     59 	INDEX_EXPR_DYNAMIC,
     60 
     61 	INDEX_EXPR_TYPE_LAST
     62 };
     63 
     64 static bool compareSingleColor (tcu::TestLog& log, const tcu::Surface& surface, tcu::RGBA expectedColor, tcu::RGBA threshold)
     65 {
     66 	const int	maxPrints			= 10;
     67 	int			numFailedPixels		= 0;
     68 
     69 	log << TestLog::Message << "Expecting " << expectedColor << " with threshold " << threshold << TestLog::EndMessage;
     70 
     71 	for (int y = 0; y < surface.getHeight(); y++)
     72 	{
     73 		for (int x = 0; x < surface.getWidth(); x++)
     74 		{
     75 			const tcu::RGBA		resultColor		= surface.getPixel(x, y);
     76 			const bool			isOk			= compareThreshold(resultColor, expectedColor, threshold);
     77 
     78 			if (!isOk)
     79 			{
     80 				if (numFailedPixels < maxPrints)
     81 					log << TestLog::Message << "ERROR: Got " << resultColor << " at (" << x << ", " << y << ")!" << TestLog::EndMessage;
     82 				else if (numFailedPixels == maxPrints)
     83 					log << TestLog::Message << "..." << TestLog::EndMessage;
     84 
     85 				numFailedPixels += 1;
     86 			}
     87 		}
     88 	}
     89 
     90 	if (numFailedPixels > 0)
     91 	{
     92 		log << TestLog::Message << "Found " << numFailedPixels << " invalid pixels, comparison FAILED!" << TestLog::EndMessage;
     93 		log << TestLog::Image("ResultImage", "Result Image", surface);
     94 		return false;
     95 	}
     96 	else
     97 	{
     98 		log << TestLog::Message << "Image comparison passed." << TestLog::EndMessage;
     99 		return true;
    100 	}
    101 }
    102 
    103 class FragDataIndexingCase : public TestCase
    104 {
    105 public:
    106 	FragDataIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType)
    107 		: TestCase			(context, name, description)
    108 		, m_indexExprType	(indexExprType)
    109 	{
    110 	}
    111 
    112 	static glu::ProgramSources genSources (const IndexExprType indexExprType)
    113 	{
    114 		const char* const	fragIndexExpr	= indexExprType == INDEX_EXPR_STATIC	? "0"				:
    115 											  indexExprType == INDEX_EXPR_UNIFORM	? "u_index"			:
    116 											  indexExprType == INDEX_EXPR_DYNAMIC	? "int(v_index)"	: DE_NULL;
    117 		glu::ProgramSources	sources;
    118 
    119 		DE_ASSERT(fragIndexExpr);
    120 
    121 		sources << glu::VertexSource(
    122 			"attribute highp vec4 a_position;\n"
    123 			"attribute highp float a_index;\n"
    124 			"attribute highp vec4 a_color;\n"
    125 			"varying mediump float v_index;\n"
    126 			"varying mediump vec4 v_color;\n"
    127 			"void main (void)\n"
    128 			"{\n"
    129 			"	gl_Position = a_position;\n"
    130 			"	v_color = a_color;\n"
    131 			"	v_index = a_index;\n"
    132 			"}\n");
    133 
    134 		sources << glu::FragmentSource(string(
    135 			"varying mediump vec4 v_color;\n"
    136 			"varying mediump float v_index;\n"
    137 			"uniform mediump int u_index;\n"
    138 			"void main (void)\n"
    139 			"{\n"
    140 			"	gl_FragData[") + fragIndexExpr + "] = v_color;\n"
    141 			"}\n");
    142 
    143 		return sources;
    144 	}
    145 
    146 	IterateResult iterate (void)
    147 	{
    148 		const glu::RenderContext&		renderCtx		= m_context.getRenderContext();
    149 		const glw::Functions&			gl				= renderCtx.getFunctions();
    150 		const glu::ShaderProgram		program			(renderCtx, genSources(m_indexExprType));
    151 		const int						viewportW		= de::min(renderCtx.getRenderTarget().getWidth(), 128);
    152 		const int						viewportH		= de::min(renderCtx.getRenderTarget().getHeight(), 128);
    153 
    154 		const float positions[] =
    155 		{
    156 			-1.0f, -1.0f,
    157 			+1.0f, -1.0f,
    158 			-1.0f, +1.0f,
    159 			+1.0f, +1.0f
    160 		};
    161 		const float colors[] =
    162 		{
    163 			0.0f, 1.0f, 0.0f, 1.0f,
    164 			0.0f, 1.0f, 0.0f, 1.0f,
    165 			0.0f, 1.0f, 0.0f, 1.0f,
    166 			0.0f, 1.0f, 0.0f, 1.0f
    167 		};
    168 		const float		indexValues[]	= { 0.0f, 0.0f, 0.0f, 0.0f };
    169 		const deUint8	indices[]		= { 0, 1, 2, 2, 1, 3 };
    170 
    171 		const glu::VertexArrayBinding vertexArrays[] =
    172 		{
    173 			glu::va::Float("a_position",	2, 4, 0, &positions[0]),
    174 			glu::va::Float("a_color",		4, 4, 0, &colors[0]),
    175 			glu::va::Float("a_index",		1, 4, 0, &indexValues[0])
    176 		};
    177 
    178 		m_testCtx.getLog() << program;
    179 
    180 		if (!program.isOk())
    181 		{
    182 			if (m_indexExprType == INDEX_EXPR_STATIC)
    183 				TCU_FAIL("Compile failed");
    184 			else
    185 				throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported");
    186 		}
    187 
    188 		gl.clearColor	(1.0f, 0.0f, 0.0f, 1.0f);
    189 		gl.clear		(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    190 
    191 		gl.viewport		(0, 0, viewportW, viewportH);
    192 		gl.useProgram	(program.getProgram());
    193 		gl.uniform1i	(gl.getUniformLocation(program.getProgram(), "u_index"), 0);
    194 
    195 		glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
    196 				  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
    197 		GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
    198 
    199 		{
    200 			tcu::Surface		result		(viewportW, viewportH);
    201 			const tcu::RGBA		threshold	= renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
    202 			bool				isOk;
    203 
    204 			glu::readPixels(renderCtx, 0, 0, result.getAccess());
    205 			GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
    206 
    207 			isOk = compareSingleColor(m_testCtx.getLog(), result, tcu::RGBA::green(), threshold);
    208 
    209 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    210 									isOk ? "Pass"				: "Image comparison failed");
    211 		}
    212 
    213 		return STOP;
    214 	}
    215 
    216 private:
    217 	const IndexExprType m_indexExprType;
    218 };
    219 
    220 class FragDataDrawBuffersCase : public TestCase
    221 {
    222 public:
    223 	FragDataDrawBuffersCase (Context& context)
    224 		: TestCase(context, "draw_buffers", "gl_FragData[] and glDrawBuffers() interaction")
    225 	{
    226 	}
    227 
    228 	IterateResult iterate (void)
    229 	{
    230 		const glu::RenderContext&		renderCtx		= m_context.getRenderContext();
    231 		const glu::ShaderProgram		program			(renderCtx, glu::ProgramSources()
    232 															<< glu::VertexSource(
    233 																"attribute highp vec4 a_position;\n"
    234 																"attribute highp vec4 a_color;\n"
    235 																"varying mediump vec4 v_color;\n"
    236 																"void main (void)\n"
    237 																"{\n"
    238 																"	gl_Position = a_position;\n"
    239 																"	v_color = a_color;\n"
    240 																"}\n")
    241 															<< glu::FragmentSource(
    242 																"varying mediump vec4 v_color;\n"
    243 																"uniform mediump int u_index;\n"
    244 																"void main (void)\n"
    245 																"{\n"
    246 																"	gl_FragData[u_index] = v_color;\n"
    247 																"}\n"));
    248 		const glw::Functions&			gl				= renderCtx.getFunctions();
    249 		const int						width			= 128;
    250 		const int						height			= 128;
    251 		const int						indexLoc		= program.isOk() ? gl.getUniformLocation(program.getProgram(), "u_index") : -1;
    252 		const glu::Framebuffer			fbo				(renderCtx);
    253 		const glu::Renderbuffer			colorBuf0		(renderCtx);
    254 		const glu::Renderbuffer			colorBuf1		(renderCtx);
    255 
    256 		const float positions[] =
    257 		{
    258 			-1.0f, -1.0f,
    259 			+1.0f, -1.0f,
    260 			-1.0f, +1.0f,
    261 			+1.0f, +1.0f
    262 		};
    263 		const float colors[] =
    264 		{
    265 			0.0f, 1.0f, 0.0f, 1.0f,
    266 			0.0f, 1.0f, 0.0f, 1.0f,
    267 			0.0f, 1.0f, 0.0f, 1.0f,
    268 			0.0f, 1.0f, 0.0f, 1.0f
    269 		};
    270 		const deUint8	indices[]		= { 0, 1, 2, 2, 1, 3 };
    271 
    272 		const glu::VertexArrayBinding vertexArrays[] =
    273 		{
    274 			glu::va::Float("a_position",	2, 4, 0, &positions[0]),
    275 			glu::va::Float("a_color",		4, 4, 0, &colors[0])
    276 		};
    277 
    278 		m_testCtx.getLog() << program;
    279 
    280 		if (!program.isOk())
    281 			throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported");
    282 
    283 		gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
    284 		for (int ndx = 0; ndx < 2; ndx++)
    285 		{
    286 			const deUint32	rbo	= ndx == 0 ? *colorBuf0 : *colorBuf1;
    287 
    288 			gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
    289 			gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
    290 			gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+ndx, GL_RENDERBUFFER, rbo);
    291 		}
    292 		TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    293 
    294 		{
    295 			const deUint32 drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
    296 			gl.drawBuffers(DE_LENGTH_OF_ARRAY(drawBuffers), &drawBuffers[0]);
    297 		}
    298 
    299 		gl.clearBufferfv(GL_COLOR, 0, tcu::RGBA::red().toVec().getPtr());
    300 		gl.clearBufferfv(GL_COLOR, 1, tcu::RGBA::red().toVec().getPtr());
    301 
    302 		gl.viewport		(0, 0, width, height);
    303 		gl.useProgram	(program.getProgram());
    304 
    305 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
    306 
    307 		m_testCtx.getLog() << TestLog::Message << "Drawing to attachments 0 and 1, expecting only attachment 0 to change." << TestLog::EndMessage;
    308 
    309 		for (int ndx = 0; ndx < 2; ndx++)
    310 		{
    311 			gl.uniform1i(indexLoc, ndx);
    312 			glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
    313 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
    314 		}
    315 		GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
    316 
    317 		{
    318 			tcu::Surface		result		(width, height);
    319 			const tcu::RGBA		threshold	= renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
    320 			bool				allOk		= true;
    321 
    322 			for (int ndx = 0; ndx < 2; ndx++)
    323 			{
    324 				m_testCtx.getLog() << TestLog::Message << "Verifying attachment " << ndx << "..." << TestLog::EndMessage;
    325 
    326 				gl.readBuffer(GL_COLOR_ATTACHMENT0+ndx);
    327 				glu::readPixels(renderCtx, 0, 0, result.getAccess());
    328 				GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
    329 
    330 				if (!compareSingleColor(m_testCtx.getLog(), result, ndx == 0 ? tcu::RGBA::green() : tcu::RGBA::red(), threshold))
    331 					allOk = false;
    332 			}
    333 
    334 			m_testCtx.setTestResult(allOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    335 									allOk ? "Pass"				: "Image comparison failed");
    336 		}
    337 
    338 		return STOP;
    339 	}
    340 };
    341 
    342 } // anonymous
    343 
    344 ShaderFragDataTests::ShaderFragDataTests (Context& context)
    345 	: TestCaseGroup(context, "fragdata", "gl_FragData[] Tests")
    346 {
    347 }
    348 
    349 ShaderFragDataTests::~ShaderFragDataTests (void)
    350 {
    351 }
    352 
    353 void ShaderFragDataTests::init (void)
    354 {
    355 	addChild(new FragDataIndexingCase		(m_context, "valid_static_index",	"Valid gl_FragData[] assignment using static index",	INDEX_EXPR_STATIC));
    356 	addChild(new FragDataIndexingCase		(m_context, "valid_uniform_index",	"Valid gl_FragData[] assignment using uniform index",	INDEX_EXPR_UNIFORM));
    357 	addChild(new FragDataIndexingCase		(m_context, "valid_dynamic_index",	"Valid gl_FragData[] assignment using dynamic index",	INDEX_EXPR_DYNAMIC));
    358 	addChild(new FragDataDrawBuffersCase	(m_context));
    359 
    360 	// Negative cases.
    361 	{
    362 		gls::ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
    363 		std::vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/fragdata.test");
    364 
    365 		for (std::vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)
    366 			addChild(*i);
    367 	}
    368 }
    369 
    370 } // Functional
    371 } // gles3
    372 } // deqp
    373