1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Interaction test utilities.
22 *//*--------------------------------------------------------------------*/
23
24#include "glsInteractionTestUtil.hpp"
25
26#include "tcuVector.hpp"
27
28#include "deRandom.hpp"
29#include "deMath.h"
30
31#include "glwEnums.hpp"
32
33namespace deqp
34{
35namespace gls
36{
37namespace InteractionTestUtil
38{
39
40using tcu::Vec4;
41using tcu::IVec2;
42using std::vector;
43
44static Vec4 getRandomColor (de::Random& rnd)
45{
46	static const float components[] = { 0.0f, 0.2f, 0.4f, 0.5f, 0.6f, 0.8f, 1.0f };
47	float r = rnd.choose<float>(DE_ARRAY_BEGIN(components), DE_ARRAY_END(components));
48	float g = rnd.choose<float>(DE_ARRAY_BEGIN(components), DE_ARRAY_END(components));
49	float b = rnd.choose<float>(DE_ARRAY_BEGIN(components), DE_ARRAY_END(components));
50	float a = rnd.choose<float>(DE_ARRAY_BEGIN(components), DE_ARRAY_END(components));
51	return Vec4(r, g, b, a);
52}
53
54void computeRandomRenderState (de::Random& rnd, RenderState& state, glu::ApiType apiType, int targetWidth, int targetHeight)
55{
56	// Constants governing randomization.
57	const float		scissorTestProbability		= 0.2f;
58	const float		stencilTestProbability		= 0.4f;
59	const float		depthTestProbability		= 0.6f;
60	const float		blendProbability			= 0.4f;
61	const float		ditherProbability			= 0.5f;
62
63	const float		depthWriteProbability		= 0.7f;
64	const float		colorWriteProbability		= 0.7f;
65
66	const int		minStencilVal				= -3;
67	const int		maxStencilVal				= 260;
68
69	const int		maxScissorOutOfBounds		= 10;
70	const float		minScissorSize				= 0.7f;
71
72	static const deUint32 compareFuncs[] =
73	{
74		GL_NEVER,
75		GL_ALWAYS,
76		GL_LESS,
77		GL_LEQUAL,
78		GL_EQUAL,
79		GL_GEQUAL,
80		GL_GREATER,
81		GL_NOTEQUAL
82	};
83
84	static const deUint32 stencilOps[] =
85	{
86		GL_KEEP,
87		GL_ZERO,
88		GL_REPLACE,
89		GL_INCR,
90		GL_DECR,
91		GL_INVERT,
92		GL_INCR_WRAP,
93		GL_DECR_WRAP
94	};
95
96	static const deUint32 blendEquations[] =
97	{
98		GL_FUNC_ADD,
99		GL_FUNC_SUBTRACT,
100		GL_FUNC_REVERSE_SUBTRACT,
101		GL_MIN,
102		GL_MAX
103	};
104
105	static const deUint32 blendFuncs[] =
106	{
107		GL_ZERO,
108		GL_ONE,
109		GL_SRC_COLOR,
110		GL_ONE_MINUS_SRC_COLOR,
111		GL_DST_COLOR,
112		GL_ONE_MINUS_DST_COLOR,
113		GL_SRC_ALPHA,
114		GL_ONE_MINUS_SRC_ALPHA,
115		GL_DST_ALPHA,
116		GL_ONE_MINUS_DST_ALPHA,
117		GL_CONSTANT_COLOR,
118		GL_ONE_MINUS_CONSTANT_COLOR,
119		GL_CONSTANT_ALPHA,
120		GL_ONE_MINUS_CONSTANT_ALPHA,
121		GL_SRC_ALPHA_SATURATE
122	};
123
124	static const deUint32 blendEquationsES2[] =
125	{
126		GL_FUNC_ADD,
127		GL_FUNC_SUBTRACT,
128		GL_FUNC_REVERSE_SUBTRACT
129	};
130
131	static const deUint32 blendFuncsDstES2[] =
132	{
133		GL_ZERO,
134		GL_ONE,
135		GL_SRC_COLOR,
136		GL_ONE_MINUS_SRC_COLOR,
137		GL_DST_COLOR,
138		GL_ONE_MINUS_DST_COLOR,
139		GL_SRC_ALPHA,
140		GL_ONE_MINUS_SRC_ALPHA,
141		GL_DST_ALPHA,
142		GL_ONE_MINUS_DST_ALPHA,
143		GL_CONSTANT_COLOR,
144		GL_ONE_MINUS_CONSTANT_COLOR,
145		GL_CONSTANT_ALPHA,
146		GL_ONE_MINUS_CONSTANT_ALPHA
147	};
148
149	state.scissorTestEnabled	= rnd.getFloat() < scissorTestProbability;
150	state.stencilTestEnabled	= rnd.getFloat() < stencilTestProbability;
151	state.depthTestEnabled		= rnd.getFloat() < depthTestProbability;
152	state.blendEnabled			= rnd.getFloat() < blendProbability;
153	state.ditherEnabled			= rnd.getFloat() < ditherProbability;
154
155	if (state.scissorTestEnabled)
156	{
157		int minScissorW		= deCeilFloatToInt32(minScissorSize*targetWidth);
158		int minScissorH		= deCeilFloatToInt32(minScissorSize*targetHeight);
159		int maxScissorW		= targetWidth + 2*maxScissorOutOfBounds;
160		int maxScissorH		= targetHeight + 2*maxScissorOutOfBounds;
161
162		int scissorW		= rnd.getInt(minScissorW, maxScissorW);
163		int	scissorH		= rnd.getInt(minScissorH, maxScissorH);
164		int scissorX		= rnd.getInt(-maxScissorOutOfBounds, targetWidth+maxScissorOutOfBounds-scissorW);
165		int scissorY		= rnd.getInt(-maxScissorOutOfBounds, targetHeight+maxScissorOutOfBounds-scissorH);
166
167		state.scissorRectangle = rr::WindowRectangle(scissorX, scissorY, scissorW, scissorH);
168	}
169
170	if (state.stencilTestEnabled)
171	{
172		for (int ndx = 0; ndx < 2; ndx++)
173		{
174			state.stencil[ndx].function			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(compareFuncs), DE_ARRAY_END(compareFuncs));
175			state.stencil[ndx].reference		= rnd.getInt(minStencilVal, maxStencilVal);
176			state.stencil[ndx].compareMask		= rnd.getUint32();
177			state.stencil[ndx].stencilFailOp	= rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
178			state.stencil[ndx].depthFailOp		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
179			state.stencil[ndx].depthPassOp		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
180			state.stencil[ndx].writeMask		= rnd.getUint32();
181		}
182	}
183
184	if (state.depthTestEnabled)
185	{
186		state.depthFunc			= rnd.choose<deUint32>(DE_ARRAY_BEGIN(compareFuncs), DE_ARRAY_END(compareFuncs));
187		state.depthWriteMask	= rnd.getFloat() < depthWriteProbability;
188	}
189
190	if (state.blendEnabled)
191	{
192		if (apiType == glu::ApiType::es(2,0))
193		{
194			state.blendRGBState.equation	= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendEquationsES2), DE_ARRAY_END(blendEquationsES2));
195			state.blendRGBState.srcFunc		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
196			state.blendRGBState.dstFunc		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncsDstES2), DE_ARRAY_END(blendFuncsDstES2));
197
198			state.blendAState.equation		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendEquationsES2), DE_ARRAY_END(blendEquationsES2));
199			state.blendAState.srcFunc		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
200			state.blendAState.dstFunc		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncsDstES2), DE_ARRAY_END(blendFuncsDstES2));
201		}
202		else
203		{
204			state.blendRGBState.equation	= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendEquations), DE_ARRAY_END(blendEquations));
205			state.blendRGBState.srcFunc		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
206			state.blendRGBState.dstFunc		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
207
208			state.blendAState.equation		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendEquations), DE_ARRAY_END(blendEquations));
209			state.blendAState.srcFunc		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
210			state.blendAState.dstFunc		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
211		}
212
213		state.blendColor				= getRandomColor(rnd);
214	}
215
216	for (int ndx = 0; ndx < 4; ndx++)
217		state.colorMask[ndx] = rnd.getFloat() < colorWriteProbability;
218}
219
220void computeRandomQuad (de::Random& rnd, gls::FragmentOpUtil::IntegerQuad& quad, int targetWidth, int targetHeight)
221{
222	// \note In viewport coordinates.
223	// \todo [2012-12-18 pyry] Out-of-bounds values.
224	// \note Not using depth 1.0 since clearing with 1.0 and rendering with 1.0 may not be same value.
225	static const float depthValues[] = { 0.0f, 0.2f, 0.4f, 0.5f, 0.51f, 0.6f, 0.8f, 0.95f };
226
227	const int		maxOutOfBounds		= 0;
228	const float		minSize				= 0.5f;
229
230	int minW		= deCeilFloatToInt32(minSize*targetWidth);
231	int minH		= deCeilFloatToInt32(minSize*targetHeight);
232	int maxW		= targetWidth + 2*maxOutOfBounds;
233	int maxH		= targetHeight + 2*maxOutOfBounds;
234
235	int width		= rnd.getInt(minW, maxW);
236	int	height		= rnd.getInt(minH, maxH);
237	int x			= rnd.getInt(-maxOutOfBounds, targetWidth+maxOutOfBounds-width);
238	int y			= rnd.getInt(-maxOutOfBounds, targetHeight+maxOutOfBounds-height);
239
240	bool flipX		= rnd.getBool();
241	bool flipY		= rnd.getBool();
242
243	float depth		= rnd.choose<float>(DE_ARRAY_BEGIN(depthValues), DE_ARRAY_END(depthValues));
244
245	quad.posA	= IVec2(flipX ? (x+width-1) : x, flipY ? (y+height-1) : y);
246	quad.posB	= IVec2(flipX ? x : (x+width-1), flipY ? y : (y+height-1));
247
248	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(quad.color); ndx++)
249		quad.color[ndx] = getRandomColor(rnd);
250
251	std::fill(DE_ARRAY_BEGIN(quad.depth), DE_ARRAY_END(quad.depth), depth);
252}
253
254void computeRandomRenderCommands (de::Random& rnd, glu::ApiType apiType, int numCommands, int targetW, int targetH, vector<RenderCommand>& dst)
255{
256	DE_ASSERT(dst.empty());
257
258	dst.resize(numCommands);
259	for (vector<RenderCommand>::iterator cmd = dst.begin(); cmd != dst.end(); cmd++)
260	{
261		computeRandomRenderState(rnd, cmd->state, apiType, targetW, targetH);
262		computeRandomQuad(rnd, cmd->quad, targetW, targetH);
263	}
264}
265
266} // InteractionTestUtil
267} // gls
268} // deqp
269