1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // IndexBufferOffsetTest.cpp: Test glDrawElements with an offset and an index buffer
8
9 #include "test_utils/ANGLETest.h"
10 #include "util/test_utils.h"
11
12 using namespace angle;
13
14 class IndexBufferOffsetTest : public ANGLETest
15 {
16 protected:
IndexBufferOffsetTest()17 IndexBufferOffsetTest()
18 {
19 setWindowWidth(128);
20 setWindowHeight(128);
21 setConfigRedBits(8);
22 setConfigGreenBits(8);
23 setConfigBlueBits(8);
24 setConfigAlphaBits(8);
25 }
26
testSetUp()27 void testSetUp() override
28 {
29 constexpr char kVS[] =
30 R"(precision highp float;
31 attribute vec2 position;
32
33 void main()
34 {
35 gl_Position = vec4(position, 0.0, 1.0);
36 })";
37
38 constexpr char kFS[] =
39 R"(precision highp float;
40 uniform vec4 color;
41
42 void main()
43 {
44 gl_FragColor = color;
45 })";
46
47 mProgram = CompileProgram(kVS, kFS);
48 ASSERT_NE(0u, mProgram);
49
50 mColorUniformLocation = glGetUniformLocation(mProgram, "color");
51 mPositionAttributeLocation = glGetAttribLocation(mProgram, "position");
52
53 const GLfloat vertices[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
54 glGenBuffers(1, &mVertexBuffer);
55 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
56 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_STATIC_DRAW);
57
58 glGenBuffers(1, &mIndexBuffer);
59 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
60 }
61
testTearDown()62 void testTearDown() override
63 {
64 glDeleteBuffers(1, &mVertexBuffer);
65 glDeleteBuffers(1, &mIndexBuffer);
66 glDeleteProgram(mProgram);
67 }
68
runTest(GLenum type,int typeWidth,void * indexData)69 void runTest(GLenum type, int typeWidth, void *indexData)
70 {
71 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
72 glClear(GL_COLOR_BUFFER_BIT);
73
74 GLuint nullIndexData[] = {0, 0, 0, 0, 0, 0};
75
76 size_t indexDataWidth = 6 * typeWidth;
77
78 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * indexDataWidth, nullptr, GL_DYNAMIC_DRAW);
79 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexDataWidth, nullIndexData);
80 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexDataWidth, indexData);
81 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2 * indexDataWidth, indexDataWidth, nullIndexData);
82
83 glUseProgram(mProgram);
84
85 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
86 glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
87 glEnableVertexAttribArray(mPositionAttributeLocation);
88
89 glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
90
91 for (int i = 0; i < 16; i++)
92 {
93 glDrawElements(GL_TRIANGLES, 6, type, reinterpret_cast<void *>(indexDataWidth));
94 EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::red);
95 }
96
97 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexDataWidth, nullIndexData);
98 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2 * indexDataWidth, indexDataWidth, indexData);
99
100 glUniform4f(mColorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
101 glDrawElements(GL_TRIANGLES, 6, type, reinterpret_cast<void *>(indexDataWidth * 2));
102 EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::green);
103
104 EXPECT_GL_NO_ERROR();
105 swapBuffers();
106 }
107
108 GLuint mProgram;
109 GLint mColorUniformLocation;
110 GLint mPositionAttributeLocation;
111 GLuint mVertexBuffer;
112 GLuint mIndexBuffer;
113 };
114
115 // Test using an offset for an UInt8 index buffer
TEST_P(IndexBufferOffsetTest,UInt8Index)116 TEST_P(IndexBufferOffsetTest, UInt8Index)
117 {
118 GLubyte indexData[] = {0, 1, 2, 1, 2, 3};
119 runTest(GL_UNSIGNED_BYTE, 1, indexData);
120 }
121
122 // Test using an offset for an UInt16 index buffer
TEST_P(IndexBufferOffsetTest,UInt16Index)123 TEST_P(IndexBufferOffsetTest, UInt16Index)
124 {
125 // TODO(jie.a.chen@intel.com): Re-enable the test once the driver fix is
126 // available in public release.
127 // http://anglebug.com/2663
128 ANGLE_SKIP_TEST_IF(IsIntel() && IsVulkan());
129
130 GLushort indexData[] = {0, 1, 2, 1, 2, 3};
131 runTest(GL_UNSIGNED_SHORT, 2, indexData);
132 }
133
134 // Test using an offset for an UInt32 index buffer
TEST_P(IndexBufferOffsetTest,UInt32Index)135 TEST_P(IndexBufferOffsetTest, UInt32Index)
136 {
137 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
138 !IsGLExtensionEnabled("GL_OES_element_index_uint"));
139
140 GLuint indexData[] = {0, 1, 2, 1, 2, 3};
141 runTest(GL_UNSIGNED_INT, 4, indexData);
142 }
143
144 // Uses index buffer offset and 2 drawElement calls one of the other, makes sure the second
145 // drawElement call will use the correct offset.
TEST_P(IndexBufferOffsetTest,DrawAtDifferentOffsets)146 TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsets)
147 {
148 GLushort indexData[] = {0, 1, 2, 1, 2, 3};
149 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
150 glClear(GL_COLOR_BUFFER_BIT);
151
152 size_t indexDataWidth = 6 * sizeof(GLushort);
153
154 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexData, GL_DYNAMIC_DRAW);
155 glUseProgram(mProgram);
156
157 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
158 glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
159 glEnableVertexAttribArray(mPositionAttributeLocation);
160
161 glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
162
163 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
164 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT,
165 reinterpret_cast<void *>(indexDataWidth / 2));
166
167 // Check the upper left triangle
168 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
169
170 // Check the down right triangle
171 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
172
173 EXPECT_GL_NO_ERROR();
174 }
175
176 // Uses index buffer offset and 2 drawElement calls one of the other, one has aligned
177 // offset and one doesn't
TEST_P(IndexBufferOffsetTest,DrawAtDifferentOffsetAlignments)178 TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsetAlignments)
179 {
180 GLubyte indexData8[] = {0, 1, 0, 1, 2, 3};
181 GLushort indexData16[] = {0, 1, 2, 1, 2, 3};
182 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
183 glClear(GL_COLOR_BUFFER_BIT);
184
185 size_t indexDataWidth16 = 6 * sizeof(GLushort);
186
187 GLuint buffer[2];
188 glGenBuffers(2, buffer);
189
190 glUseProgram(mProgram);
191 glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
192
193 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
194 glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
195 glEnableVertexAttribArray(mPositionAttributeLocation);
196
197 // 8 bit index with aligned offset
198 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[0]);
199 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData8), indexData8, GL_DYNAMIC_DRAW);
200
201 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(2));
202
203 // 16 bits index buffer, which unaligned offset
204 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[1]);
205 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth16, indexData16, GL_DYNAMIC_DRAW);
206
207 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT,
208 reinterpret_cast<void *>(indexDataWidth16 / 2));
209
210 // Check the upper left triangle
211 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
212
213 // Check the down right triangle
214 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
215
216 EXPECT_GL_NO_ERROR();
217 }
218
219 // Uses index buffer offset and 2 drawElement calls one of the other with different counts,
220 // makes sure the second drawElement call will have its data available.
TEST_P(IndexBufferOffsetTest,DrawWithDifferentCountsSameOffset)221 TEST_P(IndexBufferOffsetTest, DrawWithDifferentCountsSameOffset)
222 {
223 GLubyte indexData[] = {99, 0, 1, 2, 1, 2, 3};
224 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
225 glClear(GL_COLOR_BUFFER_BIT);
226
227 size_t indexDataWidth = 7 * sizeof(GLubyte);
228
229 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexData, GL_DYNAMIC_DRAW);
230 glUseProgram(mProgram);
231
232 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
233 glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
234 glEnableVertexAttribArray(mPositionAttributeLocation);
235
236 glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
237
238 // The first draw draws the first triangle, and the second draws a quad.
239 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(1));
240 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(1));
241
242 // Check the upper left triangle
243 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
244
245 // Check the down right triangle
246 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
247
248 EXPECT_GL_NO_ERROR();
249 }
250
251 ANGLE_INSTANTIATE_TEST(IndexBufferOffsetTest,
252 ES2_D3D9(),
253 ES2_D3D11(),
254 ES3_D3D11(),
255 ES2_METAL(),
256 ES2_OPENGL(),
257 ES3_OPENGL(),
258 ES2_OPENGLES(),
259 ES3_OPENGLES(),
260 ES2_VULKAN());
261