/*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2015-2016 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 gl4cSyncTests.cpp * \brief Declares test classes for synchronization functionality. */ /*-------------------------------------------------------------------*/ #include "gl4cSyncTests.hpp" #include "deSharedPtr.hpp" #include "gluContextInfo.hpp" #include "gluDefs.hpp" #include "gluPixelTransfer.hpp" #include "gluStrUtil.hpp" #include "tcuFuzzyImageCompare.hpp" #include "tcuImageCompare.hpp" #include "tcuRenderTarget.hpp" #include "tcuSurface.hpp" #include "tcuTestLog.hpp" #include "glw.h" #include "glwFunctions.hpp" /* Timeout of the test in nanoseconds. */ #define TEST_SYNC_WAIT_TIMEOUT 16000000000 namespace gl4cts { namespace Sync { /****************************************** Tests Group ***********************************************/ /** @brief Sync Tests Group constructor. * * @param [in] context OpenGL context. */ Tests::Tests(deqp::Context& context) : TestCaseGroup(context, "sync", "Sync Tests Suite") { } /** @brief Sync Tests initializer. */ void Tests::init() { addChild(new Sync::FlushCommandsTest(m_context)); } /*************************************** Flush Commands Test *******************************************/ /** @brief Sync Flush Commands Test constructor. * * @param [in] context OpenGL context. */ FlushCommandsTest::FlushCommandsTest(deqp::Context& context) : deqp::TestCase(context, "flush_commands", "Sync Flush Commands Test") { /* Intentionally left blank. */ } /** @brief Iterate Sync Flush Commands Test cases. * * @return Iteration result. */ tcu::TestNode::IterateResult FlushCommandsTest::iterate() { /* Shortcut for GL functionality. */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Get context setup. */ bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); return STOP; } /* Running tests. */ bool is_ok = false; bool is_error = false; bool is_timeout = false; /* Test constants. */ static const glw::GLuint reference[2] = { 3, 1415927 }; static const glw::GLuint reference_size = sizeof(reference); /* Test objects. */ glw::GLuint buffer_src = 0; glw::GLuint buffer_dst = 0; glw::GLsync sync = 0; glw::GLenum error = GL_NO_ERROR; try { /* Prepare buffers. */ gl.createBuffers(1, &buffer_src); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateBuffers have failed"); gl.namedBufferData(buffer_src, reference_size, reference, GL_STATIC_COPY); GLU_EXPECT_NO_ERROR(gl.getError(), "glNamedBufferData have failed"); gl.createBuffers(1, &buffer_dst); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateBuffers have failed"); gl.namedBufferStorage(buffer_dst, reference_size, NULL, GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glNamedBufferStorage have failed"); /* Map perisistently buffer range. */ glw::GLuint* data_dst = (glw::GLuint*)gl.mapNamedBufferRange( buffer_dst, 0, reference_size, GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapNamedBufferRange have failed"); /* Copy data from source to destination buffer */ gl.copyNamedBufferSubData(buffer_src, buffer_dst, 0, 0, reference_size); if (GL_NO_ERROR != (error = gl.getError())) { gl.unmapNamedBuffer(buffer_dst); GLU_EXPECT_NO_ERROR(error, "glCopyNamedBufferSubData have failed"); } /* Create fence sync object. */ sync = gl.fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); if (GL_NO_ERROR == (error = gl.getError())) { /* Wait until done. */ glw::GLenum wait_result = gl.clientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, TEST_SYNC_WAIT_TIMEOUT); /* Check for error. */ if (GL_NO_ERROR == (error = gl.getError())) { /* Check for timeout. */ if (GL_TIMEOUT_EXPIRED == wait_result) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "ClientWaitSync with SYNC_FLUSH_COMMANDS_BIT flag has returned TIMEOUT_EXPIRED after " << TEST_SYNC_WAIT_TIMEOUT << " nanoseconds. Potentially test may not be done in finite time " "which is expected (OpenGL 4.5 Core Profile, Chapter 4.1.2)." << " However this cannot be proven in finite time. Test timeouts." << tcu::TestLog::EndMessage; is_timeout = true; } /* Check for proper wait result. */ else if ((GL_CONDITION_SATISFIED == wait_result) || (GL_ALREADY_SIGNALED == wait_result)) { /* Compare destination buffer data with reference. */ if ((reference[0] == data_dst[0]) || (reference[1] == data_dst[1])) { is_ok = true; } else { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Result data [" << data_dst[0] << ", " << data_dst[1] << "is not equal to the reference [" << reference[0] << ", " << reference[1] << "]. Tests fails." << tcu::TestLog::EndMessage; } } } else { m_context.getTestContext().getLog() << tcu::TestLog::Message << "ClientWaitSync unexpectedly generated error " << glu::getErrorStr(error) << ". Tests fails." << tcu::TestLog::EndMessage; } } /* Unmapping. */ gl.unmapNamedBuffer(buffer_dst); GLU_EXPECT_NO_ERROR(error, "glUnmapNamedBuffer have failed"); } catch (...) { is_ok = false; is_error = true; } /* Cleanup. */ if (buffer_src) { gl.deleteBuffers(1, &buffer_src); } if (buffer_dst) { gl.deleteBuffers(1, &buffer_dst); } if (sync) { gl.deleteSync(sync); } /* Result's setup. */ if (is_timeout) { m_testCtx.setTestResult( QP_TEST_RESULT_TIMEOUT, "Timeout (Potentially, ClientWaitSync with SYNC_FLUSH_COMMANDS does not return in finite time)."); } else { if (is_ok) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { if (is_error) { m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } } } return STOP; } } /* Sync namespace */ } /* gl4cts namespace */