1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Sync stress tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3sSyncTests.hpp"
25
26#include "tcuTestLog.hpp"
27#include "deRandom.hpp"
28#include "tcuVector.hpp"
29#include "gluShaderProgram.hpp"
30#include "gluCallLogWrapper.hpp"
31#include "gluRenderContext.hpp"
32#include "deStringUtil.hpp"
33#include "deString.h"
34
35#include <vector>
36
37#include "glw.h"
38
39using tcu::TestLog;
40using std::vector;
41
42namespace deqp
43{
44namespace gles3
45{
46namespace Stress
47{
48
49static const int NUM_CASE_ITERATIONS = 1;
50
51enum WaitCommand
52{
53	COMMAND_WAIT_SYNC			= 1 << 0,
54	COMMAND_CLIENT_WAIT_SYNC	= 1 << 1
55};
56
57class FenceSyncCase : public TestCase, public glu::CallLogWrapper
58{
59public:
60						FenceSyncCase		(Context& context, const char* name, const char* description, int numPrimitives, deUint32 waitCommand);
61						~FenceSyncCase		(void);
62
63	void				init				(void);
64	void				deinit				(void);
65	IterateResult		iterate				(void);
66
67private:
68						FenceSyncCase		(const FenceSyncCase& other);
69	FenceSyncCase&		operator=			(const FenceSyncCase& other);
70
71	int					m_numSyncs;
72	deUint32			m_waitCommand;
73
74	glu::ShaderProgram*	m_program;
75	vector<GLsync>		m_syncObjects;
76	int					m_iterNdx;
77	de::Random			m_rnd;
78};
79
80FenceSyncCase::FenceSyncCase (Context& context, const char* name, const char* description, int numSyncs, deUint32 waitCommand)
81	: TestCase			(context, name, description)
82	, CallLogWrapper	(context.getRenderContext().getFunctions(), context.getTestContext().getLog())
83	, m_numSyncs		(numSyncs)
84	, m_waitCommand		(waitCommand)
85	, m_program			(DE_NULL)
86	, m_syncObjects		(DE_NULL)
87	, m_iterNdx			(0)
88	, m_rnd				(deStringHash(name))
89{
90}
91
92FenceSyncCase::~FenceSyncCase (void)
93{
94	FenceSyncCase::deinit();
95}
96
97static void generateVertices (std::vector<float>& dst, int numPrimitives, de::Random& rnd)
98{
99	int numVertices = 3*numPrimitives;
100	dst.resize(numVertices * 4);
101
102	for (int i = 0; i < numVertices; i++)
103	{
104		dst[i*4    ] = rnd.getFloat(-1.0f, 1.0f);	// x
105		dst[i*4 + 1] = rnd.getFloat(-1.0f, 1.0f);	// y
106		dst[i*4 + 2] = rnd.getFloat( 0.0f, 1.0f);	// z
107		dst[i*4 + 3] = 1.0f;						// w
108	}
109}
110
111void FenceSyncCase::init (void)
112{
113	const char*	vertShaderSource =
114				"#version 300 es\n"
115				"layout(location = 0) in mediump vec4 a_position;\n"
116				"\n"
117				"void main (void)\n"
118				"{\n"
119				"	gl_Position = a_position;\n"
120				"}\n";
121
122	const char* fragShaderSource =
123				"#version 300 es\n"
124				"layout(location = 0) out mediump vec4 o_color;\n"
125				"\n"
126				"void main (void)\n"
127				"{\n"
128				"	o_color = vec4(0.25, 0.5, 0.75, 1.0);\n"
129				"}\n";
130
131	DE_ASSERT(!m_program);
132	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSource, fragShaderSource));
133
134	if (!m_program->isOk())
135	{
136		m_testCtx.getLog() << *m_program;
137		TCU_FAIL("Failed to compile shader program");
138	}
139
140	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); // Initialize test result to pass.
141	GLU_CHECK_MSG ("Case initialization finished");
142}
143
144void FenceSyncCase::deinit (void)
145{
146	if (m_program)
147	{
148		delete m_program;
149		m_program = DE_NULL;
150	}
151
152	for (int i = 0; i < (int)m_syncObjects.size(); i++)
153		if (m_syncObjects[i])
154			glDeleteSync(m_syncObjects[i]);
155
156	m_syncObjects.erase(m_syncObjects.begin(), m_syncObjects.end());
157}
158
159FenceSyncCase::IterateResult FenceSyncCase::iterate (void)
160{
161	TestLog&				log		= m_testCtx.getLog();
162	std::vector<float>		vertices;
163	bool					testOk	= true;
164
165	std::string				header	= "Case iteration " + de::toString(m_iterNdx+1) + " / " + de::toString(NUM_CASE_ITERATIONS);
166	tcu::ScopedLogSection	section	(log, header, header);
167
168	enableLogging(true);
169
170	TCU_CHECK		(m_program);
171	glUseProgram	(m_program->getProgram());
172	glEnable		(GL_DEPTH_TEST);
173	glClearColor	(0.3f, 0.3f, 0.3f, 1.0f);
174	glClearDepthf	(1.0f);
175	glClear			(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
176
177	// Generate vertices
178
179	glEnableVertexAttribArray	(0);
180	generateVertices			(vertices, m_numSyncs, m_rnd);
181	glVertexAttribPointer		(0, 4, GL_FLOAT, GL_FALSE, 0, &vertices[0]);
182	m_syncObjects.resize		(m_numSyncs);
183
184	// Perform draws and create sync objects
185
186	enableLogging(false);
187	log << TestLog::Message << "// NOT LOGGED: " << m_numSyncs << " glDrawArrays and glFenceSync calls done here." << TestLog::EndMessage;
188
189	for (int i = 0; i < m_numSyncs; i++)
190	{
191		glDrawArrays(GL_TRIANGLES, i*3, 3);
192		m_syncObjects[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
193		GLU_CHECK_MSG("Sync object created");
194	}
195	enableLogging(true);
196	log << TestLog::Message << "// Draws performed, sync objects created." << TestLog::EndMessage;
197
198	// Wait for sync objects
199
200	m_rnd.shuffle(m_syncObjects.begin(), m_syncObjects.end());
201
202	enableLogging(false);
203	if (m_waitCommand & COMMAND_WAIT_SYNC)
204		log << TestLog::Message << "// NOT LOGGED: " << m_numSyncs << " glWaitSync calls done here." << TestLog::EndMessage;
205	else if (m_waitCommand & COMMAND_CLIENT_WAIT_SYNC)
206		log << TestLog::Message << "// NOT LOGGED: " << m_numSyncs << " glClientWaitSync calls done here." << TestLog::EndMessage;
207
208	for (int i = 0; i < m_numSyncs; i++)
209	{
210		GLenum waitValue = 0;
211
212		if (m_waitCommand & COMMAND_WAIT_SYNC)
213		{
214			glWaitSync(m_syncObjects[i], 0, GL_TIMEOUT_IGNORED);
215			GLU_CHECK_MSG("glWaitSync called");
216		}
217		else if (m_waitCommand & COMMAND_CLIENT_WAIT_SYNC)
218		{
219			waitValue = glClientWaitSync(m_syncObjects[i], 0, 100);
220			GLU_CHECK_MSG("glClientWaitSync called");
221			switch (waitValue)
222			{
223				case GL_ALREADY_SIGNALED:	 break;
224				case GL_TIMEOUT_EXPIRED:	 break;
225				case GL_CONDITION_SATISFIED: break;
226				case GL_WAIT_FAILED:		 log << TestLog::Message << "// glClientWaitSync returned GL_WAIT_FAILED"	<< TestLog::EndMessage; testOk = false; break;
227				default:					 TCU_FAIL("glClientWaitSync returned an unknown return value.");
228			}
229		}
230	}
231	enableLogging(true);
232
233	glFinish();
234
235	// Delete sync objects
236
237	enableLogging(false);
238	log << TestLog::Message << "// NOT LOGGED: " << m_numSyncs << " glDeleteSync calls done here." << TestLog::EndMessage;
239
240	for (int i = 0; i < (int)m_syncObjects.size(); i++)
241	{
242		if (m_syncObjects[i])
243		{
244			glDeleteSync(m_syncObjects[i]);
245			GLU_CHECK_MSG("Sync object deleted");
246		}
247	}
248
249	enableLogging(true);
250
251	m_syncObjects.erase(m_syncObjects.begin(), m_syncObjects.end());
252
253	// Evaluate test result
254
255	log << TestLog::Message << "// Test result: " << (testOk ? "Passed!" : "Failed!") << TestLog::EndMessage;
256
257	if (!testOk)
258	{
259		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
260		return STOP;
261	}
262
263	log << TestLog::Message << "// Sync objects created and deleted successfully." << TestLog::EndMessage;
264
265	return (++m_iterNdx < NUM_CASE_ITERATIONS) ? CONTINUE : STOP;
266}
267
268SyncTests::SyncTests (Context& context)
269	: TestCaseGroup(context, "fence_sync", "Fence Sync Tests")
270{
271}
272
273SyncTests::~SyncTests (void)
274{
275}
276
277void SyncTests::init (void)
278{
279	// Fence sync stress tests.
280
281	addChild(new FenceSyncCase(m_context, "wait_sync_10_syncs",				"",	10,		COMMAND_WAIT_SYNC));
282	addChild(new FenceSyncCase(m_context, "wait_sync_1000_syncs",			"",	1000,	COMMAND_WAIT_SYNC));
283	addChild(new FenceSyncCase(m_context, "wait_sync_10000_syncs",			"",	10000,	COMMAND_WAIT_SYNC));
284
285	addChild(new FenceSyncCase(m_context, "client_wait_sync_10_syncs",		"",	10,		COMMAND_CLIENT_WAIT_SYNC));
286	addChild(new FenceSyncCase(m_context, "client_wait_sync_1000_syncs",	"",	1000,	COMMAND_CLIENT_WAIT_SYNC));
287	addChild(new FenceSyncCase(m_context, "client_wait_sync_10000_syncs",	"",	10000,	COMMAND_CLIENT_WAIT_SYNC));
288}
289
290} // Stress
291} // gles3
292} // deqp
293