/*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 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 gl4cIndirectParametersTests.cpp * \brief Conformance tests for the GL_ARB_indirect_parameters functionality. */ /*-------------------------------------------------------------------*/ #include "gl4cIndirectParametersTests.hpp" #include "gluContextInfo.hpp" #include "gluDefs.hpp" #include "gluDrawUtil.hpp" #include "gluShaderProgram.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include "tcuRenderTarget.hpp" #include "tcuTestLog.hpp" using namespace glw; using namespace glu; namespace gl4cts { static const char* c_vertShader = "#version 430\n" "\n" "in vec3 vertex;\n" "\n" "void main()\n" "{\n" " gl_Position = vec4(vertex, 1);\n" "}\n"; static const char* c_fragShader = "#version 430\n" "\n" "out vec4 fragColor;\n" "\n" "void main()\n" "{\n" " fragColor = vec4(1, 1, 1, 0.5);\n" "}\n"; /** Constructor. * * @param context Rendering context */ ParameterBufferOperationsCase::ParameterBufferOperationsCase(deqp::Context& context) : TestCase(context, "ParameterBufferOperations", "Verifies if operations on new buffer object PARAMETER_BUFFER_ARB works as expected.") { /* Left blank intentionally */ } /** Stub init method */ void ParameterBufferOperationsCase::init() { } /** Executes test iteration. * * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. */ tcu::TestNode::IterateResult ParameterBufferOperationsCase::iterate() { glu::ContextType contextType = m_context.getRenderContext().getType(); if (!glu::contextSupports(contextType, glu::ApiType::core(4, 6)) && !m_context.getContextInfo().isExtensionSupported("GL_ARB_indirect_parameters")) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); return STOP; } const Functions& gl = m_context.getRenderContext().getFunctions(); GLuint paramBuffer; GLint data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; GLint subData[] = { 10, 11, 12, 13, 14 }; GLint expData[] = { 0, 1, 10, 11, 12, 13, 14, 7, 8, 9 }; bool result = true; // Test buffer generating and binding gl.genBuffers(1, ¶mBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, paramBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); GLint paramBinding; gl.getIntegerv(GL_PARAMETER_BUFFER_BINDING_ARB, ¶mBinding); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv"); if ((GLuint)paramBinding != paramBuffer) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Buffer binding mismatch" << tcu::TestLog::EndMessage; } else { // Test filling buffer with data gl.bufferData(GL_PARAMETER_BUFFER_ARB, 10 * sizeof(GLint), data, GL_DYNAMIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); gl.bufferSubData(GL_PARAMETER_BUFFER_ARB, 2 * sizeof(GLint), 5 * sizeof(GLint), subData); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); // Test buffer mapping GLvoid* buffer = gl.mapBuffer(GL_PARAMETER_BUFFER_ARB, GL_READ_ONLY); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer"); if (memcmp(buffer, expData, 10 * sizeof(GLint)) != 0) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Buffer data mismatch" << tcu::TestLog::EndMessage; } else { GLvoid* bufferPointer; gl.getBufferPointerv(GL_PARAMETER_BUFFER_ARB, GL_BUFFER_MAP_POINTER, &bufferPointer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBufferPointerv"); if (buffer != bufferPointer) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Buffer pointer mismatch" << tcu::TestLog::EndMessage; } else { GLint bufferSize; GLint bufferUsage; gl.getBufferParameteriv(GL_PARAMETER_BUFFER_ARB, GL_BUFFER_SIZE, &bufferSize); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBufferParameteriv"); gl.getBufferParameteriv(GL_PARAMETER_BUFFER_ARB, GL_BUFFER_USAGE, &bufferUsage); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBufferParameteriv"); if (bufferSize != 10 * sizeof(GLint)) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Buffer size mismatch" << tcu::TestLog::EndMessage; } else if (bufferUsage != GL_DYNAMIC_DRAW) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Buffer usage mismatch" << tcu::TestLog::EndMessage; } } } gl.unmapBuffer(GL_PARAMETER_BUFFER_ARB); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer"); // Test buffer ranged mapping buffer = gl.mapBufferRange(GL_PARAMETER_BUFFER_ARB, 0, sizeof(GLint), GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange"); // Test buffer flushing GLint* bufferInt = (GLint*)buffer; bufferInt[0] = 100; gl.flushMappedBufferRange(GL_PARAMETER_BUFFER_ARB, 0, sizeof(GLint)); GLU_EXPECT_NO_ERROR(gl.getError(), "glFlushMappedBufferRange"); gl.unmapBuffer(GL_PARAMETER_BUFFER_ARB); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer"); // Test buffers data copying GLuint arrayBuffer; gl.genBuffers(1, &arrayBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); gl.bindBuffer(GL_ARRAY_BUFFER, arrayBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); gl.bufferData(GL_ARRAY_BUFFER, 10 * sizeof(GLint), data, GL_DYNAMIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); gl.copyBufferSubData(GL_PARAMETER_BUFFER_ARB, GL_ARRAY_BUFFER, 0, 0, sizeof(GLint)); GLU_EXPECT_NO_ERROR(gl.getError(), "glCopyBufferSubData"); gl.mapBufferRange(GL_ARRAY_BUFFER, 0, 1, GL_MAP_READ_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange"); bufferInt = (GLint*)buffer; if (bufferInt[0] != 100) { result = false; m_testCtx.getLog() << tcu::TestLog::Message << "Buffer copy operation failed" << tcu::TestLog::EndMessage; } gl.unmapBuffer(GL_ARRAY_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer"); // Release array buffer gl.deleteBuffers(1, &arrayBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers"); } // Release parameter buffer gl.deleteBuffers(1, ¶mBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers"); if (result) m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); else m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } /** Constructor. * * @param context Rendering context */ VertexArrayIndirectDrawingBaseCase::VertexArrayIndirectDrawingBaseCase(deqp::Context& context, const char* name, const char* description) : TestCase(context, name, description) { /* Left blank intentionally */ } /** Executes test iteration. * * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. */ tcu::TestNode::IterateResult VertexArrayIndirectDrawingBaseCase::iterate() { glu::ContextType contextType = m_context.getRenderContext().getType(); if (!glu::contextSupports(contextType, glu::ApiType::core(4, 6)) && !m_context.getContextInfo().isExtensionSupported("GL_ARB_indirect_parameters")) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); return STOP; } if (draw() && verify()) m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); else m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } /** This method verifies if drawn quads are as expected. * * @return Returns true if quads are drawn properly, false otherwise. */ bool VertexArrayIndirectDrawingBaseCase::verify() { const Functions& gl = m_context.getRenderContext().getFunctions(); const tcu::RenderTarget& rt = m_context.getRenderContext().getRenderTarget(); const int width = rt.getWidth(); const int height = rt.getHeight(); std::vector pixels; pixels.resize(width * height); gl.pixelStorei(GL_PACK_ALIGNMENT, 1); gl.readPixels(0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, pixels.data()); gl.pixelStorei(GL_PACK_ALIGNMENT, 4); //Verify first quad for (int y = 2; y < height - 2; ++y) { for (int x = 2; x < width / 2 - 2; ++x) { int value = pixels[x + y * width]; // Support 5-bit precision for the framebuffer, re-quantized to 8-bits from glReadPixels. if (value < 189 || value > 197) { m_testCtx.getLog() << tcu::TestLog::Message << "First quad verification failed. " << "Wrong value read from framebuffer at " << x << "/" << y << " value: " << value << ", expected: <189-197>" << tcu::TestLog::EndMessage; return false; } } } //Verify second quad for (int y = 2; y < height - 2; ++y) { for (int x = width / 2 + 2; x < width - 2; ++x) { int value = pixels[x + y * width]; // Support 5-bit precision for the framebuffer, re-quantized to 8-bits from glReadPixels. if (value < 123 || value > 132) { m_testCtx.getLog() << tcu::TestLog::Message << "Second quad verification failed. " << "Wrong value read from framebuffer at " << x << "/" << y << " value: " << value << ", expected: <123-132>" << tcu::TestLog::EndMessage; return false; } } } return verifyErrors(); } /** Constructor. * * @param context Rendering context */ MultiDrawArraysIndirectCountCase::MultiDrawArraysIndirectCountCase(deqp::Context& context) : VertexArrayIndirectDrawingBaseCase(context, "MultiDrawArraysIndirectCount", "Test verifies if MultiDrawArraysIndirectCountARB function works as expected.") , m_vao(0) , m_arrayBuffer(0) , m_drawIndirectBuffer(0) , m_parameterBuffer(0) { /* Left blank intentionally */ } /** Stub init method */ void MultiDrawArraysIndirectCountCase::init() { glu::ContextType contextType = m_context.getRenderContext().getType(); if (!glu::contextSupports(contextType, glu::ApiType::core(4, 6)) && !m_context.getContextInfo().isExtensionSupported("GL_ARB_indirect_parameters")) return; const Functions& gl = m_context.getRenderContext().getFunctions(); const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f }; const DrawArraysIndirectCommand indirect[] = { { 4, 2, 0, 0 }, //4 vertices, 2 instanceCount, 0 first, 0 baseInstance { 4, 1, 2, 0 } //4 vertices, 1 instanceCount, 2 first, 0 baseInstance }; const GLushort parameters[] = { 2, 1 }; // Generate vertex array object gl.genVertexArrays(1, &m_vao); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays"); gl.bindVertexArray(m_vao); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray"); // Setup vertex array buffer gl.genBuffers(1, &m_arrayBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); gl.bufferData(GL_ARRAY_BUFFER, 24 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); // Setup indirect command buffer gl.genBuffers(1, &m_drawIndirectBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_drawIndirectBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); gl.bufferData(GL_DRAW_INDIRECT_BUFFER, 2 * sizeof(DrawArraysIndirectCommand), indirect, GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); // Setup parameter buffer gl.genBuffers(1, &m_parameterBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, m_parameterBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); gl.bufferData(GL_PARAMETER_BUFFER_ARB, 100 * sizeof(GLushort), parameters, GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); } /** Stub deinit method */ void MultiDrawArraysIndirectCountCase::deinit() { const Functions& gl = m_context.getRenderContext().getFunctions(); if (m_vao) gl.deleteVertexArrays(1, &m_vao); if (m_arrayBuffer) gl.deleteBuffers(1, &m_arrayBuffer); if (m_drawIndirectBuffer) gl.deleteBuffers(1, &m_drawIndirectBuffer); if (m_parameterBuffer) gl.deleteBuffers(1, &m_parameterBuffer); } /** Drawing quads method using drawArrays. */ bool MultiDrawArraysIndirectCountCase::draw() { const Functions& gl = m_context.getRenderContext().getFunctions(); ProgramSources sources = makeVtxFragSources(c_vertShader, c_fragShader); ShaderProgram program(gl, sources); if (!program.isOk()) { m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n" << "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n" << "Fragment: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n" << "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage; return false; } gl.useProgram(program.getProgram()); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram"); gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); gl.clear(GL_COLOR_BUFFER_BIT); gl.enable(GL_BLEND); gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl.enableVertexAttribArray(0); GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray"); gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer"); gl.multiDrawArraysIndirectCount(GL_TRIANGLE_STRIP, 0, 0, 2, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glMultiDrawArraysIndirectCountARB"); gl.disableVertexAttribArray(0); GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray"); gl.disable(GL_BLEND); return true; } /** Verify MultiDrawArrayIndirectCountARB errors */ bool MultiDrawArraysIndirectCountCase::verifyErrors() { const Functions& gl = m_context.getRenderContext().getFunctions(); GLint errorCode; bool result = true; // INVALID_VALUE - drawcount offset not multiple of 4 gl.multiDrawArraysIndirectCount(GL_TRIANGLE_STRIP, 0, 2, 1, 0); errorCode = gl.getError(); if (errorCode != GL_INVALID_VALUE) { m_testCtx.getLog() << tcu::TestLog::Message << "MultiDrawArraysIndirectCount error verifying failed (1). Expected code: " << GL_INVALID_VALUE << ", current code: " << errorCode << tcu::TestLog::EndMessage; result = false; } // INVALID_OPERATION - maxdrawcount greater then parameter buffer size gl.multiDrawArraysIndirectCount(GL_TRIANGLE_STRIP, 0, 0, 4, 0); errorCode = gl.getError(); if (errorCode != GL_INVALID_OPERATION) { m_testCtx.getLog() << tcu::TestLog::Message << "MultiDrawArraysIndirectCount error verifying failed (2). Expected code: " << GL_INVALID_OPERATION << ", current code: " << errorCode << tcu::TestLog::EndMessage; result = false; } gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); // INVALID_OPERATION - GL_PARAMETER_BUFFER_ARB not bound gl.multiDrawArraysIndirectCount(GL_TRIANGLE_STRIP, 0, 0, 2, 0); errorCode = gl.getError(); if (errorCode != GL_INVALID_OPERATION) { m_testCtx.getLog() << tcu::TestLog::Message << "MultiDrawArraysIndirectCount error verifying failed (3). Expected code: " << GL_INVALID_OPERATION << ", current code: " << errorCode << tcu::TestLog::EndMessage; result = false; } return result; } /** Constructor. * * @param context Rendering context */ MultiDrawElementsIndirectCountCase::MultiDrawElementsIndirectCountCase(deqp::Context& context) : VertexArrayIndirectDrawingBaseCase( context, "MultiDrawElementsIndirectCount", "Test verifies if MultiDrawElementsIndirectCountARB function works as expected.") , m_vao(0) , m_arrayBuffer(0) , m_elementBuffer(0) , m_drawIndirectBuffer(0) , m_parameterBuffer(0) { /* Left blank intentionally */ } /** Stub init method */ void MultiDrawElementsIndirectCountCase::init() { glu::ContextType contextType = m_context.getRenderContext().getType(); if (!glu::contextSupports(contextType, glu::ApiType::core(4, 6)) && !m_context.getContextInfo().isExtensionSupported("GL_ARB_indirect_parameters")) return; const Functions& gl = m_context.getRenderContext().getFunctions(); const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f }; const GLushort elements[] = { 0, 1, 2, 3, 4, 5 }; const DrawElementsIndirectCommand indirect[] = { { 4, 2, 0, 0, 0 }, //4 indices, 2 instanceCount, 0 firstIndex, 0 baseVertex, 0 baseInstance { 4, 1, 2, 0, 0 } //4 indices, 1 instanceCount, 2 firstIndex, 0 baseVertex, 0 baseInstance }; const GLushort parameters[] = { 2, 1 }; // Generate vertex array object gl.genVertexArrays(1, &m_vao); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays"); gl.bindVertexArray(m_vao); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray"); // Setup vertex array buffer gl.genBuffers(1, &m_arrayBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); gl.bufferData(GL_ARRAY_BUFFER, 24 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); // Setup element array buffer gl.genBuffers(1, &m_elementBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLushort), elements, GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); // Setup indirect command buffer gl.genBuffers(1, &m_drawIndirectBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_drawIndirectBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); gl.bufferData(GL_DRAW_INDIRECT_BUFFER, 3 * sizeof(DrawElementsIndirectCommand), indirect, GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); // Setup parameters Re: buffer gl.genBuffers(1, &m_parameterBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, m_parameterBuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); gl.bufferData(GL_PARAMETER_BUFFER_ARB, 2 * sizeof(GLushort), parameters, GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); } /** Stub deinit method */ void MultiDrawElementsIndirectCountCase::deinit() { const Functions& gl = m_context.getRenderContext().getFunctions(); if (m_vao) gl.deleteVertexArrays(1, &m_vao); if (m_arrayBuffer) gl.deleteBuffers(1, &m_arrayBuffer); if (m_elementBuffer) gl.deleteBuffers(1, &m_elementBuffer); if (m_drawIndirectBuffer) gl.deleteBuffers(1, &m_drawIndirectBuffer); if (m_parameterBuffer) gl.deleteBuffers(1, &m_parameterBuffer); } /** Drawing quads method using drawArrays. */ bool MultiDrawElementsIndirectCountCase::draw() { const Functions& gl = m_context.getRenderContext().getFunctions(); ProgramSources sources = makeVtxFragSources(c_vertShader, c_fragShader); ShaderProgram program(gl, sources); if (!program.isOk()) { m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n" << "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n" << "Fragment: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n" << "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage; return false; } gl.useProgram(program.getProgram()); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram"); gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); gl.clear(GL_COLOR_BUFFER_BIT); gl.enable(GL_BLEND); gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl.enableVertexAttribArray(0); GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray"); gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer"); gl.multiDrawElementsIndirectCount(GL_TRIANGLE_STRIP, GL_UNSIGNED_SHORT, 0, 0, 2, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glMultiDrawElementsIndirectCountARB"); gl.disableVertexAttribArray(0); GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray"); gl.disable(GL_BLEND); return true; } /** Verify MultiDrawElementsIndirectCountARB errors */ bool MultiDrawElementsIndirectCountCase::verifyErrors() { const Functions& gl = m_context.getRenderContext().getFunctions(); GLint errorCode; bool result = true; // INVALID_VALUE - drawcount offset not multiple of 4 gl.multiDrawElementsIndirectCount(GL_TRIANGLE_STRIP, GL_UNSIGNED_BYTE, 0, 2, 1, 0); errorCode = gl.getError(); if (errorCode != GL_INVALID_VALUE) { m_testCtx.getLog() << tcu::TestLog::Message << "MultiDrawElementIndirectCount error verifying failed (1). Expected code: " << GL_INVALID_VALUE << ", current code: " << errorCode << tcu::TestLog::EndMessage; result = false; } // INVALID_OPERATION - maxdrawcount greater then parameter buffer size gl.multiDrawElementsIndirectCount(GL_TRIANGLE_STRIP, GL_UNSIGNED_BYTE, 0, 0, 4, 0); errorCode = gl.getError(); if (errorCode != GL_INVALID_OPERATION) { m_testCtx.getLog() << tcu::TestLog::Message << "MultiDrawElementIndirectCount error verifying failed (2). Expected code: " << GL_INVALID_OPERATION << ", current code: " << errorCode << tcu::TestLog::EndMessage; result = false; } gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); // INVALID_OPERATION - GL_PARAMETER_BUFFER_ARB not bound gl.multiDrawElementsIndirectCount(GL_TRIANGLE_STRIP, GL_UNSIGNED_BYTE, 0, 0, 3, 0); errorCode = gl.getError(); if (errorCode != GL_INVALID_OPERATION) { m_testCtx.getLog() << tcu::TestLog::Message << "MultiDrawElementIndirectCount error verifying failed (3). Expected code: " << GL_INVALID_OPERATION << ", current code: " << errorCode << tcu::TestLog::EndMessage; result = false; } return result; } /** Constructor. * * @param context Rendering context. */ IndirectParametersTests::IndirectParametersTests(deqp::Context& context) : TestCaseGroup(context, "indirect_parameters_tests", "Verify conformance of CTS_ARB_indirect_parameters implementation") { } /** Initializes the test group contents. */ void IndirectParametersTests::init() { addChild(new ParameterBufferOperationsCase(m_context)); addChild(new MultiDrawArraysIndirectCountCase(m_context)); addChild(new MultiDrawElementsIndirectCountCase(m_context)); } } /* gl4cts namespace */