blob: 415c41165be5f3f198ac181031d4a5d47b06e992 [file] [log] [blame]
//
// 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.
//
// DrawElementsTest:
// Tests for indexed draws.
//
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle;
namespace
{
class DrawElementsTest : public ANGLETest<>
{
protected:
DrawElementsTest() : mProgram(0u)
{
setWindowWidth(64);
setWindowHeight(64);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
~DrawElementsTest()
{
for (GLuint indexBuffer : mIndexBuffers)
{
if (indexBuffer != 0)
{
glDeleteBuffers(1, &indexBuffer);
}
}
for (GLuint vertexArray : mVertexArrays)
{
if (vertexArray != 0)
{
glDeleteVertexArrays(1, &vertexArray);
}
}
for (GLuint vertexBuffer : mVertexBuffers)
{
if (vertexBuffer != 0)
{
glDeleteBuffers(1, &vertexBuffer);
}
}
if (mProgram != 0u)
{
glDeleteProgram(mProgram);
}
}
std::vector<GLuint> mIndexBuffers;
std::vector<GLuint> mVertexArrays;
std::vector<GLuint> mVertexBuffers;
GLuint mProgram;
};
class WebGLDrawElementsTest : public DrawElementsTest
{
public:
WebGLDrawElementsTest() { setWebGLCompatibilityEnabled(true); }
};
// Test no error is generated when using client-side arrays, indices = nullptr and count = 0
TEST_P(DrawElementsTest, ClientSideNullptrArrayZeroCount)
{
constexpr char kVS[] =
"attribute vec3 a_pos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(a_pos, 1.0);\n"
"}\n";
ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Blue());
GLint posLocation = glGetAttribLocation(program, "a_pos");
ASSERT_NE(-1, posLocation);
glUseProgram(program);
const auto &vertices = GetQuadVertices();
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLocation);
ASSERT_GL_NO_ERROR();
// "If drawElements is called with a count greater than zero, and no WebGLBuffer is bound to the
// ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated."
glDrawElements(GL_TRIANGLES, 1, GL_UNSIGNED_BYTE, nullptr);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
// count == 0 so it's fine to have no element array buffer bound.
glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_BYTE, nullptr);
ASSERT_GL_NO_ERROR();
}
// Test uploading part of an index buffer after deleting a vertex array
// previously used for DrawElements.
TEST_P(DrawElementsTest, DeleteVertexArrayAndUploadIndex)
{
const auto &vertices = GetIndexedQuadVertices();
const auto &indices = GetQuadIndices();
ANGLE_GL_PROGRAM(programDrawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
glUseProgram(programDrawRed);
GLint posLocation = glGetAttribLocation(programDrawRed, essl3_shaders::PositionAttrib());
ASSERT_NE(-1, posLocation);
GLuint vertexArray;
glGenVertexArrays(1, &vertexArray);
glBindVertexArray(vertexArray);
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLocation);
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
GL_STATIC_DRAW);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
glDeleteVertexArrays(1, &vertexArray);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
// Could crash here if the observer binding from the vertex array doesn't get
// removed on vertex array destruction.
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices[0]) * 3, indices.data());
ASSERT_GL_NO_ERROR();
}
// Test VAO switch is handling cached element array buffer properly along with line loop mode
// switch.
TEST_P(DrawElementsTest, LineLoopTriangles)
{
const auto &vertices = GetIndexedQuadVertices();
constexpr std::array<GLuint, 6> indices = {{0, 1, 2, 0, 2, 3}};
ANGLE_GL_PROGRAM(programDrawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
ANGLE_GL_PROGRAM(programDrawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue());
glUseProgram(programDrawRed);
GLint posLocation = glGetAttribLocation(programDrawRed, essl3_shaders::PositionAttrib());
ASSERT_NE(-1, posLocation);
GLVertexArray vertexArray[2];
GLBuffer vertexBuffer[2];
glBindVertexArray(vertexArray[0]);
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
GL_STATIC_DRAW);
for (int i = 0; i < 2; i++)
{
glBindVertexArray(vertexArray[i]);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLocation);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
}
// First draw with VAO0 and line loop mode
glBindVertexArray(vertexArray[0]);
glDrawArrays(GL_LINE_LOOP, 0, 4);
// Switch to VAO1 and draw with triangle mode.
glBindVertexArray(vertexArray[1]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
// Switch back to VAO0 and draw with triangle mode.
glUseProgram(programDrawBlue);
glBindVertexArray(vertexArray[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() - 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::blue);
ASSERT_GL_NO_ERROR();
}
// Regression test for using two VAOs, one to draw only GL_LINE_LOOPs, and
// another to draw indexed triangles.
TEST_P(DrawElementsTest, LineLoopTriangles2)
{
const auto &vertices = GetIndexedQuadVertices();
constexpr std::array<GLuint, 6> indices = {{0, 1, 2, 0, 2, 3}};
ANGLE_GL_PROGRAM(programDrawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
glUseProgram(programDrawRed);
GLint posLocation = glGetAttribLocation(programDrawRed, essl3_shaders::PositionAttrib());
ASSERT_NE(-1, posLocation);
GLVertexArray vertexArray[2];
GLBuffer vertexBuffer[2];
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
GL_STATIC_DRAW);
for (int i = 0; i < 2; i++)
{
glBindVertexArray(vertexArray[i]);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLocation);
if (i != 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
}
// First draw with VAO0 and line loop mode
glBindVertexArray(vertexArray[0]);
glDrawArrays(GL_LINE_LOOP, 0, 4);
// Switch to VAO1 and draw some indexed triangles
glBindVertexArray(vertexArray[1]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
// Switch back to VAO0 and do another line loop
glBindVertexArray(vertexArray[0]);
// Would crash if the index buffer dirty bit got errantly set on VAO0.
glDrawArrays(GL_LINE_LOOP, 0, 4);
ASSERT_GL_NO_ERROR();
}
// Test a state desync that can occur when using a streaming index buffer in GL in concert with
// deleting the applied index buffer.
TEST_P(DrawElementsTest, DeletingAfterStreamingIndexes)
{
// Init program
constexpr char kVS[] =
"attribute vec2 position;\n"
"attribute vec2 testFlag;\n"
"varying vec2 v_data;\n"
"void main() {\n"
" gl_Position = vec4(position, 0, 1);\n"
" v_data = testFlag;\n"
"}";
constexpr char kFS[] =
"varying highp vec2 v_data;\n"
"void main() {\n"
" gl_FragColor = vec4(v_data, 0, 1);\n"
"}";
mProgram = CompileProgram(kVS, kFS);
ASSERT_NE(0u, mProgram);
glUseProgram(mProgram);
GLint positionLocation = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, positionLocation);
GLint testFlagLocation = glGetAttribLocation(mProgram, "testFlag");
ASSERT_NE(-1, testFlagLocation);
mIndexBuffers.resize(3u);
glGenBuffers(3, &mIndexBuffers[0]);
mVertexArrays.resize(2);
glGenVertexArrays(2, &mVertexArrays[0]);
mVertexBuffers.resize(2);
glGenBuffers(2, &mVertexBuffers[0]);
std::vector<GLuint> indexData[2];
indexData[0].push_back(0);
indexData[0].push_back(1);
indexData[0].push_back(2);
indexData[0].push_back(2);
indexData[0].push_back(3);
indexData[0].push_back(0);
indexData[1] = indexData[0];
for (GLuint &item : indexData[1])
{
item += 4u;
}
std::vector<GLfloat> positionData = {// quad verts
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
// Repeat position data
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
std::vector<GLfloat> testFlagData = {// red
1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
// green
0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[0].size(), &indexData[0][0],
GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[0].size(), &indexData[0][0],
GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[1].size(), &indexData[1][0],
GL_STATIC_DRAW);
// Initialize first vertex array with second index buffer
glBindVertexArray(mVertexArrays[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[1]);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0],
GL_STATIC_DRAW);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
glEnableVertexAttribArray(positionLocation);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * testFlagData.size(), &testFlagData[0],
GL_STATIC_DRAW);
glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
glEnableVertexAttribArray(testFlagLocation);
// Initialize second vertex array with first index buffer
glBindVertexArray(mVertexArrays[1]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
glEnableVertexAttribArray(positionLocation);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
glEnableVertexAttribArray(testFlagLocation);
ASSERT_GL_NO_ERROR();
glBindVertexArray(mVertexArrays[0]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
glBindVertexArray(mVertexArrays[1]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glBindVertexArray(mVertexArrays[0]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Trigger the bug here.
glDeleteBuffers(1, &mIndexBuffers[2]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
ASSERT_GL_NO_ERROR();
}
// Verify that detaching shaders after linking doesn't break draw calls
TEST_P(DrawElementsTest, DrawWithDetachedShaders)
{
const auto &vertices = GetIndexedQuadVertices();
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
GLBuffer indexBuffer;
const auto &indices = GetQuadIndices();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, essl3_shaders::fs::Red());
ASSERT_NE(0u, vertexShader);
ASSERT_NE(0u, fragmentShader);
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
EXPECT_EQ(GL_TRUE, linkStatus);
glDetachShader(program, vertexShader);
glDetachShader(program, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
ASSERT_GL_NO_ERROR();
glUseProgram(program);
GLint posLocation = glGetAttribLocation(program, essl3_shaders::PositionAttrib());
ASSERT_NE(-1, posLocation);
GLVertexArray vertexArray;
glBindVertexArray(vertexArray);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLocation);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
ASSERT_GL_NO_ERROR();
glDeleteProgram(program);
ASSERT_GL_NO_ERROR();
}
// Test drawing to part of the indices in an index buffer, and then all of them.
TEST_P(DrawElementsTest, PartOfIndexBufferThenAll)
{
// Init program
constexpr char kVS[] =
"attribute vec2 position;\n"
"attribute vec2 testFlag;\n"
"varying vec2 v_data;\n"
"void main() {\n"
" gl_Position = vec4(position, 0, 1);\n"
" v_data = testFlag;\n"
"}";
constexpr char kFS[] =
"varying highp vec2 v_data;\n"
"void main() {\n"
" gl_FragColor = vec4(v_data, 0, 1);\n"
"}";
mProgram = CompileProgram(kVS, kFS);
ASSERT_NE(0u, mProgram);
glUseProgram(mProgram);
GLint positionLocation = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, positionLocation);
GLint testFlagLocation = glGetAttribLocation(mProgram, "testFlag");
ASSERT_NE(-1, testFlagLocation);
mIndexBuffers.resize(1);
glGenBuffers(1, &mIndexBuffers[0]);
mVertexArrays.resize(1);
glGenVertexArrays(1, &mVertexArrays[0]);
mVertexBuffers.resize(2);
glGenBuffers(2, &mVertexBuffers[0]);
std::vector<GLubyte> indexData[2];
indexData[0].push_back(0);
indexData[0].push_back(1);
indexData[0].push_back(2);
indexData[0].push_back(2);
indexData[0].push_back(3);
indexData[0].push_back(0);
indexData[0].push_back(4);
indexData[0].push_back(5);
indexData[0].push_back(6);
indexData[0].push_back(6);
indexData[0].push_back(7);
indexData[0].push_back(4);
// Make a copy:
indexData[1] = indexData[0];
std::vector<GLfloat> positionData = {// quad verts
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
// Repeat position data
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
std::vector<GLfloat> testFlagData = {// red
1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
// green
0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * indexData[0].size(), &indexData[0][0],
GL_STATIC_DRAW);
glBindVertexArray(mVertexArrays[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0],
GL_STATIC_DRAW);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
glEnableVertexAttribArray(positionLocation);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * testFlagData.size(), &testFlagData[0],
GL_STATIC_DRAW);
glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
glEnableVertexAttribArray(testFlagLocation);
ASSERT_GL_NO_ERROR();
// Draw with just the second set of 6 items, then first 6, and then the entire index buffer
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(6));
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_BYTE, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Reload the buffer again with a copy of the same data
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * indexData[1].size(), &indexData[1][0],
GL_STATIC_DRAW);
// Draw with just the first 6 indices, and then with the entire index buffer
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_BYTE, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Reload the buffer again with a copy of the same data
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * indexData[0].size(), &indexData[0][0],
GL_STATIC_DRAW);
// This time, do not check color between draws (which causes a flush):
// Draw with just the second set of 6 items, then first 6, and then the entire index buffer
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(6));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_BYTE, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
ASSERT_GL_NO_ERROR();
}
// Test that glDrawElements call with different index buffer offsets work as expected
TEST_P(DrawElementsTest, DrawElementsWithDifferentIndexBufferOffsets)
{
const std::array<Vector3, 4> &vertices = GetIndexedQuadVertices();
const std::array<GLushort, 6> &indices = GetQuadIndices();
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
ANGLE_GL_PROGRAM(programDrawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
ANGLE_GL_PROGRAM(programDrawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green());
ANGLE_GL_PROGRAM(programDrawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue());
glUseProgram(programDrawRed);
GLuint vertexArray;
glGenVertexArrays(1, &vertexArray);
glBindVertexArray(vertexArray);
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
GLint posLocation = glGetAttribLocation(programDrawRed, essl3_shaders::PositionAttrib());
ASSERT_NE(-1, posLocation);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLocation);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Draw both triangles of quad
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices.data());
EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 2, GLColor::red);
glUseProgram(programDrawGreen);
GLuint vertexArray1;
glGenVertexArrays(1, &vertexArray1);
glBindVertexArray(vertexArray1);
GLBuffer vertexBuffer1;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer1);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
posLocation = glGetAttribLocation(programDrawGreen, essl3_shaders::PositionAttrib());
ASSERT_NE(-1, posLocation);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLocation);
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
GL_DYNAMIC_DRAW);
// Draw right triangle of quad
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, reinterpret_cast<const void *>(6));
EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 2, GLColor::green);
glUseProgram(programDrawBlue);
glBindVertexArray(vertexArray);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
posLocation = glGetAttribLocation(programDrawBlue, essl3_shaders::PositionAttrib());
ASSERT_NE(-1, posLocation);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLocation);
// Draw both triangles of quad
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices.data());
EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 2, GLColor::blue);
glDeleteVertexArrays(1, &vertexArray);
glDeleteVertexArrays(1, &vertexArray1);
ASSERT_GL_NO_ERROR();
}
// Test that the offset in the index buffer is forced to be a multiple of the element size
TEST_P(WebGLDrawElementsTest, DrawElementsTypeAlignment)
{
constexpr char kVS[] =
"attribute vec3 a_pos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(a_pos, 1.0);\n"
"}\n";
ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Blue());
GLint posLocation = glGetAttribLocation(program, "a_pos");
ASSERT_NE(-1, posLocation);
glUseProgram(program);
const auto &vertices = GetQuadVertices();
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posLocation);
GLBuffer indexBuffer;
const GLubyte indices1[] = {0, 0, 0, 0, 0, 0};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, nullptr);
ASSERT_GL_NO_ERROR();
const GLushort indices2[] = {0, 0, 0, 0, 0, 0};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, reinterpret_cast<const void *>(1));
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawElementsTest);
ANGLE_INSTANTIATE_TEST_ES3(DrawElementsTest);
ANGLE_INSTANTIATE_TEST_ES2(WebGLDrawElementsTest);
} // namespace