Home | History | Annotate | Download | only in accuracy
      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 Varying interpolation accuracy tests.
     22  *
     23  * \todo [2012-07-03 pyry] On GLES3 we could use floating-point render target
     24  *						   for better accuracy evaluation.
     25  *//*--------------------------------------------------------------------*/
     26 
     27 #include "es3aVaryingInterpolationTests.hpp"
     28 #include "gluPixelTransfer.hpp"
     29 #include "gluShaderProgram.hpp"
     30 #include "gluShaderUtil.hpp"
     31 #include "tcuStringTemplate.hpp"
     32 #include "gluContextInfo.hpp"
     33 #include "glsTextureTestUtil.hpp"
     34 #include "tcuVector.hpp"
     35 #include "tcuVectorUtil.hpp"
     36 #include "tcuTestLog.hpp"
     37 #include "tcuFloat.hpp"
     38 #include "tcuImageCompare.hpp"
     39 #include "tcuRenderTarget.hpp"
     40 #include "deRandom.hpp"
     41 #include "deStringUtil.hpp"
     42 #include "deString.h"
     43 
     44 #include "glw.h"
     45 
     46 using tcu::TestLog;
     47 using tcu::Vec3;
     48 using tcu::Vec4;
     49 using std::string;
     50 using std::vector;
     51 using std::map;
     52 using deqp::gls::TextureTestUtil::SurfaceAccess;
     53 
     54 namespace deqp
     55 {
     56 namespace gles3
     57 {
     58 namespace Accuracy
     59 {
     60 
     61 static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
     62 {
     63 	return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]);
     64 }
     65 
     66 static void renderReference (const SurfaceAccess& dst, const float coords[4*3], const Vec4& wCoord, const Vec3& scale, const Vec3& bias)
     67 {
     68 	float		dstW		= (float)dst.getWidth();
     69 	float		dstH		= (float)dst.getHeight();
     70 
     71 	Vec3		triR[2]		= { Vec3(coords[0*3+0], coords[1*3+0], coords[2*3+0]), Vec3(coords[3*3+0], coords[2*3+0], coords[1*3+0]) };
     72 	Vec3		triG[2]		= { Vec3(coords[0*3+1], coords[1*3+1], coords[2*3+1]), Vec3(coords[3*3+1], coords[2*3+1], coords[1*3+1]) };
     73 	Vec3		triB[2]		= { Vec3(coords[0*3+2], coords[1*3+2], coords[2*3+2]), Vec3(coords[3*3+2], coords[2*3+2], coords[1*3+2]) };
     74 	tcu::Vec3	triW[2]		= { wCoord.swizzle(0, 1, 2), wCoord.swizzle(3, 2, 1) };
     75 
     76 	for (int py = 0; py < dst.getHeight(); py++)
     77 	{
     78 		for (int px = 0; px < dst.getWidth(); px++)
     79 		{
     80 			float	wx		= (float)px + 0.5f;
     81 			float	wy		= (float)py + 0.5f;
     82 			float	nx		= wx / dstW;
     83 			float	ny		= wy / dstH;
     84 
     85 			int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
     86 			float	triNx	= triNdx ? 1.0f - nx : nx;
     87 			float	triNy	= triNdx ? 1.0f - ny : ny;
     88 
     89 			float	r		= projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy) * scale[0] + bias[0];
     90 			float	g		= projectedTriInterpolate(triG[triNdx], triW[triNdx], triNx, triNy) * scale[1] + bias[1];
     91 			float	b		= projectedTriInterpolate(triB[triNdx], triW[triNdx], triNx, triNy) * scale[2] + bias[2];
     92 
     93 			Vec4	color	= Vec4(r, g, b, 1.0f);
     94 
     95 			dst.setPixel(color, px, py);
     96 		}
     97 	}
     98 }
     99 
    100 class InterpolationCase : public TestCase
    101 {
    102 public:
    103 					InterpolationCase			(Context& context, const char* name, const char* desc, glu::Precision precision, const tcu::Vec3& minVal, const tcu::Vec3& maxVal, bool projective);
    104 					~InterpolationCase			(void);
    105 
    106 	IterateResult	iterate						(void);
    107 
    108 private:
    109 	glu::Precision	m_precision;
    110 	tcu::Vec3		m_min;
    111 	tcu::Vec3		m_max;
    112 	bool			m_projective;
    113 };
    114 
    115 InterpolationCase::InterpolationCase (Context& context, const char* name, const char* desc, glu::Precision precision, const tcu::Vec3& minVal, const tcu::Vec3& maxVal, bool projective)
    116 	: TestCase		(context, tcu::NODETYPE_ACCURACY, name, desc)
    117 	, m_precision	(precision)
    118 	, m_min			(minVal)
    119 	, m_max			(maxVal)
    120 	, m_projective	(projective)
    121 {
    122 }
    123 
    124 InterpolationCase::~InterpolationCase (void)
    125 {
    126 }
    127 
    128 static bool isValidFloat (glu::Precision precision, float val)
    129 {
    130 	if (precision == glu::PRECISION_MEDIUMP)
    131 	{
    132 		tcu::Float16 fp16(val);
    133 		return !fp16.isDenorm() && !fp16.isInf() && !fp16.isNaN();
    134 	}
    135 	else
    136 	{
    137 		tcu::Float32 fp32(val);
    138 		return !fp32.isDenorm() && !fp32.isInf() && !fp32.isNaN();
    139 	}
    140 }
    141 
    142 template <int Size>
    143 static bool isValidFloatVec (glu::Precision precision, const tcu::Vector<float, Size>& vec)
    144 {
    145 	for (int ndx = 0; ndx < Size; ndx++)
    146 	{
    147 		if (!isValidFloat(precision, vec[ndx]))
    148 			return false;
    149 	}
    150 	return true;
    151 }
    152 
    153 InterpolationCase::IterateResult InterpolationCase::iterate (void)
    154 {
    155 	TestLog&					log				= m_testCtx.getLog();
    156 	de::Random					rnd				(deStringHash(getName()));
    157 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderTarget();
    158 	int							viewportWidth	= 128;
    159 	int							viewportHeight	= 128;
    160 
    161 	if (renderTarget.getWidth() < viewportWidth ||
    162 		renderTarget.getHeight() < viewportHeight)
    163 		throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
    164 
    165 	int							viewportX		= rnd.getInt(0, renderTarget.getWidth()		- viewportWidth);
    166 	int							viewportY		= rnd.getInt(0, renderTarget.getHeight()	- viewportHeight);
    167 
    168 	static const char* s_vertShaderTemplate =
    169 		"#version 300 es\n"
    170 		"in highp vec4 a_position;\n"
    171 		"in ${PRECISION} vec3 a_coords;\n"
    172 		"out ${PRECISION} vec3 v_coords;\n"
    173 		"\n"
    174 		"void main (void)\n"
    175 		"{\n"
    176 		"	gl_Position = a_position;\n"
    177 		"	v_coords = a_coords;\n"
    178 		"}\n";
    179 	static const char* s_fragShaderTemplate =
    180 		"#version 300 es\n"
    181 		"in ${PRECISION} vec3 v_coords;\n"
    182 		"uniform ${PRECISION} vec3 u_scale;\n"
    183 		"uniform ${PRECISION} vec3 u_bias;\n"
    184 		"layout(location = 0) out ${PRECISION} vec4 o_color;\n"
    185 		"\n"
    186 		"void main (void)\n"
    187 		"{\n"
    188 		"	o_color = vec4(v_coords * u_scale + u_bias, 1.0);\n"
    189 		"}\n";
    190 
    191 	map<string, string> templateParams;
    192 	templateParams["PRECISION"] = glu::getPrecisionName(m_precision);
    193 
    194 	glu::ShaderProgram program(m_context.getRenderContext(),
    195 							   glu::makeVtxFragSources(tcu::StringTemplate(s_vertShaderTemplate).specialize(templateParams),
    196 													   tcu::StringTemplate(s_fragShaderTemplate).specialize(templateParams)));
    197 	log << program;
    198 	if (!program.isOk())
    199 	{
    200 		if (m_precision == glu::PRECISION_HIGHP && !m_context.getContextInfo().isFragmentHighPrecisionSupported())
    201 			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Fragment highp not supported");
    202 		else
    203 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
    204 		return STOP;
    205 	}
    206 
    207 	// Position coordinates.
    208 	Vec4 wCoord = m_projective ? Vec4(1.3f, 0.8f, 0.6f, 2.0f) : Vec4(1.0f, 1.0f, 1.0f, 1.0f);
    209 	float positions[] =
    210 	{
    211 		-1.0f*wCoord.x(), -1.0f*wCoord.x(), 0.0f, wCoord.x(),
    212 		-1.0f*wCoord.y(), +1.0f*wCoord.y(), 0.0f, wCoord.y(),
    213 		+1.0f*wCoord.z(), -1.0f*wCoord.z(), 0.0f, wCoord.z(),
    214 		+1.0f*wCoord.w(), +1.0f*wCoord.w(), 0.0f, wCoord.w()
    215 	};
    216 
    217 	// Coordinates for interpolation.
    218 	tcu::Vec3 scale	= 1.0f / (m_max - m_min);
    219 	tcu::Vec3 bias	= -1.0f*m_min*scale;
    220 	float coords[] =
    221 	{
    222 		(0.0f - bias[0])/scale[0], (0.5f - bias[1])/scale[1], (1.0f - bias[2])/scale[2],
    223 		(0.5f - bias[0])/scale[0], (1.0f - bias[1])/scale[1], (0.5f - bias[2])/scale[2],
    224 		(0.5f - bias[0])/scale[0], (0.0f - bias[1])/scale[1], (0.5f - bias[2])/scale[2],
    225 		(1.0f - bias[0])/scale[0], (0.5f - bias[1])/scale[1], (0.0f - bias[2])/scale[2]
    226 	};
    227 
    228 	log << TestLog::Message << "a_coords = " << ((tcu::Vec3(0.0f) - bias)/scale) << " -> " << ((tcu::Vec3(1.0f) - bias)/scale) << TestLog::EndMessage;
    229 	log << TestLog::Message << "u_scale = " << scale << TestLog::EndMessage;
    230 	log << TestLog::Message << "u_bias = " << bias << TestLog::EndMessage;
    231 
    232 	// Verify that none of the inputs are denormalized / inf / nan.
    233 	TCU_CHECK(isValidFloatVec(m_precision, scale));
    234 	TCU_CHECK(isValidFloatVec(m_precision, bias));
    235 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(coords); ndx++)
    236 	{
    237 		TCU_CHECK(isValidFloat(m_precision, coords[ndx]));
    238 		TCU_CHECK(isValidFloat(m_precision, coords[ndx] * scale[ndx % 3] + bias[ndx % 3]));
    239 	}
    240 
    241 	// Indices.
    242 	static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
    243 
    244 	{
    245 		const int	posLoc		= glGetAttribLocation(program.getProgram(), "a_position");
    246 		const int	coordLoc	= glGetAttribLocation(program.getProgram(), "a_coords");
    247 
    248 		glEnableVertexAttribArray(posLoc);
    249 		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &positions[0]);
    250 
    251 		glEnableVertexAttribArray(coordLoc);
    252 		glVertexAttribPointer(coordLoc, 3, GL_FLOAT, GL_FALSE, 0, &coords[0]);
    253 	}
    254 
    255 	glUseProgram(program.getProgram());
    256 	glUniform3f(glGetUniformLocation(program.getProgram(), "u_scale"), scale.x(), scale.y(), scale.z());
    257 	glUniform3f(glGetUniformLocation(program.getProgram(), "u_bias"), bias.x(), bias.y(), bias.z());
    258 
    259 	GLU_CHECK_MSG("After program setup");
    260 
    261 	// Frames.
    262 	tcu::Surface	rendered		(viewportWidth, viewportHeight);
    263 	tcu::Surface	reference		(viewportWidth, viewportHeight);
    264 	tcu::Surface	diffMask		(viewportWidth, viewportHeight);
    265 
    266 	// Render with GL.
    267 	glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
    268 	glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
    269 
    270 	// Render reference \note While GPU is hopefully doing our draw call.
    271 	renderReference(SurfaceAccess(reference, m_context.getRenderTarget().getPixelFormat()), coords, wCoord, scale, bias);
    272 
    273 	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, rendered.getAccess());
    274 
    275 	// Compute difference.
    276 	const int		bestScoreDiff	= 16;
    277 	const int		worstScoreDiff	= 300;
    278 	int				score			= tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
    279 
    280 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
    281 	return STOP;
    282 }
    283 
    284 VaryingInterpolationTests::VaryingInterpolationTests (Context& context)
    285 	: TestCaseGroup(context, "interpolation", "Varying Interpolation Accuracy Tests")
    286 {
    287 }
    288 
    289 VaryingInterpolationTests::~VaryingInterpolationTests (void)
    290 {
    291 }
    292 
    293 void VaryingInterpolationTests::init (void)
    294 {
    295 	DE_STATIC_ASSERT(glu::PRECISION_LOWP+1		== glu::PRECISION_MEDIUMP);
    296 	DE_STATIC_ASSERT(glu::PRECISION_MEDIUMP+1	== glu::PRECISION_HIGHP);
    297 
    298 	// Exp = Emax-3, Mantissa = 0
    299 	float minF32 = tcu::Float32((0u<<31) | (0xfcu<<23) | 0x0u).asFloat();
    300 	float maxF32 = tcu::Float32((1u<<31) | (0xfcu<<23) | 0x0u).asFloat();
    301 	float minF16 = tcu::Float16((deUint16)((0u<<15) | (0x1cu<<10) | 0x0u)).asFloat();
    302 	float maxF16 = tcu::Float16((deUint16)((1u<<15) | (0x1cu<<10) | 0x0u)).asFloat();
    303 
    304 	static const struct
    305 	{
    306 		const char*		name;
    307 		Vec3			minVal;
    308 		Vec3			maxVal;
    309 		glu::Precision	minPrecision;
    310 	} coordRanges[] =
    311 	{
    312 		{ "zero_to_one",		Vec3(  0.0f,   0.0f,   0.0f), Vec3(  1.0f,   1.0f,   1.0f), glu::PRECISION_LOWP		},
    313 		{ "zero_to_minus_one",	Vec3(  0.0f,   0.0f,   0.0f), Vec3( -1.0f,  -1.0f,  -1.0f), glu::PRECISION_LOWP		},
    314 		{ "minus_one_to_one",	Vec3( -1.0f,  -1.0f,  -1.0f), Vec3(  1.0f,   1.0f,   1.0f), glu::PRECISION_LOWP		},
    315 		{ "minus_ten_to_ten",	Vec3(-10.0f, -10.0f, -10.0f), Vec3( 10.0f,  10.0f,  10.0f), glu::PRECISION_MEDIUMP	},
    316 		{ "thousands",			Vec3( -5e3f,   1e3f,   1e3f), Vec3(  3e3f,  -1e3f,   7e3f), glu::PRECISION_MEDIUMP	},
    317 		{ "full_mediump",		Vec3(minF16, minF16, minF16), Vec3(maxF16, maxF16, maxF16), glu::PRECISION_MEDIUMP	},
    318 		{ "full_highp",			Vec3(minF32, minF32, minF32), Vec3(maxF32, maxF32, maxF32), glu::PRECISION_HIGHP	},
    319 	};
    320 
    321 	for (int precision = glu::PRECISION_LOWP; precision <= glu::PRECISION_HIGHP; precision++)
    322 	{
    323 		for (int coordNdx = 0; coordNdx < DE_LENGTH_OF_ARRAY(coordRanges); coordNdx++)
    324 		{
    325 			if (precision < (int)coordRanges[coordNdx].minPrecision)
    326 				continue;
    327 
    328 			string baseName = string(glu::getPrecisionName((glu::Precision)precision)) + "_" + coordRanges[coordNdx].name;
    329 
    330 			addChild(new InterpolationCase(m_context, baseName.c_str(),				"",	(glu::Precision)precision, coordRanges[coordNdx].minVal, coordRanges[coordNdx].maxVal, false));
    331 			addChild(new InterpolationCase(m_context, (baseName + "_proj").c_str(),	"",	(glu::Precision)precision, coordRanges[coordNdx].minVal, coordRanges[coordNdx].maxVal, true));
    332 		}
    333 	}
    334 }
    335 
    336 } // Accuracy
    337 } // gles3
    338 } // deqp
    339