1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program OpenGL ES 2.0 Module
3e5c31af7Sopenharmony_ci * -------------------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief Texture unit usage tests.
22e5c31af7Sopenharmony_ci *
23e5c31af7Sopenharmony_ci * \todo [2012-07-12 nuutti] Come up with a good way to make these tests faster.
24e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ci#include "es2fTextureUnitTests.hpp"
27e5c31af7Sopenharmony_ci#include "glsTextureTestUtil.hpp"
28e5c31af7Sopenharmony_ci#include "gluTextureUtil.hpp"
29e5c31af7Sopenharmony_ci#include "gluContextInfo.hpp"
30e5c31af7Sopenharmony_ci#include "tcuTextureUtil.hpp"
31e5c31af7Sopenharmony_ci#include "tcuImageCompare.hpp"
32e5c31af7Sopenharmony_ci#include "tcuMatrix.hpp"
33e5c31af7Sopenharmony_ci#include "tcuRenderTarget.hpp"
34e5c31af7Sopenharmony_ci#include "sglrContextUtil.hpp"
35e5c31af7Sopenharmony_ci#include "sglrReferenceContext.hpp"
36e5c31af7Sopenharmony_ci#include "sglrGLContext.hpp"
37e5c31af7Sopenharmony_ci#include "deMath.h"
38e5c31af7Sopenharmony_ci#include "deStringUtil.hpp"
39e5c31af7Sopenharmony_ci#include "deRandom.hpp"
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
42e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
43e5c31af7Sopenharmony_ci
44e5c31af7Sopenharmony_ciusing tcu::Vec2;
45e5c31af7Sopenharmony_ciusing tcu::Vec3;
46e5c31af7Sopenharmony_ciusing tcu::Vec4;
47e5c31af7Sopenharmony_ciusing tcu::IVec2;
48e5c31af7Sopenharmony_ciusing tcu::Mat3;
49e5c31af7Sopenharmony_ciusing std::vector;
50e5c31af7Sopenharmony_ciusing std::string;
51e5c31af7Sopenharmony_ciusing namespace glw; // GL types
52e5c31af7Sopenharmony_ci
53e5c31af7Sopenharmony_cinamespace deqp
54e5c31af7Sopenharmony_ci{
55e5c31af7Sopenharmony_ci
56e5c31af7Sopenharmony_ciusing namespace gls::TextureTestUtil;
57e5c31af7Sopenharmony_ci
58e5c31af7Sopenharmony_cinamespace gles2
59e5c31af7Sopenharmony_ci{
60e5c31af7Sopenharmony_cinamespace Functional
61e5c31af7Sopenharmony_ci{
62e5c31af7Sopenharmony_ci
63e5c31af7Sopenharmony_cistatic const int VIEWPORT_WIDTH			= 128;
64e5c31af7Sopenharmony_cistatic const int VIEWPORT_HEIGHT		= 128;
65e5c31af7Sopenharmony_ci
66e5c31af7Sopenharmony_cistatic const int TEXTURE_WIDTH_2D		= 128;
67e5c31af7Sopenharmony_cistatic const int TEXTURE_HEIGHT_2D		= 128;
68e5c31af7Sopenharmony_ci
69e5c31af7Sopenharmony_ci// \note Cube map texture size is larger in order to make minifications possible - otherwise would need to display different faces at same time.
70e5c31af7Sopenharmony_cistatic const int TEXTURE_WIDTH_CUBE		= 256;
71e5c31af7Sopenharmony_cistatic const int TEXTURE_HEIGHT_CUBE	= 256;
72e5c31af7Sopenharmony_ci
73e5c31af7Sopenharmony_cistatic const int GRID_CELL_SIZE			= 8;
74e5c31af7Sopenharmony_ci
75e5c31af7Sopenharmony_cistatic const GLenum s_testFormats[] =
76e5c31af7Sopenharmony_ci{
77e5c31af7Sopenharmony_ci	GL_RGB,
78e5c31af7Sopenharmony_ci	GL_RGBA,
79e5c31af7Sopenharmony_ci	GL_ALPHA,
80e5c31af7Sopenharmony_ci	GL_LUMINANCE,
81e5c31af7Sopenharmony_ci	GL_LUMINANCE_ALPHA
82e5c31af7Sopenharmony_ci};
83e5c31af7Sopenharmony_ci
84e5c31af7Sopenharmony_cistatic const GLenum s_testDataTypes[] =
85e5c31af7Sopenharmony_ci{
86e5c31af7Sopenharmony_ci	GL_UNSIGNED_BYTE,
87e5c31af7Sopenharmony_ci	GL_UNSIGNED_SHORT_5_6_5,
88e5c31af7Sopenharmony_ci	GL_UNSIGNED_SHORT_4_4_4_4,
89e5c31af7Sopenharmony_ci	GL_UNSIGNED_SHORT_5_5_5_1,
90e5c31af7Sopenharmony_ci};
91e5c31af7Sopenharmony_ci
92e5c31af7Sopenharmony_cistatic const GLenum s_testWrapModes[] =
93e5c31af7Sopenharmony_ci{
94e5c31af7Sopenharmony_ci	GL_CLAMP_TO_EDGE,
95e5c31af7Sopenharmony_ci	GL_REPEAT,
96e5c31af7Sopenharmony_ci	GL_MIRRORED_REPEAT,
97e5c31af7Sopenharmony_ci};
98e5c31af7Sopenharmony_ci
99e5c31af7Sopenharmony_cistatic const GLenum s_testMinFilters[] =
100e5c31af7Sopenharmony_ci{
101e5c31af7Sopenharmony_ci	GL_NEAREST,
102e5c31af7Sopenharmony_ci	GL_LINEAR,
103e5c31af7Sopenharmony_ci	GL_NEAREST_MIPMAP_NEAREST,
104e5c31af7Sopenharmony_ci	GL_LINEAR_MIPMAP_NEAREST,
105e5c31af7Sopenharmony_ci	GL_NEAREST_MIPMAP_LINEAR,
106e5c31af7Sopenharmony_ci	GL_LINEAR_MIPMAP_LINEAR
107e5c31af7Sopenharmony_ci};
108e5c31af7Sopenharmony_ci
109e5c31af7Sopenharmony_cistatic const GLenum s_testNonMipmapMinFilters[] =
110e5c31af7Sopenharmony_ci{
111e5c31af7Sopenharmony_ci	GL_NEAREST,
112e5c31af7Sopenharmony_ci	GL_LINEAR
113e5c31af7Sopenharmony_ci};
114e5c31af7Sopenharmony_ci
115e5c31af7Sopenharmony_cistatic const GLenum s_testMagFilters[] =
116e5c31af7Sopenharmony_ci{
117e5c31af7Sopenharmony_ci	GL_NEAREST,
118e5c31af7Sopenharmony_ci	GL_LINEAR
119e5c31af7Sopenharmony_ci};
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_cistatic const GLenum s_cubeFaceTargets[] =
122e5c31af7Sopenharmony_ci{
123e5c31af7Sopenharmony_ci	GL_TEXTURE_CUBE_MAP_POSITIVE_X,
124e5c31af7Sopenharmony_ci	GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
125e5c31af7Sopenharmony_ci	GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
126e5c31af7Sopenharmony_ci	GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
127e5c31af7Sopenharmony_ci	GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
128e5c31af7Sopenharmony_ci	GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
129e5c31af7Sopenharmony_ci};
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_cistatic string generateMultiTexFragmentShader(int numUnits, const GLenum* unitTypes)
132e5c31af7Sopenharmony_ci{
133e5c31af7Sopenharmony_ci	// The fragment shader calculates the average of a set of textures.
134e5c31af7Sopenharmony_ci
135e5c31af7Sopenharmony_ci	string samplersStr;
136e5c31af7Sopenharmony_ci	string matricesStr;
137e5c31af7Sopenharmony_ci	string lookupsStr;
138e5c31af7Sopenharmony_ci
139e5c31af7Sopenharmony_ci	string colorMultiplier = "(1.0/" + de::toString(numUnits) + ".0)";
140e5c31af7Sopenharmony_ci
141e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < numUnits; ndx++)
142e5c31af7Sopenharmony_ci	{
143e5c31af7Sopenharmony_ci		string			ndxStr				= de::toString(ndx);
144e5c31af7Sopenharmony_ci		string			samplerName			= "u_sampler" + ndxStr;
145e5c31af7Sopenharmony_ci		string			transformationName	= "u_trans" + ndxStr;
146e5c31af7Sopenharmony_ci		const char*		samplerType			= unitTypes[ndx] == GL_TEXTURE_2D ? "sampler2D" : "samplerCube";
147e5c31af7Sopenharmony_ci		const char*		lookupFunc			= unitTypes[ndx] == GL_TEXTURE_2D ? "texture2D" : "textureCube";
148e5c31af7Sopenharmony_ci
149e5c31af7Sopenharmony_ci		samplersStr += string("") + "uniform mediump " + samplerType + " " + samplerName + ";\n";
150e5c31af7Sopenharmony_ci		matricesStr += "uniform mediump mat3 " + transformationName + ";\n";
151e5c31af7Sopenharmony_ci
152e5c31af7Sopenharmony_ci		string lookupCoord = transformationName + "*vec3(v_coord, 1.0)";
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci		if (unitTypes[ndx] == GL_TEXTURE_2D)
155e5c31af7Sopenharmony_ci			lookupCoord = "vec2(" + lookupCoord + ")";
156e5c31af7Sopenharmony_ci
157e5c31af7Sopenharmony_ci		lookupsStr += "\tcolor += " + colorMultiplier + "*" + lookupFunc + "(" + samplerName + ", " + lookupCoord + ");\n";
158e5c31af7Sopenharmony_ci	}
159e5c31af7Sopenharmony_ci
160e5c31af7Sopenharmony_ci	return
161e5c31af7Sopenharmony_ci		samplersStr +
162e5c31af7Sopenharmony_ci		matricesStr +
163e5c31af7Sopenharmony_ci		"varying mediump vec2 v_coord;\n"
164e5c31af7Sopenharmony_ci		"\n"
165e5c31af7Sopenharmony_ci		"void main (void)\n"
166e5c31af7Sopenharmony_ci		"{\n"
167e5c31af7Sopenharmony_ci		"	mediump vec4 color = vec4(0.0);\n" +
168e5c31af7Sopenharmony_ci		lookupsStr +
169e5c31af7Sopenharmony_ci		"	gl_FragColor = color;\n"
170e5c31af7Sopenharmony_ci		"}\n";
171e5c31af7Sopenharmony_ci}
172e5c31af7Sopenharmony_ci
173e5c31af7Sopenharmony_cistatic sglr::pdec::ShaderProgramDeclaration generateShaderProgramDeclaration (int numUnits, const GLenum* unitTypes)
174e5c31af7Sopenharmony_ci{
175e5c31af7Sopenharmony_ci	sglr::pdec::ShaderProgramDeclaration decl;
176e5c31af7Sopenharmony_ci
177e5c31af7Sopenharmony_ci	decl << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT);
178e5c31af7Sopenharmony_ci	decl << sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT);
179e5c31af7Sopenharmony_ci	decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
180e5c31af7Sopenharmony_ci	decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
181e5c31af7Sopenharmony_ci
182e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < numUnits; ++ndx)
183e5c31af7Sopenharmony_ci	{
184e5c31af7Sopenharmony_ci		string	samplerName			= "u_sampler" + de::toString(ndx);
185e5c31af7Sopenharmony_ci		string	transformationName	= "u_trans" + de::toString(ndx);
186e5c31af7Sopenharmony_ci
187e5c31af7Sopenharmony_ci		decl << sglr::pdec::Uniform(samplerName, (unitTypes[ndx] == GL_TEXTURE_2D) ? (glu::TYPE_SAMPLER_2D) : (glu::TYPE_SAMPLER_CUBE));
188e5c31af7Sopenharmony_ci		decl << sglr::pdec::Uniform(transformationName, glu::TYPE_FLOAT_MAT3);
189e5c31af7Sopenharmony_ci	}
190e5c31af7Sopenharmony_ci
191e5c31af7Sopenharmony_ci	decl << sglr::pdec::VertexSource("attribute highp vec4 a_position;\n"
192e5c31af7Sopenharmony_ci									 "attribute mediump vec2 a_coord;\n"
193e5c31af7Sopenharmony_ci									 "varying mediump vec2 v_coord;\n"
194e5c31af7Sopenharmony_ci									 "\n"
195e5c31af7Sopenharmony_ci									 "void main (void)\n"
196e5c31af7Sopenharmony_ci									 "{\n"
197e5c31af7Sopenharmony_ci									 "	gl_Position = a_position;\n"
198e5c31af7Sopenharmony_ci									 "	v_coord = a_coord;\n"
199e5c31af7Sopenharmony_ci									 "}\n");
200e5c31af7Sopenharmony_ci	decl << sglr::pdec::FragmentSource(generateMultiTexFragmentShader(numUnits, unitTypes));
201e5c31af7Sopenharmony_ci
202e5c31af7Sopenharmony_ci	return decl;
203e5c31af7Sopenharmony_ci}
204e5c31af7Sopenharmony_ci
205e5c31af7Sopenharmony_ci// Calculates values to be used in calculateLod().
206e5c31af7Sopenharmony_cistatic Vec4 calculateLodDerivateParts(const Mat3& transformation)
207e5c31af7Sopenharmony_ci{
208e5c31af7Sopenharmony_ci	// Calculate transformed coordinates of three corners.
209e5c31af7Sopenharmony_ci	Vec2 trans00 = (transformation * Vec3(0.0f, 0.0f, 1.0f)).xy();
210e5c31af7Sopenharmony_ci	Vec2 trans01 = (transformation * Vec3(0.0f, 1.0f, 1.0f)).xy();
211e5c31af7Sopenharmony_ci	Vec2 trans10 = (transformation * Vec3(1.0f, 0.0f, 1.0f)).xy();
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_ci	return Vec4(trans10.x() - trans00.x(),
214e5c31af7Sopenharmony_ci				trans01.x() - trans00.x(),
215e5c31af7Sopenharmony_ci				trans10.y() - trans00.y(),
216e5c31af7Sopenharmony_ci				trans01.y() - trans00.y());
217e5c31af7Sopenharmony_ci}
218e5c31af7Sopenharmony_ci
219e5c31af7Sopenharmony_ci// Calculates the maximum allowed lod from derivates
220e5c31af7Sopenharmony_cistatic float calculateLodMax(const Vec4& derivateParts, const tcu::IVec2& textureSize, const Vec2& screenDerivate)
221e5c31af7Sopenharmony_ci{
222e5c31af7Sopenharmony_ci	float dudx = derivateParts.x() * (float)textureSize.x() * screenDerivate.x();
223e5c31af7Sopenharmony_ci	float dudy = derivateParts.y() * (float)textureSize.x() * screenDerivate.y();
224e5c31af7Sopenharmony_ci	float dvdx = derivateParts.z() * (float)textureSize.y() * screenDerivate.x();
225e5c31af7Sopenharmony_ci	float dvdy = derivateParts.w() * (float)textureSize.y() * screenDerivate.y();
226e5c31af7Sopenharmony_ci
227e5c31af7Sopenharmony_ci	return deFloatLog2(de::max(de::abs(dudx), de::abs(dudy)) + de::max(de::abs(dvdx), de::abs(dvdy)));
228e5c31af7Sopenharmony_ci}
229e5c31af7Sopenharmony_ci
230e5c31af7Sopenharmony_ci// Calculates the minimum allowed lod from derivates
231e5c31af7Sopenharmony_cistatic float calculateLodMin(const Vec4& derivateParts, const tcu::IVec2& textureSize, const Vec2& screenDerivate)
232e5c31af7Sopenharmony_ci{
233e5c31af7Sopenharmony_ci	float dudx = derivateParts.x() * (float)textureSize.x() * screenDerivate.x();
234e5c31af7Sopenharmony_ci	float dudy = derivateParts.y() * (float)textureSize.x() * screenDerivate.y();
235e5c31af7Sopenharmony_ci	float dvdx = derivateParts.z() * (float)textureSize.y() * screenDerivate.x();
236e5c31af7Sopenharmony_ci	float dvdy = derivateParts.w() * (float)textureSize.y() * screenDerivate.y();
237e5c31af7Sopenharmony_ci
238e5c31af7Sopenharmony_ci	return deFloatLog2(de::max(de::max(de::abs(dudx), de::abs(dudy)), de::max(de::abs(dvdx), de::abs(dvdy))));
239e5c31af7Sopenharmony_ci}
240e5c31af7Sopenharmony_ci
241e5c31af7Sopenharmony_ciclass MultiTexShader : public sglr::ShaderProgram
242e5c31af7Sopenharmony_ci{
243e5c31af7Sopenharmony_cipublic:
244e5c31af7Sopenharmony_ci							MultiTexShader	(deUint32 randSeed, int numUnits, const vector<GLenum>& unitTypes);
245e5c31af7Sopenharmony_ci
246e5c31af7Sopenharmony_ci	void					setUniforms		(sglr::Context& context, deUint32 program) const;
247e5c31af7Sopenharmony_ci	void					makeSafeLods	(const vector<IVec2>& textureSizes, const IVec2& viewportSize); // Modifies texture coordinates so that LODs aren't too close to x.5 or 0.0 .
248e5c31af7Sopenharmony_ci
249e5c31af7Sopenharmony_ciprivate:
250e5c31af7Sopenharmony_ci	void					shadeVertices	(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
251e5c31af7Sopenharmony_ci	void					shadeFragments	(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
252e5c31af7Sopenharmony_ci
253e5c31af7Sopenharmony_ci	int						m_numUnits;
254e5c31af7Sopenharmony_ci	vector<GLenum>			m_unitTypes;		// 2d or cube map.
255e5c31af7Sopenharmony_ci	vector<Mat3>			m_transformations;
256e5c31af7Sopenharmony_ci	vector<Vec4>			m_lodDerivateParts;	// Parts of lod derivates; computed in init(), used in eval().
257e5c31af7Sopenharmony_ci};
258e5c31af7Sopenharmony_ci
259e5c31af7Sopenharmony_ciMultiTexShader::MultiTexShader (deUint32 randSeed, int numUnits, const vector<GLenum>& unitTypes)
260e5c31af7Sopenharmony_ci	: sglr::ShaderProgram	(generateShaderProgramDeclaration(numUnits, &unitTypes[0]))
261e5c31af7Sopenharmony_ci	, m_numUnits			(numUnits)
262e5c31af7Sopenharmony_ci	, m_unitTypes			(unitTypes)
263e5c31af7Sopenharmony_ci{
264e5c31af7Sopenharmony_ci	// 2d-to-cube-face transformations.
265e5c31af7Sopenharmony_ci	// \note 2d coordinates range from 0 to 1 and cube face coordinates from -1 to 1, so scaling is done as well.
266e5c31af7Sopenharmony_ci	static const float s_cubeTransforms[][3*3] =
267e5c31af7Sopenharmony_ci	{
268e5c31af7Sopenharmony_ci		// Face -X: (x, y, 1) -> (-1, -(2*y-1), +(2*x-1))
269e5c31af7Sopenharmony_ci		{  0.0f,  0.0f, -1.0f,
270e5c31af7Sopenharmony_ci		   0.0f, -2.0f,  1.0f,
271e5c31af7Sopenharmony_ci		   2.0f,  0.0f, -1.0f },
272e5c31af7Sopenharmony_ci		// Face +X: (x, y, 1) -> (+1, -(2*y-1), -(2*x-1))
273e5c31af7Sopenharmony_ci		{  0.0f,  0.0f,  1.0f,
274e5c31af7Sopenharmony_ci		   0.0f, -2.0f,  1.0f,
275e5c31af7Sopenharmony_ci		  -2.0f,  0.0f,  1.0f },
276e5c31af7Sopenharmony_ci		// Face -Y: (x, y, 1) -> (+(2*x-1), -1, -(2*y-1))
277e5c31af7Sopenharmony_ci		{  2.0f,  0.0f, -1.0f,
278e5c31af7Sopenharmony_ci		   0.0f,  0.0f, -1.0f,
279e5c31af7Sopenharmony_ci		   0.0f, -2.0f,  1.0f },
280e5c31af7Sopenharmony_ci		// Face +Y: (x, y, 1) -> (+(2*x-1), +1, +(2*y-1))
281e5c31af7Sopenharmony_ci		{  2.0f,  0.0f, -1.0f,
282e5c31af7Sopenharmony_ci		   0.0f,  0.0f,  1.0f,
283e5c31af7Sopenharmony_ci		   0.0f,  2.0f, -1.0f },
284e5c31af7Sopenharmony_ci		// Face -Z: (x, y, 1) -> (-(2*x-1), -(2*y-1), -1)
285e5c31af7Sopenharmony_ci		{ -2.0f,  0.0f,  1.0f,
286e5c31af7Sopenharmony_ci		   0.0f, -2.0f,  1.0f,
287e5c31af7Sopenharmony_ci		   0.0f,  0.0f, -1.0f },
288e5c31af7Sopenharmony_ci		// Face +Z: (x, y, 1) -> (+(2*x-1), -(2*y-1), +1)
289e5c31af7Sopenharmony_ci		{  2.0f,  0.0f, -1.0f,
290e5c31af7Sopenharmony_ci		   0.0f, -2.0f,  1.0f,
291e5c31af7Sopenharmony_ci		   0.0f,  0.0f,  1.0f }
292e5c31af7Sopenharmony_ci	};
293e5c31af7Sopenharmony_ci
294e5c31af7Sopenharmony_ci	// Generate transformation matrices.
295e5c31af7Sopenharmony_ci
296e5c31af7Sopenharmony_ci	de::Random rnd(randSeed);
297e5c31af7Sopenharmony_ci
298e5c31af7Sopenharmony_ci	m_transformations.reserve(m_numUnits);
299e5c31af7Sopenharmony_ci	m_lodDerivateParts.reserve(m_numUnits);
300e5c31af7Sopenharmony_ci
301e5c31af7Sopenharmony_ci	DE_ASSERT((int)m_unitTypes.size() == m_numUnits);
302e5c31af7Sopenharmony_ci
303e5c31af7Sopenharmony_ci	for (int unitNdx = 0; unitNdx < m_numUnits; unitNdx++)
304e5c31af7Sopenharmony_ci	{
305e5c31af7Sopenharmony_ci		if (m_unitTypes[unitNdx] == GL_TEXTURE_2D)
306e5c31af7Sopenharmony_ci		{
307e5c31af7Sopenharmony_ci			float rotAngle				= rnd.getFloat(0.0f, 2.0f*DE_PI);
308e5c31af7Sopenharmony_ci			float xScaleFactor			= rnd.getFloat(0.7f, 1.5f);
309e5c31af7Sopenharmony_ci			float yScaleFactor			= rnd.getFloat(0.7f, 1.5f);
310e5c31af7Sopenharmony_ci			float xShearAmount			= rnd.getFloat(0.0f, 0.5f);
311e5c31af7Sopenharmony_ci			float yShearAmount			= rnd.getFloat(0.0f, 0.5f);
312e5c31af7Sopenharmony_ci			float xTranslationAmount	= rnd.getFloat(-0.5f, 0.5f);
313e5c31af7Sopenharmony_ci			float yTranslationAmount	= rnd.getFloat(-0.5f, 0.5f);
314e5c31af7Sopenharmony_ci
315e5c31af7Sopenharmony_ci			float tempOffsetData[3*3] = // For temporarily centering the coordinates to get nicer transformations.
316e5c31af7Sopenharmony_ci			{
317e5c31af7Sopenharmony_ci				1.0f,  0.0f, -0.5f,
318e5c31af7Sopenharmony_ci				0.0f,  1.0f, -0.5f,
319e5c31af7Sopenharmony_ci				0.0f,  0.0f,  1.0f
320e5c31af7Sopenharmony_ci			};
321e5c31af7Sopenharmony_ci			float rotTransfData[3*3] =
322e5c31af7Sopenharmony_ci			{
323e5c31af7Sopenharmony_ci				deFloatCos(rotAngle),	-deFloatSin(rotAngle),	0.0f,
324e5c31af7Sopenharmony_ci				deFloatSin(rotAngle),	deFloatCos(rotAngle),	0.0f,
325e5c31af7Sopenharmony_ci				0.0f,					0.0f,					1.0f
326e5c31af7Sopenharmony_ci			};
327e5c31af7Sopenharmony_ci			float scaleTransfData[3*3] =
328e5c31af7Sopenharmony_ci			{
329e5c31af7Sopenharmony_ci				xScaleFactor,	0.0f,			0.0f,
330e5c31af7Sopenharmony_ci				0.0f,			yScaleFactor,	0.0f,
331e5c31af7Sopenharmony_ci				0.0f,			0.0f,			1.0f
332e5c31af7Sopenharmony_ci			};
333e5c31af7Sopenharmony_ci			float xShearTransfData[3*3] =
334e5c31af7Sopenharmony_ci			{
335e5c31af7Sopenharmony_ci				1.0f,			xShearAmount,	0.0f,
336e5c31af7Sopenharmony_ci				0.0f,			1.0f,			0.0f,
337e5c31af7Sopenharmony_ci				0.0f,			0.0f,			1.0f
338e5c31af7Sopenharmony_ci			};
339e5c31af7Sopenharmony_ci			float yShearTransfData[3*3] =
340e5c31af7Sopenharmony_ci			{
341e5c31af7Sopenharmony_ci				1.0f,			0.0f,			0.0f,
342e5c31af7Sopenharmony_ci				yShearAmount,	1.0f,			0.0f,
343e5c31af7Sopenharmony_ci				0.0f,			0.0f,			1.0f
344e5c31af7Sopenharmony_ci			};
345e5c31af7Sopenharmony_ci			float translationTransfData[3*3] =
346e5c31af7Sopenharmony_ci			{
347e5c31af7Sopenharmony_ci				1.0f,	0.0f,	xTranslationAmount,
348e5c31af7Sopenharmony_ci				0.0f,	1.0f,	yTranslationAmount,
349e5c31af7Sopenharmony_ci				0.0f,	0.0f,	1.0f
350e5c31af7Sopenharmony_ci			};
351e5c31af7Sopenharmony_ci
352e5c31af7Sopenharmony_ci			Mat3 transformation =
353e5c31af7Sopenharmony_ci				Mat3(tempOffsetData) *
354e5c31af7Sopenharmony_ci				Mat3(translationTransfData) *
355e5c31af7Sopenharmony_ci				Mat3(rotTransfData) *
356e5c31af7Sopenharmony_ci				Mat3(scaleTransfData) *
357e5c31af7Sopenharmony_ci				Mat3(xShearTransfData) *
358e5c31af7Sopenharmony_ci				Mat3(yShearTransfData) *
359e5c31af7Sopenharmony_ci				(Mat3(tempOffsetData) * (-1.0f));
360e5c31af7Sopenharmony_ci
361e5c31af7Sopenharmony_ci			// Calculate parts of lod derivates.
362e5c31af7Sopenharmony_ci			m_lodDerivateParts.push_back(calculateLodDerivateParts(transformation));
363e5c31af7Sopenharmony_ci
364e5c31af7Sopenharmony_ci			m_transformations.push_back(transformation);
365e5c31af7Sopenharmony_ci		}
366e5c31af7Sopenharmony_ci		else
367e5c31af7Sopenharmony_ci		{
368e5c31af7Sopenharmony_ci			DE_ASSERT(m_unitTypes[unitNdx] == GL_TEXTURE_CUBE_MAP);
369e5c31af7Sopenharmony_ci			DE_STATIC_ASSERT((int)tcu::CUBEFACE_LAST == DE_LENGTH_OF_ARRAY(s_cubeTransforms));
370e5c31af7Sopenharmony_ci
371e5c31af7Sopenharmony_ci			float planarTransData[3*3];
372e5c31af7Sopenharmony_ci
373e5c31af7Sopenharmony_ci			// In case of a cube map, we only want to render one face, so the transformation needs to be restricted - only enlarging scaling is done.
374e5c31af7Sopenharmony_ci
375e5c31af7Sopenharmony_ci			for (int i = 0; i < DE_LENGTH_OF_ARRAY(planarTransData); i++)
376e5c31af7Sopenharmony_ci			{
377e5c31af7Sopenharmony_ci				if (i == 0 || i == 4)
378e5c31af7Sopenharmony_ci					planarTransData[i] = rnd.getFloat(0.1f, 0.9f); // Two first diagonal cells control the scaling.
379e5c31af7Sopenharmony_ci				else if (i == 8)
380e5c31af7Sopenharmony_ci					planarTransData[i] = 1.0f;
381e5c31af7Sopenharmony_ci				else
382e5c31af7Sopenharmony_ci					planarTransData[i] = 0.0f;
383e5c31af7Sopenharmony_ci			}
384e5c31af7Sopenharmony_ci
385e5c31af7Sopenharmony_ci			int		faceNdx			= rnd.getInt(0, (int)tcu::CUBEFACE_LAST - 1);
386e5c31af7Sopenharmony_ci			Mat3	planarTrans		(planarTransData);									// Planar, face-agnostic transformation.
387e5c31af7Sopenharmony_ci			Mat3	finalTrans		= Mat3(s_cubeTransforms[faceNdx]) * planarTrans;	// Final transformation from planar to cube map coordinates, including the transformation just generated.
388e5c31af7Sopenharmony_ci
389e5c31af7Sopenharmony_ci			// Calculate parts of lod derivates.
390e5c31af7Sopenharmony_ci			m_lodDerivateParts.push_back(calculateLodDerivateParts(planarTrans));
391e5c31af7Sopenharmony_ci
392e5c31af7Sopenharmony_ci			m_transformations.push_back(finalTrans);
393e5c31af7Sopenharmony_ci		}
394e5c31af7Sopenharmony_ci	}
395e5c31af7Sopenharmony_ci}
396e5c31af7Sopenharmony_ci
397e5c31af7Sopenharmony_civoid MultiTexShader::setUniforms (sglr::Context& ctx, deUint32 program) const
398e5c31af7Sopenharmony_ci{
399e5c31af7Sopenharmony_ci	ctx.useProgram(program);
400e5c31af7Sopenharmony_ci
401e5c31af7Sopenharmony_ci	// Sampler and matrix uniforms.
402e5c31af7Sopenharmony_ci
403e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < m_numUnits; ndx++)
404e5c31af7Sopenharmony_ci	{
405e5c31af7Sopenharmony_ci		string			ndxStr		= de::toString(ndx);
406e5c31af7Sopenharmony_ci
407e5c31af7Sopenharmony_ci		ctx.uniform1i(ctx.getUniformLocation(program, ("u_sampler" + ndxStr).c_str()), ndx);
408e5c31af7Sopenharmony_ci		ctx.uniformMatrix3fv(ctx.getUniformLocation(program, ("u_trans" + ndxStr).c_str()), 1, GL_FALSE, (GLfloat*)&m_transformations[ndx].getColumnMajorData()[0]);
409e5c31af7Sopenharmony_ci	}
410e5c31af7Sopenharmony_ci}
411e5c31af7Sopenharmony_ci
412e5c31af7Sopenharmony_civoid MultiTexShader::makeSafeLods (const vector<IVec2>& textureSizes, const IVec2& viewportSize)
413e5c31af7Sopenharmony_ci{
414e5c31af7Sopenharmony_ci	DE_ASSERT((int)textureSizes.size() == m_numUnits);
415e5c31af7Sopenharmony_ci
416e5c31af7Sopenharmony_ci	static const float shrinkScaleMatData[3*3] =
417e5c31af7Sopenharmony_ci	{
418e5c31af7Sopenharmony_ci		0.95f,	0.0f,	0.0f,
419e5c31af7Sopenharmony_ci		0.0f,	0.95f,	0.0f,
420e5c31af7Sopenharmony_ci		0.0f,	0.0f,	1.0f
421e5c31af7Sopenharmony_ci	};
422e5c31af7Sopenharmony_ci	Mat3 shrinkScaleMat(shrinkScaleMatData);
423e5c31af7Sopenharmony_ci
424e5c31af7Sopenharmony_ci	Vec2 screenDerivate(1.0f / (float)viewportSize.x(), 1.0f / (float)viewportSize.y());
425e5c31af7Sopenharmony_ci
426e5c31af7Sopenharmony_ci	for (int unitNdx = 0; unitNdx < m_numUnits; unitNdx++)
427e5c31af7Sopenharmony_ci	{
428e5c31af7Sopenharmony_ci		// As long as LOD is too close to 0.0 or is positive and too close to a something-and-a-half (0.5, 1.5, 2.5 etc) or allowed lod range could round to different levels, zoom in a little to get a safer LOD.
429e5c31af7Sopenharmony_ci		for (;;)
430e5c31af7Sopenharmony_ci		{
431e5c31af7Sopenharmony_ci			const float threshold = 0.1f;
432e5c31af7Sopenharmony_ci			const float epsilon	= 0.01f;
433e5c31af7Sopenharmony_ci
434e5c31af7Sopenharmony_ci			const float lodMax = calculateLodMax(m_lodDerivateParts[unitNdx], textureSizes[unitNdx], screenDerivate);
435e5c31af7Sopenharmony_ci			const float lodMin = calculateLodMin(m_lodDerivateParts[unitNdx], textureSizes[unitNdx], screenDerivate);
436e5c31af7Sopenharmony_ci
437e5c31af7Sopenharmony_ci			const deInt32 maxLevel = (lodMax + epsilon < 0.5f) ? (0) : (deCeilFloatToInt32(lodMax + epsilon + 0.5f) - 1);
438e5c31af7Sopenharmony_ci			const deInt32 minLevel = (lodMin - epsilon < 0.5f) ? (0) : (deCeilFloatToInt32(lodMin - epsilon + 0.5f) - 1);
439e5c31af7Sopenharmony_ci
440e5c31af7Sopenharmony_ci			if (de::abs(lodMax) < threshold || (lodMax > 0.0f && de::abs(deFloatFrac(lodMax) - 0.5f) < threshold) ||
441e5c31af7Sopenharmony_ci				de::abs(lodMin) < threshold || (lodMin > 0.0f && de::abs(deFloatFrac(lodMin) - 0.5f) < threshold) ||
442e5c31af7Sopenharmony_ci				maxLevel != minLevel)
443e5c31af7Sopenharmony_ci			{
444e5c31af7Sopenharmony_ci				m_transformations[unitNdx] = shrinkScaleMat * m_transformations[unitNdx];
445e5c31af7Sopenharmony_ci				m_lodDerivateParts[unitNdx] = calculateLodDerivateParts(m_transformations[unitNdx]);
446e5c31af7Sopenharmony_ci			}
447e5c31af7Sopenharmony_ci			else
448e5c31af7Sopenharmony_ci				break;
449e5c31af7Sopenharmony_ci		}
450e5c31af7Sopenharmony_ci	}
451e5c31af7Sopenharmony_ci}
452e5c31af7Sopenharmony_ci
453e5c31af7Sopenharmony_civoid MultiTexShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
454e5c31af7Sopenharmony_ci{
455e5c31af7Sopenharmony_ci	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
456e5c31af7Sopenharmony_ci	{
457e5c31af7Sopenharmony_ci		rr::VertexPacket& packet = *(packets[packetNdx]);
458e5c31af7Sopenharmony_ci
459e5c31af7Sopenharmony_ci		packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
460e5c31af7Sopenharmony_ci		packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
461e5c31af7Sopenharmony_ci	}
462e5c31af7Sopenharmony_ci}
463e5c31af7Sopenharmony_ci
464e5c31af7Sopenharmony_civoid MultiTexShader::shadeFragments	(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
465e5c31af7Sopenharmony_ci{
466e5c31af7Sopenharmony_ci	DE_ASSERT((int)m_unitTypes.size() == m_numUnits);
467e5c31af7Sopenharmony_ci	DE_ASSERT((int)m_transformations.size() == m_numUnits);
468e5c31af7Sopenharmony_ci	DE_ASSERT((int)m_lodDerivateParts.size() == m_numUnits);
469e5c31af7Sopenharmony_ci
470e5c31af7Sopenharmony_ci	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
471e5c31af7Sopenharmony_ci	{
472e5c31af7Sopenharmony_ci		rr::FragmentPacket& packet				= packets[packetNdx];
473e5c31af7Sopenharmony_ci		const float			colorMultiplier		= 1.0f / (float)m_numUnits;
474e5c31af7Sopenharmony_ci		Vec4				outColors[4]		= { Vec4(0.0f), Vec4(0.0f), Vec4(0.0f), Vec4(0.0f) };
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_ci		for (int unitNdx = 0; unitNdx < m_numUnits; unitNdx++)
477e5c31af7Sopenharmony_ci		{
478e5c31af7Sopenharmony_ci			tcu::Vec4 texSamples[4];
479e5c31af7Sopenharmony_ci
480e5c31af7Sopenharmony_ci			// Read tex coords
481e5c31af7Sopenharmony_ci			const tcu::Vec2 texCoords[4] =
482e5c31af7Sopenharmony_ci			{
483e5c31af7Sopenharmony_ci				rr::readTriangleVarying<float>(packet, context, 0, 0).xy(),
484e5c31af7Sopenharmony_ci				rr::readTriangleVarying<float>(packet, context, 0, 1).xy(),
485e5c31af7Sopenharmony_ci				rr::readTriangleVarying<float>(packet, context, 0, 2).xy(),
486e5c31af7Sopenharmony_ci				rr::readTriangleVarying<float>(packet, context, 0, 3).xy(),
487e5c31af7Sopenharmony_ci			};
488e5c31af7Sopenharmony_ci
489e5c31af7Sopenharmony_ci			if (m_unitTypes[unitNdx] == GL_TEXTURE_2D)
490e5c31af7Sopenharmony_ci			{
491e5c31af7Sopenharmony_ci				// Transform
492e5c31af7Sopenharmony_ci				const tcu::Vec2 transformedTexCoords[4] =
493e5c31af7Sopenharmony_ci				{
494e5c31af7Sopenharmony_ci					(m_transformations[unitNdx] * Vec3(texCoords[0].x(), texCoords[0].y(), 1.0f)).xy(),
495e5c31af7Sopenharmony_ci					(m_transformations[unitNdx] * Vec3(texCoords[1].x(), texCoords[1].y(), 1.0f)).xy(),
496e5c31af7Sopenharmony_ci					(m_transformations[unitNdx] * Vec3(texCoords[2].x(), texCoords[2].y(), 1.0f)).xy(),
497e5c31af7Sopenharmony_ci					(m_transformations[unitNdx] * Vec3(texCoords[3].x(), texCoords[3].y(), 1.0f)).xy(),
498e5c31af7Sopenharmony_ci				};
499e5c31af7Sopenharmony_ci
500e5c31af7Sopenharmony_ci				// Sample
501e5c31af7Sopenharmony_ci				m_uniforms[2*unitNdx].sampler.tex2D->sample4(texSamples, transformedTexCoords);
502e5c31af7Sopenharmony_ci			}
503e5c31af7Sopenharmony_ci			else
504e5c31af7Sopenharmony_ci			{
505e5c31af7Sopenharmony_ci				DE_ASSERT(m_unitTypes[unitNdx] == GL_TEXTURE_CUBE_MAP);
506e5c31af7Sopenharmony_ci
507e5c31af7Sopenharmony_ci				// Transform
508e5c31af7Sopenharmony_ci				const tcu::Vec3 transformedTexCoords[4] =
509e5c31af7Sopenharmony_ci				{
510e5c31af7Sopenharmony_ci					m_transformations[unitNdx] * Vec3(texCoords[0].x(), texCoords[0].y(), 1.0f),
511e5c31af7Sopenharmony_ci					m_transformations[unitNdx] * Vec3(texCoords[1].x(), texCoords[1].y(), 1.0f),
512e5c31af7Sopenharmony_ci					m_transformations[unitNdx] * Vec3(texCoords[2].x(), texCoords[2].y(), 1.0f),
513e5c31af7Sopenharmony_ci					m_transformations[unitNdx] * Vec3(texCoords[3].x(), texCoords[3].y(), 1.0f),
514e5c31af7Sopenharmony_ci				};
515e5c31af7Sopenharmony_ci
516e5c31af7Sopenharmony_ci				// Sample
517e5c31af7Sopenharmony_ci				m_uniforms[2*unitNdx].sampler.texCube->sample4(texSamples, transformedTexCoords);
518e5c31af7Sopenharmony_ci			}
519e5c31af7Sopenharmony_ci
520e5c31af7Sopenharmony_ci			// Add to sum
521e5c31af7Sopenharmony_ci			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
522e5c31af7Sopenharmony_ci				outColors[fragNdx] += colorMultiplier * texSamples[fragNdx];
523e5c31af7Sopenharmony_ci		}
524e5c31af7Sopenharmony_ci
525e5c31af7Sopenharmony_ci		// output
526e5c31af7Sopenharmony_ci		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
527e5c31af7Sopenharmony_ci			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, outColors[fragNdx]);
528e5c31af7Sopenharmony_ci	}
529e5c31af7Sopenharmony_ci}
530e5c31af7Sopenharmony_ci
531e5c31af7Sopenharmony_ciclass TextureUnitCase : public TestCase
532e5c31af7Sopenharmony_ci{
533e5c31af7Sopenharmony_cipublic:
534e5c31af7Sopenharmony_ci	enum CaseType
535e5c31af7Sopenharmony_ci	{
536e5c31af7Sopenharmony_ci		CASE_ONLY_2D = 0,
537e5c31af7Sopenharmony_ci		CASE_ONLY_CUBE,
538e5c31af7Sopenharmony_ci		CASE_MIXED,
539e5c31af7Sopenharmony_ci
540e5c31af7Sopenharmony_ci		CASE_LAST
541e5c31af7Sopenharmony_ci	};
542e5c31af7Sopenharmony_ci								TextureUnitCase		(Context& context, const char* name, const char* desc, int numUnits /* \note If non-positive, use all units */, CaseType caseType, deUint32 randSeed);
543e5c31af7Sopenharmony_ci								~TextureUnitCase	(void);
544e5c31af7Sopenharmony_ci
545e5c31af7Sopenharmony_ci	void						init				(void);
546e5c31af7Sopenharmony_ci	void						deinit				(void);
547e5c31af7Sopenharmony_ci	IterateResult				iterate				(void);
548e5c31af7Sopenharmony_ci
549e5c31af7Sopenharmony_ciprivate:
550e5c31af7Sopenharmony_ci	struct TextureParameters
551e5c31af7Sopenharmony_ci	{
552e5c31af7Sopenharmony_ci		GLenum format;
553e5c31af7Sopenharmony_ci		GLenum dataType;
554e5c31af7Sopenharmony_ci		GLenum wrapModeS;
555e5c31af7Sopenharmony_ci		GLenum wrapModeT;
556e5c31af7Sopenharmony_ci		GLenum minFilter;
557e5c31af7Sopenharmony_ci		GLenum magFilter;
558e5c31af7Sopenharmony_ci	};
559e5c31af7Sopenharmony_ci
560e5c31af7Sopenharmony_ci								TextureUnitCase		(const TextureUnitCase& other);
561e5c31af7Sopenharmony_ci	TextureUnitCase&			operator=			(const TextureUnitCase& other);
562e5c31af7Sopenharmony_ci
563e5c31af7Sopenharmony_ci	void						render				(sglr::Context& context);
564e5c31af7Sopenharmony_ci
565e5c31af7Sopenharmony_ci	const int					m_numUnitsParam;
566e5c31af7Sopenharmony_ci	const CaseType				m_caseType;
567e5c31af7Sopenharmony_ci	const deUint32				m_randSeed;
568e5c31af7Sopenharmony_ci
569e5c31af7Sopenharmony_ci	int							m_numTextures;	//!< \note Needed in addition to m_numUnits since same texture may be bound to many texture units.
570e5c31af7Sopenharmony_ci	int							m_numUnits;		//!< = m_numUnitsParam > 0 ? m_numUnitsParam : implementationDefinedMaximum
571e5c31af7Sopenharmony_ci
572e5c31af7Sopenharmony_ci	vector<GLenum>				m_textureTypes;
573e5c31af7Sopenharmony_ci	vector<TextureParameters>	m_textureParams;
574e5c31af7Sopenharmony_ci	vector<tcu::Texture2D*>		m_textures2d;
575e5c31af7Sopenharmony_ci	vector<tcu::TextureCube*>	m_texturesCube;
576e5c31af7Sopenharmony_ci	vector<int>					m_unitTextures;	//!< Which texture is used in a particular unit.
577e5c31af7Sopenharmony_ci	vector<int>					m_ndx2dOrCube;	//!< Index of a texture in either m_textures2d or m_texturesCube, depending on texture type.
578e5c31af7Sopenharmony_ci	MultiTexShader*				m_shader;
579e5c31af7Sopenharmony_ci};
580e5c31af7Sopenharmony_ci
581e5c31af7Sopenharmony_ciTextureUnitCase::TextureUnitCase (Context& context, const char* name, const char* desc, int numUnits, CaseType caseType, deUint32 randSeed)
582e5c31af7Sopenharmony_ci	: TestCase			(context, tcu::NODETYPE_SELF_VALIDATE, name, desc)
583e5c31af7Sopenharmony_ci	, m_numUnitsParam	(numUnits)
584e5c31af7Sopenharmony_ci	, m_caseType		(caseType)
585e5c31af7Sopenharmony_ci	, m_randSeed		(randSeed)
586e5c31af7Sopenharmony_ci	, m_numTextures		(0)
587e5c31af7Sopenharmony_ci	, m_numUnits		(0)
588e5c31af7Sopenharmony_ci	, m_shader			(DE_NULL)
589e5c31af7Sopenharmony_ci{
590e5c31af7Sopenharmony_ci}
591e5c31af7Sopenharmony_ci
592e5c31af7Sopenharmony_ciTextureUnitCase::~TextureUnitCase (void)
593e5c31af7Sopenharmony_ci{
594e5c31af7Sopenharmony_ci	TextureUnitCase::deinit();
595e5c31af7Sopenharmony_ci}
596e5c31af7Sopenharmony_ci
597e5c31af7Sopenharmony_civoid TextureUnitCase::deinit (void)
598e5c31af7Sopenharmony_ci{
599e5c31af7Sopenharmony_ci	for (vector<tcu::Texture2D*>::iterator i = m_textures2d.begin(); i != m_textures2d.end(); i++)
600e5c31af7Sopenharmony_ci		delete *i;
601e5c31af7Sopenharmony_ci	m_textures2d.clear();
602e5c31af7Sopenharmony_ci
603e5c31af7Sopenharmony_ci	for (vector<tcu::TextureCube*>::iterator i = m_texturesCube.begin(); i != m_texturesCube.end(); i++)
604e5c31af7Sopenharmony_ci		delete *i;
605e5c31af7Sopenharmony_ci	m_texturesCube.clear();
606e5c31af7Sopenharmony_ci
607e5c31af7Sopenharmony_ci	delete m_shader;
608e5c31af7Sopenharmony_ci	m_shader = DE_NULL;
609e5c31af7Sopenharmony_ci}
610e5c31af7Sopenharmony_ci
611e5c31af7Sopenharmony_civoid TextureUnitCase::init (void)
612e5c31af7Sopenharmony_ci{
613e5c31af7Sopenharmony_ci	m_numUnits = m_numUnitsParam > 0 ? m_numUnitsParam : m_context.getContextInfo().getInt(GL_MAX_TEXTURE_IMAGE_UNITS);
614e5c31af7Sopenharmony_ci
615e5c31af7Sopenharmony_ci	// Make the textures.
616e5c31af7Sopenharmony_ci
617e5c31af7Sopenharmony_ci	try
618e5c31af7Sopenharmony_ci	{
619e5c31af7Sopenharmony_ci		tcu::TestLog&	log	= m_testCtx.getLog();
620e5c31af7Sopenharmony_ci		de::Random		rnd	(m_randSeed);
621e5c31af7Sopenharmony_ci
622e5c31af7Sopenharmony_ci		if (rnd.getFloat() < 0.7f)
623e5c31af7Sopenharmony_ci			m_numTextures = m_numUnits;											// In most cases use one unit per texture.
624e5c31af7Sopenharmony_ci		else
625e5c31af7Sopenharmony_ci			m_numTextures = rnd.getInt(deMax32(1, m_numUnits - 2), m_numUnits);	// Sometimes assign same texture to multiple units.
626e5c31af7Sopenharmony_ci
627e5c31af7Sopenharmony_ci		log << tcu::TestLog::Message << ("Using " + de::toString(m_numUnits) + " texture unit(s) and " + de::toString(m_numTextures) + " texture(s)").c_str() << tcu::TestLog::EndMessage;
628e5c31af7Sopenharmony_ci
629e5c31af7Sopenharmony_ci		m_textureTypes.reserve(m_numTextures);
630e5c31af7Sopenharmony_ci		m_textureParams.reserve(m_numTextures);
631e5c31af7Sopenharmony_ci		m_ndx2dOrCube.reserve(m_numTextures);
632e5c31af7Sopenharmony_ci
633e5c31af7Sopenharmony_ci		// Generate textures.
634e5c31af7Sopenharmony_ci
635e5c31af7Sopenharmony_ci		for (int texNdx = 0; texNdx < m_numTextures; texNdx++)
636e5c31af7Sopenharmony_ci		{
637e5c31af7Sopenharmony_ci			// Either fixed or randomized target types (2d or cube), and randomized parameters for every texture.
638e5c31af7Sopenharmony_ci
639e5c31af7Sopenharmony_ci			TextureParameters	params;
640e5c31af7Sopenharmony_ci			bool				is2d		= m_caseType == CASE_ONLY_2D	? true :
641e5c31af7Sopenharmony_ci											  m_caseType == CASE_ONLY_CUBE	? false :
642e5c31af7Sopenharmony_ci																			  rnd.getBool();
643e5c31af7Sopenharmony_ci
644e5c31af7Sopenharmony_ci			GLenum				type		= is2d ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP;
645e5c31af7Sopenharmony_ci			const int			texWidth	= is2d ? TEXTURE_WIDTH_2D : TEXTURE_WIDTH_CUBE;
646e5c31af7Sopenharmony_ci			const int			texHeight	= is2d ? TEXTURE_HEIGHT_2D : TEXTURE_HEIGHT_CUBE;
647e5c31af7Sopenharmony_ci			bool				mipmaps		= (deIsPowerOfTwo32(texWidth) && deIsPowerOfTwo32(texHeight));
648e5c31af7Sopenharmony_ci			int					numLevels	= mipmaps ? deLog2Floor32(de::max(texWidth, texHeight))+1 : 1;
649e5c31af7Sopenharmony_ci
650e5c31af7Sopenharmony_ci			params.wrapModeS	= s_testWrapModes	[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testWrapModes) - 1)];
651e5c31af7Sopenharmony_ci			params.wrapModeT	= s_testWrapModes	[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testWrapModes) - 1)];
652e5c31af7Sopenharmony_ci			params.magFilter	= s_testMagFilters	[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testMagFilters) - 1)];
653e5c31af7Sopenharmony_ci			params.dataType		= s_testDataTypes	[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testDataTypes) - 1)];
654e5c31af7Sopenharmony_ci
655e5c31af7Sopenharmony_ci			// Certain minification filters are only used when using mipmaps.
656e5c31af7Sopenharmony_ci			if (mipmaps)
657e5c31af7Sopenharmony_ci				params.minFilter = s_testMinFilters[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testMinFilters) - 1)];
658e5c31af7Sopenharmony_ci			else
659e5c31af7Sopenharmony_ci				params.minFilter = s_testNonMipmapMinFilters[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testNonMipmapMinFilters) - 1)];
660e5c31af7Sopenharmony_ci
661e5c31af7Sopenharmony_ci			// Format may depend on data type.
662e5c31af7Sopenharmony_ci			if (params.dataType == GL_UNSIGNED_SHORT_5_6_5)
663e5c31af7Sopenharmony_ci				params.format = GL_RGB;
664e5c31af7Sopenharmony_ci			else if (params.dataType == GL_UNSIGNED_SHORT_4_4_4_4 || params.dataType == GL_UNSIGNED_SHORT_5_5_5_1)
665e5c31af7Sopenharmony_ci				params.format = GL_RGBA;
666e5c31af7Sopenharmony_ci			else
667e5c31af7Sopenharmony_ci				params.format = s_testFormats[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testFormats) - 1)];
668e5c31af7Sopenharmony_ci
669e5c31af7Sopenharmony_ci			m_textureTypes.push_back(type);
670e5c31af7Sopenharmony_ci			m_textureParams.push_back(params);
671e5c31af7Sopenharmony_ci
672e5c31af7Sopenharmony_ci			// Create new texture.
673e5c31af7Sopenharmony_ci
674e5c31af7Sopenharmony_ci			if (is2d)
675e5c31af7Sopenharmony_ci			{
676e5c31af7Sopenharmony_ci				m_ndx2dOrCube.push_back((int)m_textures2d.size()); // Remember the index this texture has in the 2d array.
677e5c31af7Sopenharmony_ci				m_textures2d.push_back(new tcu::Texture2D(glu::mapGLTransferFormat(params.format, params.dataType), texWidth, texHeight, isES2Context(m_context.getRenderContext().getType())));
678e5c31af7Sopenharmony_ci			}
679e5c31af7Sopenharmony_ci			else
680e5c31af7Sopenharmony_ci			{
681e5c31af7Sopenharmony_ci				m_ndx2dOrCube.push_back((int)m_texturesCube.size()); // Remember the index this texture has in the cube array.
682e5c31af7Sopenharmony_ci				DE_ASSERT(texWidth == texHeight);
683e5c31af7Sopenharmony_ci				m_texturesCube.push_back(new tcu::TextureCube(glu::mapGLTransferFormat(params.format, params.dataType), texWidth));
684e5c31af7Sopenharmony_ci			}
685e5c31af7Sopenharmony_ci
686e5c31af7Sopenharmony_ci			tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(is2d ? m_textures2d.back()->getFormat() : m_texturesCube.back()->getFormat());
687e5c31af7Sopenharmony_ci			Vec4					cBias		= fmtInfo.valueMin;
688e5c31af7Sopenharmony_ci			Vec4					cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
689e5c31af7Sopenharmony_ci
690e5c31af7Sopenharmony_ci			// Fill with grid texture.
691e5c31af7Sopenharmony_ci
692e5c31af7Sopenharmony_ci			int numFaces = is2d ? 1 : (int)tcu::CUBEFACE_LAST;
693e5c31af7Sopenharmony_ci
694e5c31af7Sopenharmony_ci			for (int face = 0; face < numFaces; face++)
695e5c31af7Sopenharmony_ci			{
696e5c31af7Sopenharmony_ci				deUint32 rgb	= rnd.getUint32() & 0x00ffffff;
697e5c31af7Sopenharmony_ci				deUint32 alpha0	= 0xff000000;
698e5c31af7Sopenharmony_ci				deUint32 alpha1	= 0xff000000;
699e5c31af7Sopenharmony_ci
700e5c31af7Sopenharmony_ci				if (params.format == GL_ALPHA) // \note This needs alpha to be visible.
701e5c31af7Sopenharmony_ci				{
702e5c31af7Sopenharmony_ci					alpha0 &= rnd.getUint32();
703e5c31af7Sopenharmony_ci					alpha1 = ~alpha0;
704e5c31af7Sopenharmony_ci				}
705e5c31af7Sopenharmony_ci
706e5c31af7Sopenharmony_ci				deUint32 colorA = alpha0 | rgb;
707e5c31af7Sopenharmony_ci				deUint32 colorB = alpha1 | ~rgb;
708e5c31af7Sopenharmony_ci
709e5c31af7Sopenharmony_ci				for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
710e5c31af7Sopenharmony_ci				{
711e5c31af7Sopenharmony_ci					if (is2d)
712e5c31af7Sopenharmony_ci						m_textures2d.back()->allocLevel(levelNdx);
713e5c31af7Sopenharmony_ci					else
714e5c31af7Sopenharmony_ci						m_texturesCube.back()->allocLevel((tcu::CubeFace)face, levelNdx);
715e5c31af7Sopenharmony_ci
716e5c31af7Sopenharmony_ci					int curCellSize = deMax32(1, GRID_CELL_SIZE >> levelNdx); // \note Scale grid cell size for mipmaps.
717e5c31af7Sopenharmony_ci
718e5c31af7Sopenharmony_ci					tcu::PixelBufferAccess access = is2d ? m_textures2d.back()->getLevel(levelNdx) : m_texturesCube.back()->getLevelFace(levelNdx, (tcu::CubeFace)face);
719e5c31af7Sopenharmony_ci					tcu::fillWithGrid(access, curCellSize, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
720e5c31af7Sopenharmony_ci				}
721e5c31af7Sopenharmony_ci			}
722e5c31af7Sopenharmony_ci		}
723e5c31af7Sopenharmony_ci
724e5c31af7Sopenharmony_ci		// Assign a texture index to each unit.
725e5c31af7Sopenharmony_ci
726e5c31af7Sopenharmony_ci		m_unitTextures.reserve(m_numUnits);
727e5c31af7Sopenharmony_ci
728e5c31af7Sopenharmony_ci		// \note Every texture is used at least once.
729e5c31af7Sopenharmony_ci		for (int i = 0; i < m_numTextures; i++)
730e5c31af7Sopenharmony_ci			m_unitTextures.push_back(i);
731e5c31af7Sopenharmony_ci
732e5c31af7Sopenharmony_ci		// Assign a random texture to remaining units.
733e5c31af7Sopenharmony_ci		while ((int)m_unitTextures.size() < m_numUnits)
734e5c31af7Sopenharmony_ci			m_unitTextures.push_back(rnd.getInt(0, m_numTextures - 1));
735e5c31af7Sopenharmony_ci
736e5c31af7Sopenharmony_ci		rnd.shuffle(m_unitTextures.begin(), m_unitTextures.end());
737e5c31af7Sopenharmony_ci
738e5c31af7Sopenharmony_ci		// Create shader.
739e5c31af7Sopenharmony_ci
740e5c31af7Sopenharmony_ci		vector<GLenum> unitTypes;
741e5c31af7Sopenharmony_ci		unitTypes.reserve(m_numUnits);
742e5c31af7Sopenharmony_ci		for (int i = 0; i < m_numUnits; i++)
743e5c31af7Sopenharmony_ci			unitTypes.push_back(m_textureTypes[m_unitTextures[i]]);
744e5c31af7Sopenharmony_ci
745e5c31af7Sopenharmony_ci		DE_ASSERT(m_shader == DE_NULL);
746e5c31af7Sopenharmony_ci		m_shader = new MultiTexShader(rnd.getUint32(), m_numUnits, unitTypes);
747e5c31af7Sopenharmony_ci	}
748e5c31af7Sopenharmony_ci	catch (const std::exception&)
749e5c31af7Sopenharmony_ci	{
750e5c31af7Sopenharmony_ci		// Clean up to save memory.
751e5c31af7Sopenharmony_ci		TextureUnitCase::deinit();
752e5c31af7Sopenharmony_ci		throw;
753e5c31af7Sopenharmony_ci	}
754e5c31af7Sopenharmony_ci}
755e5c31af7Sopenharmony_ci
756e5c31af7Sopenharmony_ciTextureUnitCase::IterateResult TextureUnitCase::iterate (void)
757e5c31af7Sopenharmony_ci{
758e5c31af7Sopenharmony_ci	glu::RenderContext&			renderCtx			= m_context.getRenderContext();
759e5c31af7Sopenharmony_ci	const tcu::RenderTarget&	renderTarget		= renderCtx.getRenderTarget();
760e5c31af7Sopenharmony_ci	tcu::TestLog&				log					= m_testCtx.getLog();
761e5c31af7Sopenharmony_ci	de::Random					rnd					(m_randSeed);
762e5c31af7Sopenharmony_ci
763e5c31af7Sopenharmony_ci	int							viewportWidth		= deMin32(VIEWPORT_WIDTH, renderTarget.getWidth());
764e5c31af7Sopenharmony_ci	int							viewportHeight		= deMin32(VIEWPORT_HEIGHT, renderTarget.getHeight());
765e5c31af7Sopenharmony_ci	int							viewportX			= rnd.getInt(0, renderTarget.getWidth() - viewportWidth);
766e5c31af7Sopenharmony_ci	int							viewportY			= rnd.getInt(0, renderTarget.getHeight() - viewportHeight);
767e5c31af7Sopenharmony_ci
768e5c31af7Sopenharmony_ci	tcu::Surface				gles2Frame			(viewportWidth, viewportHeight);
769e5c31af7Sopenharmony_ci	tcu::Surface				refFrame			(viewportWidth, viewportHeight);
770e5c31af7Sopenharmony_ci
771e5c31af7Sopenharmony_ci	{
772e5c31af7Sopenharmony_ci		// First we do some tricks to make the LODs safer wrt. precision issues. See MultiTexShader::makeSafeLods().
773e5c31af7Sopenharmony_ci
774e5c31af7Sopenharmony_ci		vector<IVec2> texSizes;
775e5c31af7Sopenharmony_ci		texSizes.reserve(m_numUnits);
776e5c31af7Sopenharmony_ci
777e5c31af7Sopenharmony_ci		for (int i = 0; i < m_numUnits; i++)
778e5c31af7Sopenharmony_ci		{
779e5c31af7Sopenharmony_ci			int		texNdx			= m_unitTextures[i];
780e5c31af7Sopenharmony_ci			int		texNdxInType	= m_ndx2dOrCube[texNdx];
781e5c31af7Sopenharmony_ci			GLenum	type			= m_textureTypes[texNdx];
782e5c31af7Sopenharmony_ci
783e5c31af7Sopenharmony_ci			switch (type)
784e5c31af7Sopenharmony_ci			{
785e5c31af7Sopenharmony_ci				case GL_TEXTURE_2D:			texSizes.push_back(IVec2(m_textures2d[texNdxInType]->getWidth(),	m_textures2d[texNdxInType]->getHeight()));	break;
786e5c31af7Sopenharmony_ci				case GL_TEXTURE_CUBE_MAP:	texSizes.push_back(IVec2(m_texturesCube[texNdxInType]->getSize(),	m_texturesCube[texNdxInType]->getSize()));	break;
787e5c31af7Sopenharmony_ci				default:
788e5c31af7Sopenharmony_ci					DE_ASSERT(DE_FALSE);
789e5c31af7Sopenharmony_ci			}
790e5c31af7Sopenharmony_ci		}
791e5c31af7Sopenharmony_ci
792e5c31af7Sopenharmony_ci		m_shader->makeSafeLods(texSizes, IVec2(viewportWidth, viewportHeight));
793e5c31af7Sopenharmony_ci	}
794e5c31af7Sopenharmony_ci
795e5c31af7Sopenharmony_ci	// Render using GLES2.
796e5c31af7Sopenharmony_ci	{
797e5c31af7Sopenharmony_ci		sglr::GLContext context(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS|sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(viewportX, viewportY, viewportWidth, viewportHeight));
798e5c31af7Sopenharmony_ci
799e5c31af7Sopenharmony_ci		render(context);
800e5c31af7Sopenharmony_ci
801e5c31af7Sopenharmony_ci		context.readPixels(gles2Frame, 0, 0, viewportWidth, viewportHeight);
802e5c31af7Sopenharmony_ci	}
803e5c31af7Sopenharmony_ci
804e5c31af7Sopenharmony_ci	// Render reference image.
805e5c31af7Sopenharmony_ci	{
806e5c31af7Sopenharmony_ci		sglr::ReferenceContextBuffers	buffers	(tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), 0 /* depth */, 0 /* stencil */, viewportWidth, viewportHeight);
807e5c31af7Sopenharmony_ci		sglr::ReferenceContext			context	(sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
808e5c31af7Sopenharmony_ci
809e5c31af7Sopenharmony_ci		render(context);
810e5c31af7Sopenharmony_ci
811e5c31af7Sopenharmony_ci		context.readPixels(refFrame, 0, 0, viewportWidth, viewportHeight);
812e5c31af7Sopenharmony_ci	}
813e5c31af7Sopenharmony_ci
814e5c31af7Sopenharmony_ci	// Compare images.
815e5c31af7Sopenharmony_ci	const float		threshold	= 0.001f;
816e5c31af7Sopenharmony_ci	bool			isOk		= tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, gles2Frame, threshold, tcu::COMPARE_LOG_RESULT);
817e5c31af7Sopenharmony_ci
818e5c31af7Sopenharmony_ci	// Store test result.
819e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
820e5c31af7Sopenharmony_ci							isOk ? "Pass"				: "Image comparison failed");
821e5c31af7Sopenharmony_ci
822e5c31af7Sopenharmony_ci	return STOP;
823e5c31af7Sopenharmony_ci}
824e5c31af7Sopenharmony_ci
825e5c31af7Sopenharmony_civoid TextureUnitCase::render (sglr::Context& context)
826e5c31af7Sopenharmony_ci{
827e5c31af7Sopenharmony_ci	// Setup textures.
828e5c31af7Sopenharmony_ci
829e5c31af7Sopenharmony_ci	vector<deUint32>	textureGLNames;
830e5c31af7Sopenharmony_ci	vector<bool>		isTextureSetUp(m_numTextures, false); // \note Same texture may be bound to multiple units, but we only want to set up parameters and data once per texture.
831e5c31af7Sopenharmony_ci
832e5c31af7Sopenharmony_ci	textureGLNames.resize(m_numTextures);
833e5c31af7Sopenharmony_ci	context.genTextures(m_numTextures, &textureGLNames[0]);
834e5c31af7Sopenharmony_ci
835e5c31af7Sopenharmony_ci	for (int unitNdx = 0; unitNdx < m_numUnits; unitNdx++)
836e5c31af7Sopenharmony_ci	{
837e5c31af7Sopenharmony_ci		int texNdx = m_unitTextures[unitNdx];
838e5c31af7Sopenharmony_ci
839e5c31af7Sopenharmony_ci		// Bind texture to unit.
840e5c31af7Sopenharmony_ci		context.activeTexture(GL_TEXTURE0 + unitNdx);
841e5c31af7Sopenharmony_ci		context.bindTexture(m_textureTypes[texNdx], textureGLNames[texNdx]);
842e5c31af7Sopenharmony_ci
843e5c31af7Sopenharmony_ci		if (!isTextureSetUp[texNdx])
844e5c31af7Sopenharmony_ci		{
845e5c31af7Sopenharmony_ci			// Binding this texture for first time, so set parameters and data.
846e5c31af7Sopenharmony_ci
847e5c31af7Sopenharmony_ci			context.texParameteri(m_textureTypes[texNdx], GL_TEXTURE_WRAP_S, m_textureParams[texNdx].wrapModeS);
848e5c31af7Sopenharmony_ci			context.texParameteri(m_textureTypes[texNdx], GL_TEXTURE_WRAP_T, m_textureParams[texNdx].wrapModeT);
849e5c31af7Sopenharmony_ci			context.texParameteri(m_textureTypes[texNdx], GL_TEXTURE_MIN_FILTER, m_textureParams[texNdx].minFilter);
850e5c31af7Sopenharmony_ci			context.texParameteri(m_textureTypes[texNdx], GL_TEXTURE_MAG_FILTER, m_textureParams[texNdx].magFilter);
851e5c31af7Sopenharmony_ci
852e5c31af7Sopenharmony_ci			if (m_textureTypes[texNdx] == GL_TEXTURE_2D)
853e5c31af7Sopenharmony_ci			{
854e5c31af7Sopenharmony_ci				int						ndx2d		= m_ndx2dOrCube[texNdx];
855e5c31af7Sopenharmony_ci				const tcu::Texture2D*	texture		= m_textures2d[ndx2d];
856e5c31af7Sopenharmony_ci				bool					mipmaps		= (deIsPowerOfTwo32(texture->getWidth()) && deIsPowerOfTwo32(texture->getHeight()));
857e5c31af7Sopenharmony_ci				int						numLevels	= mipmaps ? deLog2Floor32(de::max(texture->getWidth(), texture->getHeight()))+1 : 1;
858e5c31af7Sopenharmony_ci
859e5c31af7Sopenharmony_ci				context.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
860e5c31af7Sopenharmony_ci
861e5c31af7Sopenharmony_ci				for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
862e5c31af7Sopenharmony_ci				{
863e5c31af7Sopenharmony_ci					tcu::ConstPixelBufferAccess		access	= texture->getLevel(levelNdx);
864e5c31af7Sopenharmony_ci					int								width	= access.getWidth();
865e5c31af7Sopenharmony_ci					int								height	= access.getHeight();
866e5c31af7Sopenharmony_ci
867e5c31af7Sopenharmony_ci					DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*width);
868e5c31af7Sopenharmony_ci
869e5c31af7Sopenharmony_ci					context.texImage2D(GL_TEXTURE_2D, levelNdx, m_textureParams[texNdx].format, width, height, 0, m_textureParams[texNdx].format, m_textureParams[texNdx].dataType, access.getDataPtr());
870e5c31af7Sopenharmony_ci				}
871e5c31af7Sopenharmony_ci			}
872e5c31af7Sopenharmony_ci			else
873e5c31af7Sopenharmony_ci			{
874e5c31af7Sopenharmony_ci				DE_ASSERT(m_textureTypes[texNdx] == GL_TEXTURE_CUBE_MAP);
875e5c31af7Sopenharmony_ci
876e5c31af7Sopenharmony_ci				int							ndxCube		= m_ndx2dOrCube[texNdx];
877e5c31af7Sopenharmony_ci				const tcu::TextureCube*		texture		= m_texturesCube[ndxCube];
878e5c31af7Sopenharmony_ci				bool						mipmaps		= deIsPowerOfTwo32(texture->getSize()) != DE_FALSE;
879e5c31af7Sopenharmony_ci				int							numLevels	= mipmaps ? deLog2Floor32(texture->getSize())+1 : 1;
880e5c31af7Sopenharmony_ci
881e5c31af7Sopenharmony_ci				context.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
882e5c31af7Sopenharmony_ci
883e5c31af7Sopenharmony_ci				for (int face = 0; face < (int)tcu::CUBEFACE_LAST; face++)
884e5c31af7Sopenharmony_ci				{
885e5c31af7Sopenharmony_ci					for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
886e5c31af7Sopenharmony_ci					{
887e5c31af7Sopenharmony_ci						tcu::ConstPixelBufferAccess		access	= texture->getLevelFace(levelNdx, (tcu::CubeFace)face);
888e5c31af7Sopenharmony_ci						int								width	= access.getWidth();
889e5c31af7Sopenharmony_ci						int								height	= access.getHeight();
890e5c31af7Sopenharmony_ci
891e5c31af7Sopenharmony_ci						DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*width);
892e5c31af7Sopenharmony_ci
893e5c31af7Sopenharmony_ci						context.texImage2D(s_cubeFaceTargets[face], levelNdx, m_textureParams[texNdx].format, width, height, 0, m_textureParams[texNdx].format, m_textureParams[texNdx].dataType, access.getDataPtr());
894e5c31af7Sopenharmony_ci					}
895e5c31af7Sopenharmony_ci				}
896e5c31af7Sopenharmony_ci			}
897e5c31af7Sopenharmony_ci
898e5c31af7Sopenharmony_ci			isTextureSetUp[texNdx] = true; // Don't set up this texture's parameters and data again later.
899e5c31af7Sopenharmony_ci		}
900e5c31af7Sopenharmony_ci	}
901e5c31af7Sopenharmony_ci
902e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(context.getError(), "Set textures");
903e5c31af7Sopenharmony_ci
904e5c31af7Sopenharmony_ci	// Setup shader
905e5c31af7Sopenharmony_ci
906e5c31af7Sopenharmony_ci	deUint32 shaderID = context.createProgram(m_shader);
907e5c31af7Sopenharmony_ci
908e5c31af7Sopenharmony_ci	// Draw.
909e5c31af7Sopenharmony_ci
910e5c31af7Sopenharmony_ci	context.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
911e5c31af7Sopenharmony_ci	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
912e5c31af7Sopenharmony_ci	m_shader->setUniforms(context, shaderID);
913e5c31af7Sopenharmony_ci	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
914e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(context.getError(), "Draw");
915e5c31af7Sopenharmony_ci
916e5c31af7Sopenharmony_ci	// Delete previously generated texture names.
917e5c31af7Sopenharmony_ci
918e5c31af7Sopenharmony_ci	context.deleteTextures(m_numTextures, &textureGLNames[0]);
919e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(context.getError(), "Delete textures");
920e5c31af7Sopenharmony_ci}
921e5c31af7Sopenharmony_ci
922e5c31af7Sopenharmony_ciTextureUnitTests::TextureUnitTests (Context& context)
923e5c31af7Sopenharmony_ci	: TestCaseGroup(context, "units", "Texture Unit Usage Tests")
924e5c31af7Sopenharmony_ci{
925e5c31af7Sopenharmony_ci}
926e5c31af7Sopenharmony_ci
927e5c31af7Sopenharmony_ciTextureUnitTests::~TextureUnitTests (void)
928e5c31af7Sopenharmony_ci{
929e5c31af7Sopenharmony_ci}
930e5c31af7Sopenharmony_ci
931e5c31af7Sopenharmony_civoid TextureUnitTests::init (void)
932e5c31af7Sopenharmony_ci{
933e5c31af7Sopenharmony_ci	const int numTestsPerGroup = 10;
934e5c31af7Sopenharmony_ci
935e5c31af7Sopenharmony_ci	static const int unitCounts[] =
936e5c31af7Sopenharmony_ci	{
937e5c31af7Sopenharmony_ci		2,
938e5c31af7Sopenharmony_ci		4,
939e5c31af7Sopenharmony_ci		8,
940e5c31af7Sopenharmony_ci		-1 // \note Negative stands for the implementation-specified maximum.
941e5c31af7Sopenharmony_ci	};
942e5c31af7Sopenharmony_ci
943e5c31af7Sopenharmony_ci	for (int unitCountNdx = 0; unitCountNdx < DE_LENGTH_OF_ARRAY(unitCounts); unitCountNdx++)
944e5c31af7Sopenharmony_ci	{
945e5c31af7Sopenharmony_ci		int numUnits = unitCounts[unitCountNdx];
946e5c31af7Sopenharmony_ci
947e5c31af7Sopenharmony_ci		string countGroupName = (unitCounts[unitCountNdx] < 0 ? "all" : de::toString(numUnits)) + "_units";
948e5c31af7Sopenharmony_ci
949e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* countGroup = new tcu::TestCaseGroup(m_testCtx, countGroupName.c_str(), "");
950e5c31af7Sopenharmony_ci		addChild(countGroup);
951e5c31af7Sopenharmony_ci
952e5c31af7Sopenharmony_ci		DE_STATIC_ASSERT((int)TextureUnitCase::CASE_ONLY_2D == 0);
953e5c31af7Sopenharmony_ci
954e5c31af7Sopenharmony_ci		for (int caseType = (int)TextureUnitCase::CASE_ONLY_2D; caseType < (int)TextureUnitCase::CASE_LAST; caseType++)
955e5c31af7Sopenharmony_ci		{
956e5c31af7Sopenharmony_ci			const char* caseTypeGroupName = (TextureUnitCase::CaseType)caseType == TextureUnitCase::CASE_ONLY_2D	? "only_2d" :
957e5c31af7Sopenharmony_ci											(TextureUnitCase::CaseType)caseType == TextureUnitCase::CASE_ONLY_CUBE	? "only_cube" :
958e5c31af7Sopenharmony_ci											(TextureUnitCase::CaseType)caseType == TextureUnitCase::CASE_MIXED		? "mixed" :
959e5c31af7Sopenharmony_ci																													  DE_NULL;
960e5c31af7Sopenharmony_ci			DE_ASSERT(caseTypeGroupName != DE_NULL);
961e5c31af7Sopenharmony_ci
962e5c31af7Sopenharmony_ci			tcu::TestCaseGroup* caseTypeGroup = new tcu::TestCaseGroup(m_testCtx, caseTypeGroupName, "");
963e5c31af7Sopenharmony_ci			countGroup->addChild(caseTypeGroup);
964e5c31af7Sopenharmony_ci
965e5c31af7Sopenharmony_ci			for (int testNdx = 0; testNdx < numTestsPerGroup; testNdx++)
966e5c31af7Sopenharmony_ci				caseTypeGroup->addChild(new TextureUnitCase(m_context, de::toString(testNdx).c_str(), "", numUnits, (TextureUnitCase::CaseType)caseType, (deUint32)deInt32Hash(testNdx)));
967e5c31af7Sopenharmony_ci		}
968e5c31af7Sopenharmony_ci	}
969e5c31af7Sopenharmony_ci}
970e5c31af7Sopenharmony_ci
971e5c31af7Sopenharmony_ci} // Functional
972e5c31af7Sopenharmony_ci} // gles2
973e5c31af7Sopenharmony_ci} // deqp
974