148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos/*-------------------------------------------------------------------------
248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * OpenGL Conformance Test Suite
348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * -----------------------------
448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * Copyright (c) 2016 Google Inc.
648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * Copyright (c) 2016 The Khronos Group Inc.
748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * Licensed under the Apache License, Version 2.0 (the "License");
948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * you may not use this file except in compliance with the License.
1048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * You may obtain a copy of the License at
1148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
1248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *      http://www.apache.org/licenses/LICENSE-2.0
1348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
1448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * Unless required by applicable law or agreed to in writing, software
1548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * distributed under the License is distributed on an "AS IS" BASIS,
1648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * See the License for the specific language governing permissions and
1848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * limitations under the License.
1948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos *
2084322c9402f810da3cd80b52e9f9ef72150a9004Alexander Galazin */ /*!
2148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * \file
2248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos * \brief Compiler test case.
2384322c9402f810da3cd80b52e9f9ef72150a9004Alexander Galazin */ /*-------------------------------------------------------------------*/
2448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
2548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "glcShaderLibraryCase.hpp"
2648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
2748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "tcuRenderTarget.hpp"
2848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "tcuTestLog.hpp"
2948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
3048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "gluDrawUtil.hpp"
3148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "gluPixelTransfer.hpp"
3248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "gluShaderProgram.hpp"
3348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "tcuStringTemplate.hpp"
3448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
3548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "glwEnums.hpp"
3648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "glwFunctions.hpp"
3748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
3848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "deInt32.h"
3948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "deMath.h"
4048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "deRandom.hpp"
4148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include "deString.h"
4248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
4348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include <map>
4448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include <sstream>
4548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include <string>
4648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos#include <vector>
4748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
4848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing namespace std;
4948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing namespace tcu;
5048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosusing namespace glu;
5148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
5248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosnamespace deqp
5348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
5448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosnamespace sl
5548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
5648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
5748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosenum
5848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
5948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	VIEWPORT_WIDTH  = 128,
6048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	VIEWPORT_HEIGHT = 128
6148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos};
6248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
6348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosstatic inline bool usesShaderInoutQualifiers(glu::GLSLVersion version)
6448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
6548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	switch (version)
6648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
6748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case glu::GLSL_VERSION_100_ES:
6848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case glu::GLSL_VERSION_130:
6948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case glu::GLSL_VERSION_140:
7048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case glu::GLSL_VERSION_150:
7148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return false;
7248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
7348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	default:
7448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return true;
7548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
7648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
7748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
7848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos// ShaderCase.
7948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
8048087f5f0eb08759ee763f98daf3b34becb74559Pyry HaulosShaderCase::ShaderCase(tcu::TestContext& testCtx, RenderContext& renderCtx, const char* name, const char* description,
8148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					   ExpectResult expectResult, const std::vector<ValueBlock>& valueBlocks, GLSLVersion targetVersion,
8248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					   const char* vertexSource, const char* fragmentSource)
8348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	: tcu::TestCase(testCtx, name, description)
8448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	, m_renderCtx(renderCtx)
8548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	, m_expectResult(expectResult)
8648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	, m_valueBlocks(valueBlocks)
8748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	, m_targetVersion(targetVersion)
8848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
8948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// If no value blocks given, use an empty one.
9048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (m_valueBlocks.size() == 0)
9148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_valueBlocks.push_back(ValueBlock());
9248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
9348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Use first value block to specialize shaders.
9448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const ValueBlock& valueBlock = m_valueBlocks[0];
9548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
9648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// \todo [2010-04-01 petri] Check that all value blocks have matching values.
9748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
9848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Generate specialized shader sources.
9948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (vertexSource && fragmentSource)
10048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
10148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_caseType = CASETYPE_COMPLETE;
10248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		specializeShaders(vertexSource, fragmentSource, m_vertexSource, m_fragmentSource, valueBlock);
10348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
10448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	else if (vertexSource)
10548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
10648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_caseType		 = CASETYPE_VERTEX_ONLY;
10748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertexSource   = specializeVertexShader(vertexSource, valueBlock);
10848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_fragmentSource = genFragmentShader(valueBlock);
10948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
11048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	else
11148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
11248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		DE_ASSERT(fragmentSource);
11348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_caseType		 = CASETYPE_FRAGMENT_ONLY;
11448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_vertexSource   = genVertexShader(valueBlock);
11548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_fragmentSource = specializeFragmentShader(fragmentSource, valueBlock);
11648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
11748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
11848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
11948087f5f0eb08759ee763f98daf3b34becb74559Pyry HaulosShaderCase::~ShaderCase(void)
12048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
12148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
12248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
12348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosstatic void setUniformValue(const glw::Functions& gl, deUint32 programID, const std::string& name,
12448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							const ShaderCase::Value& val, int arrayNdx)
12548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
12648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int scalarSize = getDataTypeScalarSize(val.dataType);
12748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int loc		   = gl.getUniformLocation(programID, name.c_str());
12848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
12948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	TCU_CHECK_MSG(loc != -1, "uniform location not found");
13048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
13148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLfloat));
13248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLint));
13348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
13448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int elemNdx = (val.arrayLength == 1) ? 0 : (arrayNdx * scalarSize);
13548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
13648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	switch (val.dataType)
13748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
13848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT:
13948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32);
14048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
14148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_VEC2:
14248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32);
14348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
14448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_VEC3:
14548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32);
14648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
14748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_VEC4:
14848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32);
14948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
15048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_MAT2:
15148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
15248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
15348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_MAT3:
15448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
15548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
15648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_MAT4:
15748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
15848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
15948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_INT:
16048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);
16148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
16248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_INT_VEC2:
16348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);
16448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
16548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_INT_VEC3:
16648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);
16748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
16848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_INT_VEC4:
16948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);
17048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
17148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_BOOL:
17248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);
17348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
17448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_BOOL_VEC2:
17548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);
17648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
17748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_BOOL_VEC3:
17848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);
17948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
18048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_BOOL_VEC4:
18148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);
18248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
18348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_UINT:
18448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);
18548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
18648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_UINT_VEC2:
18748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);
18848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
18948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_UINT_VEC3:
19048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);
19148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
19248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_UINT_VEC4:
19348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);
19448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
19548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_MAT2X3:
19648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
19748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
19848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_MAT2X4:
19948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
20048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
20148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_MAT3X2:
20248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
20348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
20448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_MAT3X4:
20548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
20648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
20748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_MAT4X2:
20848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
20948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
21048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_FLOAT_MAT4X3:
21148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);
21248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
21348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
21448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_SAMPLER_2D:
21548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case TYPE_SAMPLER_CUBE:
21648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		DE_ASSERT(DE_FALSE && "implement!");
21748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
21848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
21948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	default:
22048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		DE_ASSERT(false);
22148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
22248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
22348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
22448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosbool ShaderCase::checkPixels(Surface& surface, int minX, int maxX, int minY, int maxY)
22548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
22648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	TestLog& log		   = m_testCtx.getLog();
22748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool	 allWhite	  = true;
22848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool	 allBlack	  = true;
22948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool	 anyUnexpected = false;
23048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
23148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	DE_ASSERT((maxX > minX) && (maxY > minY));
23248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
23348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int y = minY; y <= maxY; y++)
23448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
23548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int x = minX; x <= maxX; x++)
23648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
23748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			RGBA pixel = surface.getPixel(x, y);
23848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			// Note: we really do not want to involve alpha in the check comparison
23948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			// \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black.
24048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			bool isWhite = (pixel.getRed() == 255) && (pixel.getGreen() == 255) && (pixel.getBlue() == 255);
24148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			bool isBlack = (pixel.getRed() == 0) && (pixel.getGreen() == 0) && (pixel.getBlue() == 0);
24248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
24348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			allWhite	  = allWhite && isWhite;
24448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			allBlack	  = allBlack && isBlack;
24548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			anyUnexpected = anyUnexpected || (!isWhite && !isBlack);
24648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
24748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
24848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
24948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (!allWhite)
25048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
25148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (anyUnexpected)
25248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			log << TestLog::Message
25348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				<< "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!"
25448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				<< TestLog::EndMessage;
25548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (!allBlack)
25648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			log << TestLog::Message
25748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				<< "WARNING: got inconsistent results over the image, when all pixels should be the same color!"
25848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				<< TestLog::EndMessage;
25948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
26048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return false;
26148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
26248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	return true;
26348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
26448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
26548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosbool ShaderCase::execute(void)
26648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
26748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	TestLog&			  log = m_testCtx.getLog();
26848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const glw::Functions& gl  = m_renderCtx.getFunctions();
26948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
27048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Compute viewport.
27148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const tcu::RenderTarget& renderTarget = m_renderCtx.getRenderTarget();
27248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	de::Random				 rnd(deStringHash(getName()));
27348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int						 width				= deMin32(renderTarget.getWidth(), VIEWPORT_WIDTH);
27448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int						 height				= deMin32(renderTarget.getHeight(), VIEWPORT_HEIGHT);
27548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int						 viewportX			= rnd.getInt(0, renderTarget.getWidth() - width);
27648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int						 viewportY			= rnd.getInt(0, renderTarget.getHeight() - height);
27748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const int				 numVerticesPerDraw = 4;
27848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
27948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start");
28048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
28148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Setup viewport.
28248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	gl.viewport(viewportX, viewportY, width, height);
28348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
28448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const float		   quadSize			  = 1.0f;
28548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	static const float s_positions[4 * 4] = { -quadSize, -quadSize, 0.0f, 1.0f, -quadSize, +quadSize, 0.0f, 1.0f,
28648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos											  +quadSize, -quadSize, 0.0f, 1.0f, +quadSize, +quadSize, 0.0f, 1.0f };
28748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
28848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	static const deUint16 s_indices[2 * 3] = { 0, 1, 2, 1, 3, 2 };
28948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
29048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Setup program.
29148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	glu::ShaderProgram program(m_renderCtx, glu::makeVtxFragSources(m_vertexSource.c_str(), m_fragmentSource.c_str()));
29248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
29348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Check that compile/link results are what we expect.
29448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool		vertexOk   = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
29548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool		fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
29648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool		linkOk	 = program.getProgramInfo().linkOk;
29748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const char* failReason = DE_NULL;
29848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
29948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	log << program;
30048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
30148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	switch (m_expectResult)
30248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
30348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case EXPECT_PASS:
30448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!vertexOk || !fragmentOk)
30548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			failReason = "expected shaders to compile and link properly, but failed to compile.";
30648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (!linkOk)
30748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			failReason = "expected shaders to compile and link properly, but failed to link.";
30848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
30948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
31048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case EXPECT_COMPILE_FAIL:
31148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (vertexOk && fragmentOk && !linkOk)
31248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			failReason = "expected compilation to fail, but both shaders compiled and link failed.";
31348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (vertexOk && fragmentOk)
31448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			failReason = "expected compilation to fail, but both shaders compiled correctly.";
31548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
31648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
31748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	case EXPECT_LINK_FAIL:
31848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (!vertexOk || !fragmentOk)
31948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			failReason = "expected linking to fail, but unable to compile.";
32048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (linkOk)
32148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			failReason = "expected linking to fail, but passed.";
32248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		break;
32348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
32448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	default:
32548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		DE_ASSERT(false);
32648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return false;
32748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
32848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
32948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (failReason != DE_NULL)
33048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
33148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// \todo [2010-06-07 petri] These should be handled in the test case?
33248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
33348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
33448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// If implementation parses shader at link time, report it as quality warning.
33548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (m_expectResult == EXPECT_COMPILE_FAIL && vertexOk && fragmentOk && !linkOk)
33648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
33748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else
33848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason);
33948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return false;
34048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
34148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
34248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Return if compile/link expected to fail.
34348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (m_expectResult != EXPECT_PASS)
34448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		return (failReason == DE_NULL);
34548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
34648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Start using program.
34748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	deUint32 programID = program.getProgram();
34848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	gl.useProgram(programID);
34948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
35048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
35148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Fetch location for positions positions.
35248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int positionLoc = gl.getAttribLocation(programID, "dEQP_Position");
35348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (positionLoc == -1)
35448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
35548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		string errStr = string("no location found for attribute 'dEQP_Position'");
35648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		TCU_FAIL(errStr.c_str());
35748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
35848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
35948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Iterate all value blocks.
36048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int blockNdx = 0; blockNdx < (int)m_valueBlocks.size(); blockNdx++)
36148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
36248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const ValueBlock& valueBlock = m_valueBlocks[blockNdx];
36348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
36448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// Iterate all array sub-cases.
36548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int arrayNdx = 0; arrayNdx < valueBlock.arrayLength; arrayNdx++)
36648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
36748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int						   numValues = (int)valueBlock.values.size();
36848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			vector<VertexArrayBinding> vertexArrays;
36948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
37048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int					   attribValueNdx = 0;
37148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			vector<vector<float> > attribValues(numValues);
37248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
37348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0]));
37448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
37548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			// Collect VA pointer for inputs and set uniform values for outputs (refs).
37648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int valNdx = 0; valNdx < numValues; valNdx++)
37748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
37848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const ShaderCase::Value& val		= valueBlock.values[valNdx];
37948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const char*				 valueName  = val.valueName.c_str();
38048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				DataType				 dataType   = val.dataType;
38148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				int						 scalarSize = getDataTypeScalarSize(val.dataType);
38248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
38348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms");
38448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
38548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
38648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
38748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					// Replicate values four times.
38848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					std::vector<float>& scalars = attribValues[attribValueNdx++];
38948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					scalars.resize(numVerticesPerDraw * scalarSize);
39048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType))
39148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
39248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
39348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							for (int ndx						   = 0; ndx < scalarSize; ndx++)
39448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								scalars[repNdx * scalarSize + ndx] = val.elements[arrayNdx * scalarSize + ndx].float32;
39548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
39648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					else
39748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
39848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						// convert to floats.
39948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
40048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						{
40148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							for (int ndx = 0; ndx < scalarSize; ndx++)
40248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							{
40348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								float v = (float)val.elements[arrayNdx * scalarSize + ndx].int32;
40448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								DE_ASSERT(val.elements[arrayNdx * scalarSize + ndx].int32 == (int)v);
40548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								scalars[repNdx * scalarSize + ndx] = v;
40648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							}
40748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						}
40848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
40948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
41048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					// Attribute name prefix.
41148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					string attribPrefix = "";
41248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					// \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)?
41348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					if ((m_caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT))
41448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						attribPrefix = "a_";
41548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
41648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					// Input always given as attribute.
41748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					string attribName = attribPrefix + valueName;
41848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					int	attribLoc  = gl.getAttribLocation(programID, attribName.c_str());
41948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					if (attribLoc == -1)
42048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
42148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'"
42248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							<< TestLog::EndMessage;
42348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						continue;
42448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
42548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
42648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					if (isDataTypeMatrix(dataType))
42748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
42848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						int numCols = getDataTypeMatrixNumColumns(dataType);
42948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						int numRows = getDataTypeMatrixNumRows(dataType);
43048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						DE_ASSERT(scalarSize == numCols * numRows);
43148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
43248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						for (int i = 0; i < numCols; i++)
43348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos							vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw,
43448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos															 static_cast<int>(scalarSize * sizeof(float)),
43548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos															 &scalars[i * numRows]));
43648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
43748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					else
43848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					{
43948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) ||
44048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								  isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType));
44148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0]));
44248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					}
44348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
44448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array");
44548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
44648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
44748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
44848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					// Set reference value.
44948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					string refName = string("ref_") + valueName;
45048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					setUniformValue(gl, programID, refName, val, arrayNdx);
45148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms");
45248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
45348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				else
45448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
45548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					DE_ASSERT(val.storageType == ShaderCase::Value::STORAGE_UNIFORM);
45648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					setUniformValue(gl, programID, valueName, val, arrayNdx);
45748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms");
45848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
45948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
46048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
46148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			// Clear.
46248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
46348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			gl.clear(GL_COLOR_BUFFER_BIT);
46448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
46548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
46648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			// Draw.
46748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			draw(m_renderCtx, program.getProgram(), (int)vertexArrays.size(), &vertexArrays[0],
46848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				 pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0]));
46948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
47048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
47148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			// Read back results.
47248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			Surface surface(width, height);
47348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess());
47448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
47548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
47648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			float w	= s_positions[3];
47748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int   minY = deCeilFloatToInt32(((-quadSize / w) * 0.5f + 0.5f) * (float)height + 1.0f);
47848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int   maxY = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)height - 0.5f);
47948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int   minX = deCeilFloatToInt32(((-quadSize / w) * 0.5f + 0.5f) * (float)width + 1.0f);
48048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int   maxX = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)width - 0.5f);
48148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
48248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (!checkPixels(surface, minX, maxX, minY, maxY))
48348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
48448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				log << TestLog::Message << "INCORRECT RESULT for (value block " << (blockNdx + 1) << " of "
48548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					<< (int)m_valueBlocks.size() << ", sub-case " << arrayNdx + 1 << " of " << valueBlock.arrayLength
48648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					<< "):" << TestLog::EndMessage;
48748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
48848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage;
48948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				dumpValues(valueBlock, arrayNdx);
49048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
49148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				// Dump image on failure.
49248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				log << TestLog::Image("Result", "Rendered result image", surface);
49348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
49448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				gl.useProgram(0);
49548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
49648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				return false;
49748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
49848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
49948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
50048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
50148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	gl.useProgram(0);
50248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end");
50348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	return true;
50448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
50548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
50648087f5f0eb08759ee763f98daf3b34becb74559Pyry HaulosTestCase::IterateResult ShaderCase::iterate(void)
50748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
50848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Initialize state to pass.
50948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
51048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
51148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool executeOk = execute();
51248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
51348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS :
51448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						  m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
51548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	(void)executeOk;
51648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	return TestCase::STOP;
51748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
51848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
51948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos// This functions builds a matching vertex shader for a 'both' case, when
52048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos// the fragment shader is being tested.
52148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos// We need to build attributes and varyings for each 'input'.
52248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosstring ShaderCase::genVertexShader(const ValueBlock& valueBlock)
52348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
52448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	ostringstream res;
52548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const bool	usesInout = usesShaderInoutQualifiers(m_targetVersion);
52648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const char*   vtxIn		= usesInout ? "in" : "attribute";
52748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const char*   vtxOut	= usesInout ? "out" : "varying";
52848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
52948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n";
53048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
53148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Declarations (position + attribute/varying for each input).
53248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << "precision highp float;\n";
53348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << "precision highp int;\n";
53448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << "\n";
53548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << vtxIn << " highp vec4 dEQP_Position;\n";
53648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
53748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
53848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const ShaderCase::Value& val = valueBlock.values[ndx];
53948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
54048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
54148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			DataType	floatType = getDataTypeFloatScalars(val.dataType);
54248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char* typeStr   = getDataTypeName(floatType);
54348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			res << vtxIn << " " << typeStr << " a_" << val.valueName << ";\n";
54448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
54548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
54648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				res << vtxOut << " " << typeStr << " " << val.valueName << ";\n";
54748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else
54848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				res << vtxOut << " " << typeStr << " v_" << val.valueName << ";\n";
54948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
55048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
55148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << "\n";
55248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
55348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Main function.
55448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// - gl_Position = dEQP_Position;
55548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// - for each input: write attribute directly to varying
55648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << "void main()\n";
55748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << "{\n";
55848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << "    gl_Position = dEQP_Position;\n";
55948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
56048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
56148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const ShaderCase::Value& val = valueBlock.values[ndx];
56248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
56348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
56448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const string& name = val.valueName;
56548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
56648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				res << "    " << name << " = a_" << name << ";\n";
56748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else
56848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				res << "    v_" << name << " = a_" << name << ";\n";
56948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
57048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
57148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
57248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	res << "}\n";
57348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	return res.str();
57448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
57548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
57648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosstatic void genCompareFunctions(ostringstream& stream, const ShaderCase::ValueBlock& valueBlock, bool useFloatTypes)
57748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
57848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool cmpTypeFound[TYPE_LAST];
57948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int i			= 0; i < TYPE_LAST; i++)
58048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		cmpTypeFound[i] = false;
58148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
58248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++)
58348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
58448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const ShaderCase::Value& val = valueBlock.values[valueNdx];
58548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
58648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			cmpTypeFound[(int)val.dataType] = true;
58748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
58848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
58948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (useFloatTypes)
59048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
59148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_BOOL])
59248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n";
59348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_BOOL_VEC2])
59448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n";
59548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_BOOL_VEC3])
59648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n";
59748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_BOOL_VEC4])
59848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n";
59948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_INT])
60048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (float a, int b)  { float atemp = a+0.5; return (float(b) <= atemp && atemp <= "
60148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					  "float(b+1)); }\n";
60248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_INT_VEC2])
60348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n";
60448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_INT_VEC3])
60548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n";
60648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_INT_VEC4])
60748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n";
60848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_UINT])
60948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= "
61048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					  "float(b+1)); }\n";
61148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_UINT_VEC2])
61248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n";
61348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_UINT_VEC3])
61448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n";
61548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_UINT_VEC4])
61648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n";
61748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
61848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	else
61948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
62048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_BOOL])
62148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (bool a, bool b)   { return (a == b); }\n";
62248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_BOOL_VEC2])
62348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n";
62448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_BOOL_VEC3])
62548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n";
62648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_BOOL_VEC4])
62748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n";
62848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_INT])
62948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (int a, int b)     { return (a == b); }\n";
63048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_INT_VEC2])
63148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n";
63248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_INT_VEC3])
63348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n";
63448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_INT_VEC4])
63548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n";
63648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_UINT])
63748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (uint a, uint b)   { return (a == b); }\n";
63848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_UINT_VEC2])
63948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n";
64048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_UINT_VEC3])
64148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n";
64248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (cmpTypeFound[TYPE_UINT_VEC4])
64348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n";
64448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
64548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
64648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT])
64748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n";
64848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_VEC2])
64948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream
65048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			<< "bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
65148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_VEC3])
65248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream
65348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			<< "bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
65448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_VEC4])
65548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream
65648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			<< "bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
65748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
65848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_MAT2])
65948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return "
66048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "all(lessThanEqual(diff, vec2(eps))); }\n";
66148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_MAT2X3])
66248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return "
66348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "all(lessThanEqual(diff, vec3(eps))); }\n";
66448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_MAT2X4])
66548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return "
66648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "all(lessThanEqual(diff, vec4(eps))); }\n";
66748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_MAT3X2])
66848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
66948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n";
67048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_MAT3])
67148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
67248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n";
67348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_MAT3X4])
67448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
67548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n";
67648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_MAT4X2])
67748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
67848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n";
67948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_MAT4X3])
68048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
68148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n";
68248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (cmpTypeFound[TYPE_FLOAT_MAT4])
68348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		stream << "bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), "
68448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				  "max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n";
68548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
68648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
68748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosstatic void genCompareOp(ostringstream& output, const char* dstVec4Var, const ShaderCase::ValueBlock& valueBlock,
68848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						 const char* nonFloatNamePrefix, const char* checkVarName)
68948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
69048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	bool isFirstOutput = true;
69148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
69248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
69348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
69448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const ShaderCase::Value& val	   = valueBlock.values[ndx];
69548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 valueName = val.valueName.c_str();
69648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
69748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
69848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
69948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			// Check if we're only interested in one variable (then skip if not the right one).
70048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (checkVarName && !deStringEqual(valueName, checkVarName))
70148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				continue;
70248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
70348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			// Prefix.
70448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (isFirstOutput)
70548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
70648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				output << "bool RES = ";
70748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				isFirstOutput = false;
70848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
70948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else
71048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				output << "RES = RES && ";
71148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
71248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			// Generate actual comparison.
71348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
71448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				output << "isOk(" << valueName << ", ref_" << valueName << ", 0.05);\n";
71548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else
71648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				output << "isOk(" << nonFloatNamePrefix << valueName << ", ref_" << valueName << ");\n";
71748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
71848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		// \note Uniforms are already declared in shader.
71948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
72048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
72148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (isFirstOutput)
72248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		output << dstVec4Var << " = vec4(1.0);\n"; // \todo [petri] Should we give warning if not expect-failure case?
72348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	else
72448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n";
72548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
72648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
72748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosstring ShaderCase::genFragmentShader(const ValueBlock& valueBlock)
72848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
72948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	ostringstream shader;
73048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const bool	usesInout		 = usesShaderInoutQualifiers(m_targetVersion);
73148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const bool	customColorOut = usesInout;
73248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const char*   fragIn		 = usesInout ? "in" : "varying";
73348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
73448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n";
73548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
73648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << "precision mediump float;\n";
73748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << "precision mediump int;\n";
73848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << "\n";
73948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
74048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (customColorOut)
74148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
74248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
74348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		shader << "\n";
74448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
74548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
74648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	genCompareFunctions(shader, valueBlock, true);
74748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << "\n";
74848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
74948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Declarations (varying, reference for each output).
75048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
75148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
75248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const ShaderCase::Value& val		  = valueBlock.values[ndx];
75348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		DataType				 floatType	= getDataTypeFloatScalars(val.dataType);
75448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 floatTypeStr = getDataTypeName(floatType);
75548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 refTypeStr   = getDataTypeName(val.dataType);
75648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
75748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
75848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
75948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
76048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				shader << fragIn << " " << floatTypeStr << " " << val.valueName << ";\n";
76148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else
76248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				shader << fragIn << " " << floatTypeStr << " v_" << val.valueName << ";\n";
76348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
76448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			shader << "uniform " << refTypeStr << " ref_" << val.valueName << ";\n";
76548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
76648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
76748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
76848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << "\n";
76948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << "void main()\n";
77048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << "{\n";
77148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
77248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << " ";
77348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", valueBlock, "v_", DE_NULL);
77448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
77548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	shader << "}\n";
77648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	return shader.str();
77748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
77848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
77948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos// Specialize a shader for the vertex shader test case.
78048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosstring ShaderCase::specializeVertexShader(const char* src, const ValueBlock& valueBlock)
78148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
78248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	ostringstream decl;
78348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	ostringstream setup;
78448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	ostringstream output;
78548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const bool	usesInout = usesShaderInoutQualifiers(m_targetVersion);
78648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const char*   vtxIn		= usesInout ? "in" : "attribute";
78748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const char*   vtxOut	= usesInout ? "out" : "varying";
78848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
78948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Output (write out position).
79048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	output << "gl_Position = dEQP_Position;\n";
79148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
79248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Declarations (position + attribute for each input, varying for each output).
79348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	decl << vtxIn << " highp vec4 dEQP_Position;\n";
79448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
79548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
79648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const ShaderCase::Value& val		  = valueBlock.values[ndx];
79748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 valueName	= val.valueName.c_str();
79848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		DataType				 floatType	= getDataTypeFloatScalars(val.dataType);
79948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 floatTypeStr = getDataTypeName(floatType);
80048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 refTypeStr   = getDataTypeName(val.dataType);
80148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
80248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
80348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
80448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
80548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
80648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << vtxIn << " " << floatTypeStr << " " << valueName << ";\n";
80748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
80848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else
80948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
81048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << vtxIn << " " << floatTypeStr << " a_" << valueName << ";\n";
81148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(a_" << valueName << ");\n";
81248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
81348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
81448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
81548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
81648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
81748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << vtxOut << " " << floatTypeStr << " " << valueName << ";\n";
81848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else
81948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
82048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << vtxOut << " " << floatTypeStr << " v_" << valueName << ";\n";
82148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << refTypeStr << " " << valueName << ";\n";
82248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
82348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				output << "v_" << valueName << " = " << floatTypeStr << "(" << valueName << ");\n";
82448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
82548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
82648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
82748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
82848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Shader specialization.
82948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	map<string, string> params;
83048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
83148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	params.insert(pair<string, string>("SETUP", setup.str()));
83248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	params.insert(pair<string, string>("OUTPUT", output.str()));
83348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position"));
83448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
83548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	StringTemplate tmpl(src);
83648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	return tmpl.specialize(params);
83748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
83848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
83948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos// Specialize a shader for the fragment shader test case.
84048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosstring ShaderCase::specializeFragmentShader(const char* src, const ValueBlock& valueBlock)
84148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
84248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	ostringstream decl;
84348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	ostringstream setup;
84448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	ostringstream output;
84548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
84648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const bool  usesInout	  = usesShaderInoutQualifiers(m_targetVersion);
84748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const bool  customColorOut = usesInout;
84848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const char* fragIn		   = usesInout ? "in" : "varying";
84948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const char* fragColor	  = customColorOut ? "dEQP_FragColor" : "gl_FragColor";
85048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
85148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	genCompareFunctions(decl, valueBlock, false);
85248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	genCompareOp(output, fragColor, valueBlock, "", DE_NULL);
85348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
85448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	if (customColorOut)
85548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
85648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
85748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
85848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
85948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const ShaderCase::Value& val		  = valueBlock.values[ndx];
86048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 valueName	= val.valueName.c_str();
86148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		DataType				 floatType	= getDataTypeFloatScalars(val.dataType);
86248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 floatTypeStr = getDataTypeName(floatType);
86348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 refTypeStr   = getDataTypeName(val.dataType);
86448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
86548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
86648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
86748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
86848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << fragIn << " " << floatTypeStr << " " << valueName << ";\n";
86948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else
87048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
87148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << fragIn << " " << floatTypeStr << " v_" << valueName << ";\n";
87248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				std::string offset =
87348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					isDataTypeIntOrIVec(val.dataType) ?
87448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						" * 1.0025" :
87548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos						""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation
87648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(v_" << valueName << offset
87748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					  << ");\n";
87848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
87948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
88048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
88148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
88248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n";
88348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			decl << refTypeStr << " " << valueName << ";\n";
88448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
88548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
88648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
88748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	/* \todo [2010-04-01 petri] Check all outputs. */
88848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
88948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Shader specialization.
89048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	map<string, string> params;
89148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
89248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	params.insert(pair<string, string>("SETUP", setup.str()));
89348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	params.insert(pair<string, string>("OUTPUT", output.str()));
89448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor));
89548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
89648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	StringTemplate tmpl(src);
89748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	return tmpl.specialize(params);
89848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
89948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
90048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosvoid ShaderCase::specializeShaders(const char* vertexSource, const char* fragmentSource, string& outVertexSource,
90148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos								   string& outFragmentSource, const ValueBlock& valueBlock)
90248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
90348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const bool usesInout	  = usesShaderInoutQualifiers(m_targetVersion);
90448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	const bool customColorOut = usesInout;
90548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
90648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Vertex shader specialization.
90748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
90848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ostringstream decl;
90948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ostringstream setup;
91048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*   vtxIn = usesInout ? "in" : "attribute";
91148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
91248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		decl << vtxIn << " highp vec4 dEQP_Position;\n";
91348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
91448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
91548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
91648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const ShaderCase::Value& val	 = valueBlock.values[ndx];
91748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char*				 typeStr = getDataTypeName(val.dataType);
91848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
91948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
92048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
92148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
92248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
92348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					decl << vtxIn << " " << typeStr << " " << val.valueName << ";\n";
92448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
92548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				else
92648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
92748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					DataType	floatType	= getDataTypeFloatScalars(val.dataType);
92848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					const char* floatTypeStr = getDataTypeName(floatType);
92948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
93048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					decl << vtxIn << " " << floatTypeStr << " a_" << val.valueName << ";\n";
93148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					setup << typeStr << " " << val.valueName << " = " << typeStr << "(a_" << val.valueName << ");\n";
93248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
93348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
93448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && val.valueName.find('.') == string::npos)
93548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
93648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << "uniform " << typeStr << " " << val.valueName << ";\n";
93748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
93848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
93948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
94048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		map<string, string> params;
94148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		params.insert(pair<string, string>("VERTEX_DECLARATIONS", decl.str()));
94248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		params.insert(pair<string, string>("VERTEX_SETUP", setup.str()));
94348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		params.insert(pair<string, string>("VERTEX_OUTPUT", string("gl_Position = dEQP_Position;\n")));
94448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		StringTemplate tmpl(vertexSource);
94548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		outVertexSource = tmpl.specialize(params);
94648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
94748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
94848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	// Fragment shader specialization.
94948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
95048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ostringstream decl;
95148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ostringstream output;
95248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*   fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor";
95348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
95448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		genCompareFunctions(decl, valueBlock, false);
95548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		genCompareOp(output, fragColor, valueBlock, "", DE_NULL);
95648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
95748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (customColorOut)
95848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
95948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
96048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
96148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
96248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const ShaderCase::Value& val		= valueBlock.values[ndx];
96348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char*				 valueName  = val.valueName.c_str();
96448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			const char*				 refTypeStr = getDataTypeName(val.dataType);
96548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
96648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
96748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
96848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n";
96948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << refTypeStr << " " << valueName << ";\n";
97048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
97148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && val.valueName.find('.') == string::npos)
97248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
97348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				decl << "uniform " << refTypeStr << " " << valueName << ";\n";
97448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
97548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
97648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
97748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		map<string, string> params;
97848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		params.insert(pair<string, string>("FRAGMENT_DECLARATIONS", decl.str()));
97948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		params.insert(pair<string, string>("FRAGMENT_OUTPUT", output.str()));
98048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		params.insert(pair<string, string>("FRAG_COLOR", fragColor));
98148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		StringTemplate tmpl(fragmentSource);
98248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		outFragmentSource = tmpl.specialize(params);
98348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
98448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
98548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
98648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulosvoid ShaderCase::dumpValues(const ValueBlock& valueBlock, int arrayNdx)
98748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos{
98848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	vector<vector<float> > attribValues;
98948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
99048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	int numValues = (int)valueBlock.values.size();
99148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	for (int valNdx = 0; valNdx < numValues; valNdx++)
99248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	{
99348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const ShaderCase::Value& val		= valueBlock.values[valNdx];
99448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		const char*				 valueName  = val.valueName.c_str();
99548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		DataType				 dataType   = val.dataType;
99648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		int						 scalarSize = getDataTypeScalarSize(val.dataType);
99748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		ostringstream			 result;
99848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
99948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		result << "    ";
100048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (val.storageType == Value::STORAGE_INPUT)
100148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result << "input ";
100248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (val.storageType == Value::STORAGE_UNIFORM)
100348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result << "uniform ";
100448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (val.storageType == Value::STORAGE_OUTPUT)
100548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result << "expected ";
100648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
100748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		result << getDataTypeName(dataType) << " " << valueName << ":";
100848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
100948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (isDataTypeScalar(dataType))
101048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result << " ";
101148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (isDataTypeVector(dataType))
101248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result << " [ ";
101348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (isDataTypeMatrix(dataType))
101448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result << "\n";
101548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
101648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (isDataTypeScalarOrVector(dataType))
101748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
101848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
101948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
102048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				int					  elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx;
102148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				const Value::Element& e		  = val.elements[elemNdx * scalarSize + scalarNdx];
102248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				result << ((scalarNdx != 0) ? ", " : "");
102348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
102448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				if (isDataTypeFloatOrVec(dataType))
102548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					result << e.float32;
102648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				else if (isDataTypeIntOrIVec(dataType))
102748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					result << e.int32;
102848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				else if (isDataTypeBoolOrBVec(dataType))
102948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					result << (e.bool32 ? "true" : "false");
103048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
103148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
103248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (isDataTypeMatrix(dataType))
103348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		{
103448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int numRows = getDataTypeMatrixNumRows(dataType);
103548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			int numCols = getDataTypeMatrixNumColumns(dataType);
103648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
103748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			{
103848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				result << "       [ ";
103948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				for (int colNdx = 0; colNdx < numCols; colNdx++)
104048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				{
104148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					int   elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx;
104248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					float v		  = val.elements[elemNdx * scalarSize + rowNdx * numCols + colNdx].float32;
104348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos					result << ((colNdx == 0) ? "" : ", ") << v;
104448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				}
104548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos				result << " ]\n";
104648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			}
104748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		}
104848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
104948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		if (isDataTypeScalar(dataType))
105048087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result << "\n";
105148087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		else if (isDataTypeVector(dataType))
105248087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos			result << " ]\n";
105348087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
105448087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos		m_testCtx.getLog() << TestLog::Message << result.str() << TestLog::EndMessage;
105548087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos	}
105648087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos}
105748087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos
105848087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos} // sl
105948087f5f0eb08759ee763f98daf3b34becb74559Pyry Haulos} // deqp
1060