// // Copyright 2015 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // #include "test_utils/ANGLETest.h" #include "test_utils/gl_raii.h" using namespace angle; class LineLoopTest : public ANGLETest<> { protected: LineLoopTest() { setWindowWidth(256); setWindowHeight(256); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } void testSetUp() override { mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); if (mProgram == 0) { FAIL() << "shader compilation failed."; } mPositionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib()); mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform()); glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_BLEND); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); ASSERT_GL_NO_ERROR(); } void testTearDown() override { glDeleteProgram(mProgram); } void checkPixels() { std::vector pixels(getWindowWidth() * getWindowHeight() * 4); glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); ASSERT_GL_NO_ERROR(); for (int y = 0; y < getWindowHeight(); y++) { for (int x = 0; x < getWindowWidth(); x++) { const GLubyte *pixel = &pixels[0] + ((y * getWindowWidth() + x) * 4); EXPECT_EQ(pixel[0], 0) << "Failed at " << x << ", " << y << std::endl; EXPECT_EQ(pixel[1], pixel[2]) << "Failed at " << x << ", " << y << std::endl; ASSERT_EQ(pixel[3], 255) << "Failed at " << x << ", " << y << std::endl; } } } void preTestUpdateBuffer(GLuint framebuffer, GLuint texture, GLuint buffer, GLsizei size) { GLsizei uboSize = std::max(size, 16); const std::vector initialData((uboSize + 3) / 4, 0x1234567u); glBindTexture(GL_TEXTURE_2D, texture); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); glBindBuffer(GL_UNIFORM_BUFFER, buffer); glBufferData(GL_UNIFORM_BUFFER, uboSize, initialData.data(), GL_DYNAMIC_DRAW); glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer); constexpr char kVerifyUBO[] = R"(#version 300 es precision mediump float; uniform block { uint data; } ubo; out vec4 colorOut; void main() { if (ubo.data == 0x1234567u) colorOut = vec4(0, 1.0, 0, 1.0); else colorOut = vec4(1.0, 0, 0, 1.0); })"; ANGLE_GL_PROGRAM(verifyUbo, essl3_shaders::vs::Simple(), kVerifyUBO); glDisable(GL_BLEND); drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5); EXPECT_GL_NO_ERROR(); glBindFramebuffer(GL_FRAMEBUFFER, 0); } void runTest(GLenum indexType, GLuint indexBuffer, const void *indexPtr) { glClear(GL_COLOR_BUFFER_BIT); static const GLfloat loopPositions[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f}; static const GLfloat stripPositions[] = {-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f}; static const GLubyte stripIndices[] = {1, 0, 3, 2, 1}; glEnable(GL_BLEND); glUseProgram(mProgram); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glEnableVertexAttribArray(mPositionLocation); glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, loopPositions); glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f); glDrawElements(GL_LINE_LOOP, 4, indexType, indexPtr); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, stripPositions); glUniform4f(mColorLocation, 0, 1, 0, 1); glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, stripIndices); checkPixels(); } GLuint mProgram; GLint mPositionLocation; GLint mColorLocation; }; TEST_P(LineLoopTest, LineLoopUByteIndices) { // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. // On Win7, the D3D SDK Layers emits a false warning for these tests. // This doesn't occur on Windows 10 (Version 1511) though. ignoreD3D11SDKLayersWarnings(); static const GLubyte indices[] = {0, 7, 6, 9, 8, 0}; runTest(GL_UNSIGNED_BYTE, 0, indices + 1); } TEST_P(LineLoopTest, LineLoopUShortIndices) { // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); static const GLushort indices[] = {0, 7, 6, 9, 8, 0}; runTest(GL_UNSIGNED_SHORT, 0, indices + 1); } TEST_P(LineLoopTest, LineLoopUIntIndices) { if (!IsGLExtensionEnabled("GL_OES_element_index_uint")) { return; } // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); static const GLuint indices[] = {0, 7, 6, 9, 8, 0}; runTest(GL_UNSIGNED_INT, 0, indices + 1); } TEST_P(LineLoopTest, LineLoopUByteIndexBuffer) { // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); static const GLubyte indices[] = {0, 7, 6, 9, 8, 0}; GLBuffer buf; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); runTest(GL_UNSIGNED_BYTE, buf, reinterpret_cast(sizeof(GLubyte))); } TEST_P(LineLoopTest, LineLoopUShortIndexBuffer) { // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); static const GLushort indices[] = {0, 7, 6, 9, 8, 0}; GLBuffer buf; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); runTest(GL_UNSIGNED_SHORT, buf, reinterpret_cast(sizeof(GLushort))); } TEST_P(LineLoopTest, LineLoopUIntIndexBuffer) { if (!IsGLExtensionEnabled("GL_OES_element_index_uint")) { return; } // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); static const GLuint indices[] = {0, 7, 6, 9, 8, 0}; GLBuffer buf; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); runTest(GL_UNSIGNED_INT, buf, reinterpret_cast(sizeof(GLuint))); } // Test that drawing elements between line loop arrays using the same array buffer does not result // in incorrect rendering. TEST_P(LineLoopTest, DrawTriangleElementsBetweenArrays) { // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); static const GLfloat positions[] = {-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.1f, 0.1f, -0.1f, -0.1f, 0.1f, -0.1f, 0.1f, 0.1f}; static const GLubyte indices[] = {5, 6, 7, 5, 7, 8}; GLBuffer arrayBuffer; glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW); GLBuffer indexBuffer; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgram); glEnableVertexAttribArray(mPositionLocation); glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, nullptr); glEnable(GL_BLEND); glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f); glDrawArrays(GL_LINE_LOOP, 0, 4); glUniform4f(mColorLocation, 0.0f, 0.0f, 0.0f, 1.0f); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr); glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f); glDrawArrays(GL_LINE_LOOP, 0, 4); checkPixels(); } class LineLoopTestES3 : public LineLoopTest {}; // Test that uploading data to buffer that's in use then using it for line loop elements works. TEST_P(LineLoopTestES3, UseAsUBOThenUpdateThenLineLoopUByteIndexBuffer) { // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); static const GLubyte indices[] = {0, 7, 6, 9, 8, 0}; GLFramebuffer framebuffer; GLTexture texture; GLBuffer buf; preTestUpdateBuffer(framebuffer, texture, buf, sizeof(indices)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices); runTest(GL_UNSIGNED_BYTE, buf, reinterpret_cast(sizeof(GLubyte))); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } // Test that uploading data to buffer that's in use then using it for line loop elements works. TEST_P(LineLoopTestES3, UseAsUBOThenUpdateThenLineLoopUShortIndexBuffer) { // http://anglebug.com/42264370 ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm()); // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); static const GLushort indices[] = {0, 7, 6, 9, 8, 0}; GLFramebuffer framebuffer; GLTexture texture; GLBuffer buf; preTestUpdateBuffer(framebuffer, texture, buf, sizeof(indices)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices); runTest(GL_UNSIGNED_SHORT, buf, reinterpret_cast(sizeof(GLushort))); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } // Test that uploading data to buffer that's in use then using it for line loop elements works. TEST_P(LineLoopTestES3, UseAsUBOThenUpdateThenLineLoopUIntIndexBuffer) { if (!IsGLExtensionEnabled("GL_OES_element_index_uint")) { return; } // http://anglebug.com/42264370 ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm()); // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); static const GLuint indices[] = {0, 7, 6, 9, 8, 0}; GLFramebuffer framebuffer; GLTexture texture; GLBuffer buf; preTestUpdateBuffer(framebuffer, texture, buf, sizeof(indices)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices); runTest(GL_UNSIGNED_INT, buf, reinterpret_cast(sizeof(GLuint))); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } // Tests an edge case with a very large line loop element count. // Disabled because it is slow and triggers an internal error. TEST_P(LineLoopTest, DISABLED_DrawArraysWithLargeCount) { constexpr char kVS[] = "void main() { gl_Position = vec4(0); }"; constexpr char kFS[] = "void main() { gl_FragColor = vec4(0, 1, 0, 1); }"; ANGLE_GL_PROGRAM(program, kVS, kFS); glUseProgram(program); glDrawArrays(GL_LINE_LOOP, 0, 0x3FFFFFFE); EXPECT_GL_ERROR(GL_OUT_OF_MEMORY); glDrawArrays(GL_LINE_LOOP, 0, 0x1FFFFFFE); EXPECT_GL_NO_ERROR(); } class LineLoopPrimitiveRestartTest : public ANGLETest<> { protected: LineLoopPrimitiveRestartTest() { setWindowWidth(64); setWindowHeight(64); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } }; TEST_P(LineLoopPrimitiveRestartTest, LineLoopWithPrimitiveRestart) { constexpr char kVS[] = R"(#version 300 es in vec2 a_position; // x,y = offset, z = scale in vec3 a_transform; invariant gl_Position; void main() { vec2 v_position = a_transform.z * a_position + a_transform.xy; gl_Position = vec4(v_position, 0.0, 1.0); })"; constexpr char kFS[] = R"(#version 300 es precision highp float; layout (location=0) out vec4 fragColor; void main() { fragColor = vec4(1.0, 0.0, 0.0, 1.0); })"; ANGLE_GL_PROGRAM(program, kVS, kFS); glBindAttribLocation(program, 0, "a_position"); glBindAttribLocation(program, 1, "a_transform"); glLinkProgram(program); glUseProgram(program); ASSERT_GL_NO_ERROR(); // clang-format off constexpr GLfloat vertices[] = { 0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1, 0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1, 0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1, 0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1, }; constexpr GLfloat transform[] = { // first loop transform 0, 0, 9, 0, 0, 9, 0, 0, 9, 0, 0, 9, // second loop transform 0.2, 0.1, 2, 0.2, 0.1, 2, 0.2, 0.1, 2, 0.2, 0.1, 2, // third loop transform 0.5, -0.2, 3, 0.5, -0.2, 3, 0.5, -0.2, 3, 0.5, -0.2, 3, // forth loop transform -0.8, -0.5, 1, -0.8, -0.5, 1, -0.8, -0.5, 1, -0.8, -0.5, 1, }; constexpr GLushort lineloopAsStripIndices[] = { // first strip 0, 1, 2, 3, 0, // second strip 4, 5, 6, 7, 4, // third strip 8, 9, 10, 11, 8, // forth strip 12, 13, 14, 15, 12 }; constexpr GLushort lineloopWithRestartIndices[] = { // first loop 0, 1, 2, 3, 0xffff, // second loop 4, 5, 6, 7, 0xffff, // third loop 8, 9, 10, 11, 0xffff, // forth loop 12, 13, 14, 15, }; // clang-format on std::vector expectedPixels(getWindowWidth() * getWindowHeight()); std::vector renderedPixels(getWindowWidth() * getWindowHeight()); // Draw in non-primitive restart way glClear(GL_COLOR_BUFFER_BIT); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); for (int loop = 0; loop < 4; ++loop) { glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices + 8 * loop); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, transform + 12 * loop); glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, lineloopAsStripIndices); } glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, expectedPixels.data()); ASSERT_GL_NO_ERROR(); // Draw line loop with primitive restart: glClear(GL_COLOR_BUFFER_BIT); GLBuffer vertexBuffer[2]; GLBuffer indexBuffer; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lineloopWithRestartIndices), lineloopWithRestartIndices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(transform), transform, GL_STATIC_DRAW); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); glClear(GL_COLOR_BUFFER_BIT); glDrawElements(GL_LINE_LOOP, ArraySize(lineloopWithRestartIndices), GL_UNSIGNED_SHORT, 0); glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, renderedPixels.data()); for (int y = 0; y < getWindowHeight(); ++y) { for (int x = 0; x < getWindowWidth(); ++x) { int idx = y * getWindowWidth() + x; EXPECT_EQ(expectedPixels[idx], renderedPixels[idx]) << "Expected pixel at " << x << ", " << y << " to be " << expectedPixels[idx] << std::endl; } } } class LineLoopIndirectTest : public LineLoopTest { protected: struct DrawCommand { GLuint count; GLuint primCount; GLuint firstIndex; GLint baseVertex; GLuint reservedMustBeZero; }; void initUpdateBuffers(GLuint vertexArray, GLuint vertexBuffer, GLuint indexBuffer, const void *positions, uint32_t positionsSize, const void *indices, uint32_t indicesSize) { glBindVertexArray(vertexArray); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ARRAY_BUFFER, positionsSize, positions, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesSize, indices, GL_STATIC_DRAW); } void preTestUBOAndInitUpdateBuffers(GLuint vertexArray, GLuint vertexBuffer, GLuint indexBuffer, const void *positions, GLsizei positionsSize, const void *indices, GLsizei indicesSize, GLuint arrayUpdateFbo, GLuint arrayUpdateTexture, GLuint elementUpdateFbo, GLuint elementUpdateTexture) { preTestUpdateBuffer(arrayUpdateFbo, arrayUpdateTexture, vertexBuffer, positionsSize); preTestUpdateBuffer(elementUpdateFbo, elementUpdateTexture, indexBuffer, indicesSize); glBindVertexArray(vertexArray); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferSubData(GL_ARRAY_BUFFER, 0, positionsSize, positions); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indicesSize, indices); } void initIndirectBuffer(GLuint indirectBuffer, GLuint firstIndex) { DrawCommand indirectData = {}; indirectData.count = 4; indirectData.firstIndex = firstIndex; indirectData.primCount = 1; glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer); glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand), &indirectData, GL_STATIC_DRAW); ASSERT_GL_NO_ERROR(); } void setVertexAttribs(const void *positions) { glEnableVertexAttribArray(mPositionLocation); glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, positions); ASSERT_GL_NO_ERROR(); } static constexpr GLfloat kLoopPositions[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f}; static constexpr GLfloat kStripPositions[] = {-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f}; static constexpr GLubyte kStripIndices[] = {1, 0, 3, 2, 1}; }; // Test that drawing a line loop using an index buffer of unsigned bytes works. TEST_P(LineLoopIndirectTest, UByteIndexIndirectBuffer) { // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader. // http://anglebug.com/40096699 ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan()); // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); // Start at index 1. GLuint firstIndex = 1; const GLubyte indices[] = {0, 7, 6, 9, 8, 0}; glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgram); ASSERT_GL_NO_ERROR(); GLVertexArray vertexArray; GLBuffer vertexBuffer; GLBuffer indexBuffer; initUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions, sizeof(kLoopPositions), indices, sizeof(indices)); GLBuffer indirectBuffer; initIndirectBuffer(indirectBuffer, firstIndex); glEnable(GL_BLEND); setVertexAttribs(nullptr); glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f); glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_BYTE, nullptr); ASSERT_GL_NO_ERROR(); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); setVertexAttribs(kStripPositions); glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f); glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices); ASSERT_GL_NO_ERROR(); checkPixels(); } // Test that drawing a line loop using an index buffer of unsigned short values works. TEST_P(LineLoopIndirectTest, UShortIndexIndirectBuffer) { // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader. // http://anglebug.com/40096699 ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan()); // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); // Start at index 1. GLuint firstIndex = 1; const GLushort indices[] = {0, 7, 6, 9, 8, 0}; glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgram); ASSERT_GL_NO_ERROR(); GLVertexArray vertexArray; GLBuffer vertexBuffer; GLBuffer indexBuffer; initUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions, sizeof(kLoopPositions), indices, sizeof(indices)); GLBuffer indirectBuffer; initIndirectBuffer(indirectBuffer, firstIndex); glEnable(GL_BLEND); setVertexAttribs(nullptr); glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f); glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); setVertexAttribs(kStripPositions); glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f); glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices); ASSERT_GL_NO_ERROR(); checkPixels(); } // Test that uploading data to buffer that's in use then using it for line loop elements works. TEST_P(LineLoopIndirectTest, UseAsUBOThenUpdateThenUByteIndexIndirectBuffer) { // http://anglebug.com/42264370 ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm()); // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader. // http://anglebug.com/40096699 ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan()); // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); // Start at index 1. GLuint firstIndex = 1; const GLubyte indices[] = {0, 7, 6, 9, 8, 0}; glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgram); ASSERT_GL_NO_ERROR(); GLVertexArray vertexArray; GLFramebuffer arrayUpdateFbo, elementUpdateFbo; GLTexture arrayUpdateTex, elementUpdateTex; GLBuffer vertexBuffer; GLBuffer indexBuffer; preTestUBOAndInitUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions, sizeof(kLoopPositions), indices, sizeof(indices), arrayUpdateFbo, arrayUpdateTex, elementUpdateFbo, elementUpdateTex); GLBuffer indirectBuffer; initIndirectBuffer(indirectBuffer, firstIndex); glEnable(GL_BLEND); setVertexAttribs(nullptr); glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f); glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_BYTE, nullptr); ASSERT_GL_NO_ERROR(); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); setVertexAttribs(kStripPositions); glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f); glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices); ASSERT_GL_NO_ERROR(); checkPixels(); glBindFramebuffer(GL_FRAMEBUFFER, arrayUpdateFbo); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); glBindFramebuffer(GL_FRAMEBUFFER, elementUpdateFbo); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } // Test that uploading data to buffer that's in use then using it for line loop elements works. TEST_P(LineLoopIndirectTest, UseAsUBOThenUpdateThenUShortIndexIndirectBuffer) { // http://anglebug.com/42264370 ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm()); // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader. // http://anglebug.com/40096699 ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan()); // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); // Start at index 1. GLuint firstIndex = 1; const GLshort indices[] = {0, 7, 6, 9, 8, 0}; glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgram); ASSERT_GL_NO_ERROR(); GLVertexArray vertexArray; GLFramebuffer arrayUpdateFbo, elementUpdateFbo; GLTexture arrayUpdateTex, elementUpdateTex; GLBuffer vertexBuffer; GLBuffer indexBuffer; preTestUBOAndInitUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions, sizeof(kLoopPositions), indices, sizeof(indices), arrayUpdateFbo, arrayUpdateTex, elementUpdateFbo, elementUpdateTex); GLBuffer indirectBuffer; initIndirectBuffer(indirectBuffer, firstIndex); glEnable(GL_BLEND); setVertexAttribs(nullptr); glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f); glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); setVertexAttribs(kStripPositions); glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f); glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices); ASSERT_GL_NO_ERROR(); checkPixels(); glBindFramebuffer(GL_FRAMEBUFFER, arrayUpdateFbo); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); glBindFramebuffer(GL_FRAMEBUFFER, elementUpdateFbo); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } // Test that two indirect draws drawing lineloop and sharing same index buffer works. TEST_P(LineLoopIndirectTest, TwoIndirectDrawsShareIndexBuffer) { // http://anglebug.com/42264370 ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm()); // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader. // http://anglebug.com/40096699 ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan()); // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); // Start at index 1. GLuint firstIndex = 1; const GLushort indices[] = {0, 7, 6, 9, 8, 0}; glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgram); ASSERT_GL_NO_ERROR(); GLVertexArray vertexArray; GLBuffer vertexBuffer; GLBuffer indexBuffer; initUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions, sizeof(kLoopPositions), indices, sizeof(indices)); GLBuffer indirectBuffer; initIndirectBuffer(indirectBuffer, firstIndex); glEnable(GL_BLEND); setVertexAttribs(nullptr); glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f); glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); setVertexAttribs(kStripPositions); glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f); glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices); ASSERT_GL_NO_ERROR(); checkPixels(); } // Test that one indirect line-loop followed by one non-line-loop draw that share the same index // buffer works. TEST_P(LineLoopIndirectTest, IndirectAndElementDrawsShareIndexBuffer) { // http://anglebug.com/42264370 ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm()); // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader. // http://anglebug.com/40096699 ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan()); // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks. ignoreD3D11SDKLayersWarnings(); GLuint firstIndex = 10; static const GLubyte indices[] = {0, 6, 9, 8, 7, 6, 0, 0, 9, 1, 2, 3, 4, 1, 0}; static const GLfloat loopPositions[] = {0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f}; glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgram); ASSERT_GL_NO_ERROR(); GLVertexArray vertexArray; GLBuffer vertexBuffer; GLBuffer indexBuffer; initUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, loopPositions, sizeof(loopPositions), indices, sizeof(indices)); GLBuffer indirectBuffer; initIndirectBuffer(indirectBuffer, firstIndex); glEnable(GL_BLEND); setVertexAttribs(nullptr); glUniform4f(mColorLocation, 1.0f, 0.0f, 1.0f, 1.0f); glViewport(0, 0, getWindowWidth() / 2, getWindowHeight()); glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_BYTE, nullptr); ASSERT_GL_NO_ERROR(); glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight()); glUniform4f(mColorLocation, 0.0, 1.0, 1.0, 1.0); glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, reinterpret_cast(1)); ASSERT_GL_NO_ERROR(); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); // Check pixels. std::vector pixels(getWindowWidth() * getWindowHeight() * 4); glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); ASSERT_GL_NO_ERROR(); for (int y = 0; y < getWindowHeight(); y++) { for (int x = 0; x < getWindowWidth() / 2; x++) { const GLubyte *pixel = &pixels[0] + ((y * getWindowWidth() + x) * 4); EXPECT_TRUE(pixel[0] == pixel[2]) << "Failed at " << x << ", " << y << std::endl; EXPECT_TRUE(pixel[1] == 0) << "Failed at " << x << ", " << y << std::endl; ASSERT_EQ(pixel[3], 255) << "Failed at " << x << ", " << y << std::endl; } for (int x = getWindowWidth() / 2; x < getWindowWidth(); x++) { const GLubyte *pixel = &pixels[0] + ((y * getWindowWidth() + x) * 4); EXPECT_TRUE(pixel[0] == 0) << "Failed at " << x << ", " << y << std::endl; EXPECT_TRUE(pixel[1] == pixel[2]) << "Failed at " << x << ", " << y << std::endl; ASSERT_EQ(pixel[3], 255) << "Failed at " << x << ", " << y << std::endl; } } } ANGLE_INSTANTIATE_TEST_ES2(LineLoopTest); ANGLE_INSTANTIATE_TEST_ES3(LineLoopTestES3); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LineLoopPrimitiveRestartTest); ANGLE_INSTANTIATE_TEST_ES3_AND( LineLoopPrimitiveRestartTest, ES3_METAL().enable(Feature::ForceBufferGPUStorage), ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass)); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LineLoopIndirectTest); ANGLE_INSTANTIATE_TEST_ES31(LineLoopIndirectTest);