/*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2016-2017 The Khronos Group Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /*! * \file * \brief */ /*-------------------------------------------------------------------*/ /** */ /*! * \file glcParallelShaderCompileTests.cpp * \brief Conformance tests for the GL_KHR_parallel_shader_compile functionality. */ /*-------------------------------------------------------------------*/ #include "glcParallelShaderCompileTests.hpp" #include "deClock.h" #include "gluContextInfo.hpp" #include "gluDefs.hpp" #include "gluShaderProgram.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include "tcuTestLog.hpp" using namespace glu; using namespace glw; namespace glcts { static const char* shaderVersionES = "#version 300 es\n"; static const char* shaderVersionGL = "#version 450\n"; static const char* vShader = "\n" "in vec3 vertex;\n" "\n" "void main() {\n" " gl_Position = vec4(vertex, 1);\n" "}\n"; static const char* fShader = "\n" "out vec4 fragColor;\n" "\n" "void main() {\n" " fragColor = vec4(1, 1, 1, 1);\n" "}\n"; /** Constructor. * * @param context Rendering context * @param name Test name * @param description Test description */ SimpleQueriesTest::SimpleQueriesTest(deqp::Context& context) : TestCase(context, "simple_queries", "Tests verifies if simple queries works as expected for MAX_SHADER_COMPILER_THREADS_KHR ") { /* Left blank intentionally */ } /** Executes test iteration. * * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. */ tcu::TestNode::IterateResult SimpleQueriesTest::iterate() { const glu::ContextInfo& contextInfo = m_context.getContextInfo(); const glu::ContextType& contextType = m_context.getRenderContext().getType(); const bool isGL = glu::isContextTypeGLCore(contextType); const bool supportParallel = (isGL && contextInfo.isExtensionSupported("GL_ARB_parallel_shader_compile")) || contextInfo.isExtensionSupported("GL_KHR_parallel_shader_compile"); if (!supportParallel) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported"); return STOP; } const Functions& gl = m_context.getRenderContext().getFunctions(); GLboolean boolValue; GLint intValue; GLint64 int64Value; GLfloat floatValue; GLdouble doubleValue; bool supportsInt64 = isGL || glu::contextSupports(contextType, glu::ApiType::es(3, 0)); bool supportsDouble = isGL; gl.getBooleanv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &boolValue); GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv"); gl.getIntegerv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &intValue); GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv"); if (supportsInt64) { gl.getInteger64v(GL_MAX_SHADER_COMPILER_THREADS_KHR, &int64Value); GLU_EXPECT_NO_ERROR(gl.getError(), "getInteger64v"); } gl.getFloatv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &floatValue); GLU_EXPECT_NO_ERROR(gl.getError(), "getFloatv"); if (supportsDouble) { gl.getDoublev(GL_MAX_SHADER_COMPILER_THREADS_KHR, &doubleValue); GLU_EXPECT_NO_ERROR(gl.getError(), "getDoublev"); } if (boolValue != (intValue != 0) || intValue != (GLint)floatValue || (supportsInt64 && intValue != (GLint)int64Value) || (supportsDouble && intValue != (GLint)doubleValue)) { tcu::MessageBuilder message = m_testCtx.getLog() << tcu::TestLog::Message; message << "Simple queries returned different values: " << "bool(" << (int)boolValue << "), " << "int(" << intValue << "), "; if (supportsInt64) message << "int64(" << int64Value << "), "; message << "float(" << floatValue << ")"; if (supportsDouble) message << ", double(" << doubleValue << ")"; message << tcu::TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } /** Constructor. * * @param context Rendering context * @param name Test name * @param description Test description */ MaxShaderCompileThreadsTest::MaxShaderCompileThreadsTest(deqp::Context& context) : TestCase(context, "max_shader_compile_threads", "Tests verifies if MaxShaderCompileThreadsKHR function works as expected") { /* Left blank intentionally */ } /** Executes test iteration. * * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. */ tcu::TestNode::IterateResult MaxShaderCompileThreadsTest::iterate() { const glu::ContextInfo& contextInfo = m_context.getContextInfo(); const glu::ContextType& contextType = m_context.getRenderContext().getType(); const bool isGL = glu::isContextTypeGLCore(contextType); const bool supportParallel = (isGL && contextInfo.isExtensionSupported("GL_ARB_parallel_shader_compile")) || contextInfo.isExtensionSupported("GL_KHR_parallel_shader_compile"); if (!supportParallel) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported"); return STOP; } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); GLint intValue; gl.maxShaderCompilerThreadsKHR(0); GLU_EXPECT_NO_ERROR(gl.getError(), "maxShaderCompilerThreadsKHR"); gl.getIntegerv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &intValue); GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv"); if (intValue != 0) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Failed to disable parallel shader compilation."); return STOP; } gl.maxShaderCompilerThreadsKHR(0xFFFFFFFF); GLU_EXPECT_NO_ERROR(gl.getError(), "maxShaderCompilerThreadsKHR"); gl.getIntegerv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &intValue); GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv"); if (intValue != GLint(0xFFFFFFFF)) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Failed to set maximum shader compiler threads."); return STOP; } m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } /** Constructor. * * @param context Rendering context * @param name Test name * @param description Test description */ CompilationCompletionParallelTest::CompilationCompletionParallelTest(deqp::Context& context) : TestCase(context, "compilation_completion_parallel", "Tests verifies if shader COMPLETION_STATUS query works as expected for parallel compilation") { /* Left blank intentionally */ } /** Executes test iteration. * * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. */ tcu::TestNode::IterateResult CompilationCompletionParallelTest::iterate() { const glu::ContextInfo& contextInfo = m_context.getContextInfo(); const glu::ContextType& contextType = m_context.getRenderContext().getType(); const bool isGL = glu::isContextTypeGLCore(contextType); const bool supportParallel = (isGL && contextInfo.isExtensionSupported("GL_ARB_parallel_shader_compile")) || contextInfo.isExtensionSupported("GL_KHR_parallel_shader_compile"); if (!supportParallel) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported"); return STOP; } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); GLint completionStatus; gl.maxShaderCompilerThreadsKHR(8); GLU_EXPECT_NO_ERROR(gl.getError(), "maxShaderCompilerThreadsKHR"); { Shader vertexShader(gl, SHADERTYPE_VERTEX); deUint32 fragmentShader[8]; deUint32 program[8]; bool isContextES = (glu::isContextTypeES(m_context.getRenderContext().getType())); const char* shaderVersion = isContextES ? shaderVersionES : shaderVersionGL; for (int i = 0; i < 8; ++i) { fragmentShader[i] = gl.createShader(GL_FRAGMENT_SHADER); program[i] = gl.createProgram(); } const char* vSources[] = { shaderVersion, vShader }; const int vLengths[] = { int(strlen(shaderVersion)), int(strlen(vShader)) }; vertexShader.setSources(2, vSources, vLengths); //Compilation test for (int i = 0; i < 8; ++i) { const char* fSources[] = { shaderVersion, fShader }; const int fLengths[] = { int(strlen(shaderVersion)), int(strlen(fShader)) }; gl.shaderSource(fragmentShader[i], 2, fSources, fLengths); } gl.compileShader(vertexShader.getShader()); GLU_EXPECT_NO_ERROR(gl.getError(), "compileShader"); for (int i = 0; i < 8; ++i) { gl.compileShader(fragmentShader[i]); GLU_EXPECT_NO_ERROR(gl.getError(), "compileShader"); } { int completion = 0; deUint64 shLoopStart = deGetMicroseconds(); while (completion != 8 && deGetMicroseconds() < shLoopStart + 1000000) { completion = 0; for (int i = 0; i < 8; ++i) { gl.getShaderiv(fragmentShader[i], GL_COMPLETION_STATUS_KHR, &completionStatus); GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv"); if (completionStatus) completion++; } } if (completion != 8) { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed reading completion status for parallel shader compiling"); for (int i = 0; i < 8; ++i) { gl.deleteProgram(program[i]); gl.deleteShader(fragmentShader[i]); } return STOP; } } for (int i = 0; i < 8; ++i) { gl.attachShader(program[i], vertexShader.getShader()); GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader"); gl.attachShader(program[i], fragmentShader[i]); GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader"); } //Linking test for (int i = 0; i < 8; ++i) { gl.linkProgram(program[i]); GLU_EXPECT_NO_ERROR(gl.getError(), "linkProgram"); } { int completion = 0; deUint64 prLoopStart = deGetMicroseconds(); while (completion != 8 && deGetMicroseconds() < prLoopStart + 1000000) { completion = 0; for (int i = 0; i < 8; ++i) { gl.getProgramiv(program[i], GL_COMPLETION_STATUS_KHR, &completionStatus); GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv"); if (completionStatus) completion++; } } if (completion != 8) { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed reading completion status for parallel program linking"); for (int i = 0; i < 8; ++i) { gl.deleteProgram(program[i]); gl.deleteShader(fragmentShader[i]); } return STOP; } } } m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } /** Constructor. * * @param context Rendering context. */ ParallelShaderCompileTests::ParallelShaderCompileTests(deqp::Context& context) : TestCaseGroup(context, "parallel_shader_compile", "Verify conformance of KHR_parallel_shader_compile implementation") { } /** Initializes the test group contents. */ void ParallelShaderCompileTests::init() { addChild(new SimpleQueriesTest(m_context)); addChild(new MaxShaderCompileThreadsTest(m_context)); addChild(new CompilationCompletionParallelTest(m_context)); } } /* glcts namespace */