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 
39 using tcu::TestLog;
40 using std::vector;
41 
42 namespace deqp
43 {
44 namespace gles3
45 {
46 namespace Stress
47 {
48 
49 static const int NUM_CASE_ITERATIONS = 1;
50 
51 enum WaitCommand
52 {
53 	COMMAND_WAIT_SYNC			= 1 << 0,
54 	COMMAND_CLIENT_WAIT_SYNC	= 1 << 1
55 };
56 
57 class FenceSyncCase : public TestCase, public glu::CallLogWrapper
58 {
59 public:
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 
67 private:
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 
FenceSyncCase(Context & context,const char * name,const char * description,int numSyncs,deUint32 waitCommand)80 FenceSyncCase::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 
~FenceSyncCase(void)92 FenceSyncCase::~FenceSyncCase (void)
93 {
94 	FenceSyncCase::deinit();
95 }
96 
generateVertices(std::vector<float> & dst,int numPrimitives,de::Random & rnd)97 static 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 
init(void)111 void 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 
deinit(void)144 void 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 
iterate(void)159 FenceSyncCase::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 
SyncTests(Context & context)268 SyncTests::SyncTests (Context& context)
269 	: TestCaseGroup(context, "fence_sync", "Fence Sync Tests")
270 {
271 }
272 
~SyncTests(void)273 SyncTests::~SyncTests (void)
274 {
275 }
276 
init(void)277 void 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