1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2016-2017 The Khronos Group Inc.
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
22 */ /*-------------------------------------------------------------------*/
23
24/**
25 */ /*!
26 * \file  glcParallelShaderCompileTests.cpp
27 * \brief Conformance tests for the GL_KHR_parallel_shader_compile functionality.
28 */ /*-------------------------------------------------------------------*/
29
30#include "glcParallelShaderCompileTests.hpp"
31#include "deClock.h"
32#include "gluContextInfo.hpp"
33#include "gluDefs.hpp"
34#include "gluShaderProgram.hpp"
35#include "glwEnums.hpp"
36#include "glwFunctions.hpp"
37#include "tcuTestLog.hpp"
38
39using namespace glu;
40using namespace glw;
41
42namespace glcts
43{
44
45static const char* shaderVersionES = "#version 300 es\n";
46static const char* shaderVersionGL = "#version 450\n";
47static const char* vShader		   = "\n"
48							 "in vec3 vertex;\n"
49							 "\n"
50							 "void main() {\n"
51							 "    gl_Position = vec4(vertex, 1);\n"
52							 "}\n";
53
54static const char* fShader = "\n"
55							 "out vec4 fragColor;\n"
56							 "\n"
57							 "void main() {\n"
58							 "    fragColor = vec4(1, 1, 1, 1);\n"
59							 "}\n";
60
61/** Constructor.
62 *
63 *  @param context     Rendering context
64 *  @param name        Test name
65 *  @param description Test description
66 */
67SimpleQueriesTest::SimpleQueriesTest(deqp::Context& context)
68	: TestCase(context, "simple_queries",
69			   "Tests verifies if simple queries works as expected for MAX_SHADER_COMPILER_THREADS_KHR <pname>")
70{
71	/* Left blank intentionally */
72}
73
74/** Executes test iteration.
75 *
76 *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
77 */
78tcu::TestNode::IterateResult SimpleQueriesTest::iterate()
79{
80	const glu::ContextInfo& contextInfo		= m_context.getContextInfo();
81	const glu::ContextType& contextType		= m_context.getRenderContext().getType();
82	const bool				isGL			= glu::isContextTypeGLCore(contextType);
83	const bool				supportParallel	= (isGL && contextInfo.isExtensionSupported("GL_ARB_parallel_shader_compile")) ||
84												contextInfo.isExtensionSupported("GL_KHR_parallel_shader_compile");
85
86	if (!supportParallel)
87	{
88		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
89		return STOP;
90	}
91
92	const Functions&		gl			 = m_context.getRenderContext().getFunctions();
93
94	GLboolean boolValue;
95	GLint	 intValue;
96	GLint64   int64Value;
97	GLfloat   floatValue;
98	GLdouble  doubleValue;
99
100	bool supportsInt64  = isGL || glu::contextSupports(contextType, glu::ApiType::es(3, 0));
101	bool supportsDouble = isGL;
102
103	gl.getBooleanv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &boolValue);
104	GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv");
105
106	gl.getIntegerv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &intValue);
107	GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv");
108
109	if (supportsInt64)
110	{
111		gl.getInteger64v(GL_MAX_SHADER_COMPILER_THREADS_KHR, &int64Value);
112		GLU_EXPECT_NO_ERROR(gl.getError(), "getInteger64v");
113	}
114
115	gl.getFloatv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &floatValue);
116	GLU_EXPECT_NO_ERROR(gl.getError(), "getFloatv");
117
118	if (supportsDouble)
119	{
120		gl.getDoublev(GL_MAX_SHADER_COMPILER_THREADS_KHR, &doubleValue);
121		GLU_EXPECT_NO_ERROR(gl.getError(), "getDoublev");
122	}
123
124	if (boolValue != (intValue != 0) || intValue != (GLint)floatValue ||
125		(supportsInt64 && intValue != (GLint)int64Value) || (supportsDouble && intValue != (GLint)doubleValue))
126	{
127		tcu::MessageBuilder message = m_testCtx.getLog() << tcu::TestLog::Message;
128
129		message << "Simple queries returned different values: "
130				<< "bool(" << (int)boolValue << "), "
131				<< "int(" << intValue << "), ";
132
133		if (supportsInt64)
134			message << "int64(" << int64Value << "), ";
135
136		message << "float(" << floatValue << ")";
137
138		if (supportsDouble)
139			message << ", double(" << doubleValue << ")";
140
141		message << tcu::TestLog::EndMessage;
142
143		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
144		return STOP;
145	}
146
147	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
148	return STOP;
149}
150
151/** Constructor.
152 *
153 *  @param context     Rendering context
154 *  @param name        Test name
155 *  @param description Test description
156 */
157MaxShaderCompileThreadsTest::MaxShaderCompileThreadsTest(deqp::Context& context)
158	: TestCase(context, "max_shader_compile_threads",
159			   "Tests verifies if MaxShaderCompileThreadsKHR function works as expected")
160{
161	/* Left blank intentionally */
162}
163
164/** Executes test iteration.
165 *
166 *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
167 */
168tcu::TestNode::IterateResult MaxShaderCompileThreadsTest::iterate()
169{
170	const glu::ContextInfo& contextInfo		= m_context.getContextInfo();
171	const glu::ContextType& contextType		= m_context.getRenderContext().getType();
172	const bool				isGL			= glu::isContextTypeGLCore(contextType);
173	const bool				supportParallel	= (isGL && contextInfo.isExtensionSupported("GL_ARB_parallel_shader_compile")) ||
174												contextInfo.isExtensionSupported("GL_KHR_parallel_shader_compile");
175
176	if (!supportParallel)
177	{
178		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
179		return STOP;
180	}
181
182	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
183
184	GLint intValue;
185
186	gl.maxShaderCompilerThreadsKHR(0);
187	GLU_EXPECT_NO_ERROR(gl.getError(), "maxShaderCompilerThreadsKHR");
188
189	gl.getIntegerv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &intValue);
190	GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv");
191
192	if (intValue != 0)
193	{
194		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Failed to disable parallel shader compilation.");
195		return STOP;
196	}
197
198	gl.maxShaderCompilerThreadsKHR(0xFFFFFFFF);
199	GLU_EXPECT_NO_ERROR(gl.getError(), "maxShaderCompilerThreadsKHR");
200
201	gl.getIntegerv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &intValue);
202	GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv");
203
204	if (intValue != GLint(0xFFFFFFFF))
205	{
206		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Failed to set maximum shader compiler threads.");
207		return STOP;
208	}
209
210	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
211	return STOP;
212}
213
214/** Constructor.
215 *
216 *  @param context     Rendering context
217 *  @param name        Test name
218 *  @param description Test description
219 */
220CompilationCompletionParallelTest::CompilationCompletionParallelTest(deqp::Context& context)
221	: TestCase(context, "compilation_completion_parallel",
222			   "Tests verifies if shader COMPLETION_STATUS query works as expected for parallel compilation")
223{
224	/* Left blank intentionally */
225}
226
227/** Executes test iteration.
228 *
229 *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
230 */
231tcu::TestNode::IterateResult CompilationCompletionParallelTest::iterate()
232{
233	const glu::ContextInfo& contextInfo		= m_context.getContextInfo();
234	const glu::ContextType& contextType		= m_context.getRenderContext().getType();
235	const bool				isGL			= glu::isContextTypeGLCore(contextType);
236	const bool				supportParallel	= (isGL && contextInfo.isExtensionSupported("GL_ARB_parallel_shader_compile")) ||
237												contextInfo.isExtensionSupported("GL_KHR_parallel_shader_compile");
238
239	if (!supportParallel)
240	{
241		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
242		return STOP;
243	}
244
245	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
246
247	GLint completionStatus;
248
249	gl.maxShaderCompilerThreadsKHR(8);
250	GLU_EXPECT_NO_ERROR(gl.getError(), "maxShaderCompilerThreadsKHR");
251
252	{
253		Shader   vertexShader(gl, SHADERTYPE_VERTEX);
254		deUint32 fragmentShader[8];
255		deUint32 program[8];
256
257		bool		isContextES   = (glu::isContextTypeES(m_context.getRenderContext().getType()));
258		const char* shaderVersion = isContextES ? shaderVersionES : shaderVersionGL;
259
260		for (int i = 0; i < 8; ++i)
261		{
262			fragmentShader[i] = gl.createShader(GL_FRAGMENT_SHADER);
263			program[i]		  = gl.createProgram();
264		}
265
266		const char* vSources[] = { shaderVersion, vShader };
267		const int   vLengths[] = { int(strlen(shaderVersion)), int(strlen(vShader)) };
268		vertexShader.setSources(2, vSources, vLengths);
269
270		//Compilation test
271		for (int i = 0; i < 8; ++i)
272		{
273			const char* fSources[] = { shaderVersion, fShader };
274			const int   fLengths[] = { int(strlen(shaderVersion)), int(strlen(fShader)) };
275			gl.shaderSource(fragmentShader[i], 2, fSources, fLengths);
276		}
277
278		gl.compileShader(vertexShader.getShader());
279		GLU_EXPECT_NO_ERROR(gl.getError(), "compileShader");
280		for (int i = 0; i < 8; ++i)
281		{
282			gl.compileShader(fragmentShader[i]);
283			GLU_EXPECT_NO_ERROR(gl.getError(), "compileShader");
284		}
285
286		{
287			int		 completion  = 0;
288			deUint64 shLoopStart = deGetMicroseconds();
289			while (completion != 8 && deGetMicroseconds() < shLoopStart + 1000000)
290			{
291				completion = 0;
292				for (int i = 0; i < 8; ++i)
293				{
294					gl.getShaderiv(fragmentShader[i], GL_COMPLETION_STATUS_KHR, &completionStatus);
295					GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv");
296					if (completionStatus)
297						completion++;
298				}
299			}
300			if (completion != 8)
301			{
302				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL,
303										"Failed reading completion status for parallel shader compiling");
304				for (int i = 0; i < 8; ++i)
305				{
306					gl.deleteProgram(program[i]);
307					gl.deleteShader(fragmentShader[i]);
308				}
309				return STOP;
310			}
311		}
312
313		for (int i = 0; i < 8; ++i)
314		{
315			gl.attachShader(program[i], vertexShader.getShader());
316			GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader");
317			gl.attachShader(program[i], fragmentShader[i]);
318			GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader");
319		}
320
321		//Linking test
322		for (int i = 0; i < 8; ++i)
323		{
324			gl.linkProgram(program[i]);
325			GLU_EXPECT_NO_ERROR(gl.getError(), "linkProgram");
326		}
327
328		{
329			int		 completion  = 0;
330			deUint64 prLoopStart = deGetMicroseconds();
331			while (completion != 8 && deGetMicroseconds() < prLoopStart + 1000000)
332			{
333				completion = 0;
334				for (int i = 0; i < 8; ++i)
335				{
336					gl.getProgramiv(program[i], GL_COMPLETION_STATUS_KHR, &completionStatus);
337					GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
338					if (completionStatus)
339						completion++;
340				}
341			}
342			if (completion != 8)
343			{
344				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL,
345										"Failed reading completion status for parallel program linking");
346				for (int i = 0; i < 8; ++i)
347				{
348					gl.deleteProgram(program[i]);
349					gl.deleteShader(fragmentShader[i]);
350				}
351				return STOP;
352			}
353		}
354	}
355
356	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
357	return STOP;
358}
359
360/** Constructor.
361 *
362 *  @param context Rendering context.
363 */
364ParallelShaderCompileTests::ParallelShaderCompileTests(deqp::Context& context)
365	: TestCaseGroup(context, "parallel_shader_compile",
366					"Verify conformance of KHR_parallel_shader_compile implementation")
367{
368}
369
370/** Initializes the test group contents. */
371void ParallelShaderCompileTests::init()
372{
373	addChild(new SimpleQueriesTest(m_context));
374	addChild(new MaxShaderCompileThreadsTest(m_context));
375	addChild(new CompilationCompletionParallelTest(m_context));
376}
377
378} /* glcts namespace */
379