• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "test_utils/gl_raii.h"
11 #include "util/test_utils.h"
12 
13 using namespace angle;
14 
15 class IndexBufferOffsetTest : public ANGLETest
16 {
17   protected:
IndexBufferOffsetTest()18     IndexBufferOffsetTest()
19     {
20         setWindowWidth(128);
21         setWindowHeight(128);
22         setConfigRedBits(8);
23         setConfigGreenBits(8);
24         setConfigBlueBits(8);
25         setConfigAlphaBits(8);
26     }
27 
testSetUp()28     void testSetUp() override
29     {
30         constexpr char kVS[] =
31             R"(precision highp float;
32             attribute vec2 position;
33 
34             void main()
35             {
36                 gl_Position = vec4(position, 0.0, 1.0);
37             })";
38 
39         constexpr char kFS[] =
40             R"(precision highp float;
41             uniform vec4 color;
42 
43             void main()
44             {
45                 gl_FragColor = color;
46             })";
47 
48         mProgram = CompileProgram(kVS, kFS);
49         ASSERT_NE(0u, mProgram);
50 
51         mColorUniformLocation      = glGetUniformLocation(mProgram, "color");
52         mPositionAttributeLocation = glGetAttribLocation(mProgram, "position");
53 
54         const GLfloat vertices[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
55         glGenBuffers(1, &mVertexBuffer);
56         glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
57         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_STATIC_DRAW);
58 
59         glGenBuffers(1, &mIndexBuffer);
60         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
61     }
62 
testTearDown()63     void testTearDown() override
64     {
65         glDeleteBuffers(1, &mVertexBuffer);
66         glDeleteBuffers(1, &mIndexBuffer);
67         glDeleteProgram(mProgram);
68     }
69 
preTestUpdateBuffer(GLuint framebuffer,GLuint texture,GLuint buffer,GLsizei size)70     void preTestUpdateBuffer(GLuint framebuffer, GLuint texture, GLuint buffer, GLsizei size)
71     {
72         GLsizei uboSize = std::max(size, 16);
73         const std::vector<uint32_t> initialData((uboSize + 3) / 4, 0x1234567u);
74 
75         glBindTexture(GL_TEXTURE_2D, texture);
76         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
77 
78         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
79         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
80                                0);
81 
82         glBindBuffer(GL_UNIFORM_BUFFER, buffer);
83         glBufferData(GL_UNIFORM_BUFFER, uboSize, initialData.data(), GL_DYNAMIC_DRAW);
84         glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
85 
86         constexpr char kVerifyUBO[] = R"(#version 300 es
87 precision mediump float;
88 uniform block {
89     uint data;
90 } ubo;
91 out vec4 colorOut;
92 void main()
93 {
94     if (ubo.data == 0x1234567u)
95         colorOut = vec4(0, 1.0, 0, 1.0);
96     else
97         colorOut = vec4(1.0, 0, 0, 1.0);
98 })";
99 
100         ANGLE_GL_PROGRAM(verifyUbo, essl3_shaders::vs::Simple(), kVerifyUBO);
101 
102         glDisable(GL_BLEND);
103         drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);
104 
105         EXPECT_GL_NO_ERROR();
106 
107         glBindFramebuffer(GL_FRAMEBUFFER, 0);
108     }
109 
runTest(GLenum type,int typeWidth,void * indexDataIn,bool smallUpdates,bool useBuffersAsUboFirst)110     void runTest(GLenum type,
111                  int typeWidth,
112                  void *indexDataIn,
113                  bool smallUpdates,
114                  bool useBuffersAsUboFirst)
115     {
116         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
117         glClear(GL_COLOR_BUFFER_BIT);
118 
119         size_t indexDataWidth = 6 * typeWidth;
120 
121         std::vector<GLubyte> indexData(6 * 3 * sizeof(GLuint), 0);
122         memcpy(indexData.data() + indexDataWidth, indexDataIn, indexDataWidth);
123 
124         GLFramebuffer elementUpdateFbo;
125         GLTexture elementUpdateTex;
126 
127         if (useBuffersAsUboFirst)
128         {
129             preTestUpdateBuffer(elementUpdateFbo, elementUpdateTex, mIndexBuffer,
130                                 3 * indexDataWidth);
131         }
132         else
133         {
134             glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * indexDataWidth, nullptr, GL_DYNAMIC_DRAW);
135         }
136 
137         if (smallUpdates)
138         {
139             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexDataWidth, indexData.data());
140             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexDataWidth,
141                             indexData.data() + indexDataWidth);
142             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2 * indexDataWidth, indexDataWidth,
143                             indexData.data() + 2 * indexDataWidth);
144         }
145         else
146         {
147             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 3 * indexDataWidth, indexData.data());
148         }
149 
150         glUseProgram(mProgram);
151 
152         glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
153         glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
154         glEnableVertexAttribArray(mPositionAttributeLocation);
155 
156         glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
157 
158         for (int i = 0; i < 16; i++)
159         {
160             glDrawElements(GL_TRIANGLES, 6, type, reinterpret_cast<void *>(indexDataWidth));
161             EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::red);
162         }
163 
164         if (smallUpdates)
165         {
166             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexDataWidth,
167                             indexData.data());
168             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2 * indexDataWidth, indexDataWidth,
169                             indexData.data() + indexDataWidth);
170         }
171         else
172         {
173             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, 2 * indexDataWidth,
174                             indexData.data());
175         }
176 
177         glUniform4f(mColorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
178         glDrawElements(GL_TRIANGLES, 6, type, reinterpret_cast<void *>(indexDataWidth * 2));
179         EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::green);
180 
181         if (useBuffersAsUboFirst)
182         {
183             glBindFramebuffer(GL_FRAMEBUFFER, elementUpdateFbo);
184             EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
185         }
186 
187         EXPECT_GL_NO_ERROR();
188         swapBuffers();
189     }
190 
191     GLuint mProgram;
192     GLint mColorUniformLocation;
193     GLint mPositionAttributeLocation;
194     GLuint mVertexBuffer;
195     GLuint mIndexBuffer;
196 };
197 
198 class IndexBufferOffsetTestES3 : public IndexBufferOffsetTest
199 {};
200 
201 // Test using an offset for an UInt8 index buffer
TEST_P(IndexBufferOffsetTest,UInt8Index)202 TEST_P(IndexBufferOffsetTest, UInt8Index)
203 {
204     GLubyte indexData[] = {0, 1, 2, 1, 2, 3};
205     runTest(GL_UNSIGNED_BYTE, 1, indexData, false, false);
206 }
207 
208 // Test using an offset for an UInt16 index buffer
TEST_P(IndexBufferOffsetTest,UInt16Index)209 TEST_P(IndexBufferOffsetTest, UInt16Index)
210 {
211     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
212     runTest(GL_UNSIGNED_SHORT, 2, indexData, false, false);
213 }
214 
215 // Test using an offset for an UInt32 index buffer
TEST_P(IndexBufferOffsetTest,UInt32Index)216 TEST_P(IndexBufferOffsetTest, UInt32Index)
217 {
218     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
219                        !IsGLExtensionEnabled("GL_OES_element_index_uint"));
220 
221     GLuint indexData[] = {0, 1, 2, 1, 2, 3};
222     runTest(GL_UNSIGNED_INT, 4, indexData, false, false);
223 }
224 
225 // Test using an offset for an UInt8 index buffer with small buffer updates
TEST_P(IndexBufferOffsetTest,UInt8IndexSmallUpdates)226 TEST_P(IndexBufferOffsetTest, UInt8IndexSmallUpdates)
227 {
228     GLubyte indexData[] = {0, 1, 2, 1, 2, 3};
229     runTest(GL_UNSIGNED_BYTE, 1, indexData, true, false);
230 }
231 
232 // Test using an offset for an UInt16 index buffer with small buffer updates
TEST_P(IndexBufferOffsetTest,UInt16IndexSmallUpdates)233 TEST_P(IndexBufferOffsetTest, UInt16IndexSmallUpdates)
234 {
235     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
236     runTest(GL_UNSIGNED_SHORT, 2, indexData, true, false);
237 }
238 
239 // Test using an offset for an UInt32 index buffer with small buffer updates
TEST_P(IndexBufferOffsetTest,UInt32IndexSmallUpdates)240 TEST_P(IndexBufferOffsetTest, UInt32IndexSmallUpdates)
241 {
242     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
243                        !IsGLExtensionEnabled("GL_OES_element_index_uint"));
244 
245     GLuint indexData[] = {0, 1, 2, 1, 2, 3};
246     runTest(GL_UNSIGNED_INT, 4, indexData, true, false);
247 }
248 
249 // Test using an offset for an UInt8 index buffer after uploading data to a buffer that is in use
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt8Index)250 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt8Index)
251 {
252     // http://anglebug.com/5950
253     ANGLE_SKIP_TEST_IF(IsAMD() && IsVulkan() && IsWindows());
254 
255     // http://anglebug.com/5957
256     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
257 
258     GLubyte indexData[] = {0, 1, 2, 1, 2, 3};
259     runTest(GL_UNSIGNED_BYTE, 1, indexData, false, true);
260 }
261 
262 // Test using an offset for an UInt16 index buffer after uploading data to a buffer that is in use
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt16Index)263 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt16Index)
264 {
265     // http://anglebug.com/5957
266     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
267 
268     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
269     runTest(GL_UNSIGNED_SHORT, 2, indexData, false, true);
270 }
271 
272 // Test using an offset for an UInt32 index buffer after uploading data to a buffer that is in use
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt32Index)273 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt32Index)
274 {
275     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
276                        !IsGLExtensionEnabled("GL_OES_element_index_uint"));
277 
278     // http://anglebug.com/5957
279     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
280 
281     GLuint indexData[] = {0, 1, 2, 1, 2, 3};
282     runTest(GL_UNSIGNED_INT, 4, indexData, false, true);
283 }
284 
285 // Test using an offset for an UInt8 index buffer after uploading data to a buffer that is in use,
286 // with small buffer updates
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt8IndexSmallUpdates)287 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt8IndexSmallUpdates)
288 {
289     // http://anglebug.com/5950
290     ANGLE_SKIP_TEST_IF(IsAMD() && IsVulkan() && IsWindows());
291 
292     // http://anglebug.com/5957
293     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
294 
295     GLubyte indexData[] = {0, 1, 2, 1, 2, 3};
296     runTest(GL_UNSIGNED_BYTE, 1, indexData, true, true);
297 }
298 
299 // Test using an offset for an UInt16 index buffer after uploading data to a buffer that is in use,
300 // with small buffer updates
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt16IndexSmallUpdates)301 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt16IndexSmallUpdates)
302 {
303     // http://anglebug.com/5957
304     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
305 
306     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
307     runTest(GL_UNSIGNED_SHORT, 2, indexData, true, true);
308 }
309 
310 // Test using an offset for an UInt32 index buffer after uploading data to a buffer that is in use,
311 // with small buffer updates
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt32IndexSmallUpdates)312 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt32IndexSmallUpdates)
313 {
314     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
315                        !IsGLExtensionEnabled("GL_OES_element_index_uint"));
316 
317     // http://anglebug.com/5957
318     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
319 
320     GLuint indexData[] = {0, 1, 2, 1, 2, 3};
321     runTest(GL_UNSIGNED_INT, 4, indexData, true, true);
322 }
323 
324 // Uses index buffer offset and 2 drawElement calls one of the other, makes sure the second
325 // drawElement call will use the correct offset.
TEST_P(IndexBufferOffsetTest,DrawAtDifferentOffsets)326 TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsets)
327 {
328     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
329     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
330     glClear(GL_COLOR_BUFFER_BIT);
331 
332     size_t indexDataWidth = 6 * sizeof(GLushort);
333 
334     glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexData, GL_DYNAMIC_DRAW);
335     glUseProgram(mProgram);
336 
337     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
338     glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
339     glEnableVertexAttribArray(mPositionAttributeLocation);
340 
341     glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
342 
343     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
344     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT,
345                    reinterpret_cast<void *>(indexDataWidth / 2));
346 
347     // Check the upper left triangle
348     EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
349 
350     // Check the down right triangle
351     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
352 
353     EXPECT_GL_NO_ERROR();
354 }
355 
356 // Uses index buffer offset and 2 drawElement calls one of the other, one has aligned
357 // offset and one doesn't
TEST_P(IndexBufferOffsetTest,DrawAtDifferentOffsetAlignments)358 TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsetAlignments)
359 {
360     GLubyte indexData8[]   = {0, 1, 0, 1, 2, 3};
361     GLushort indexData16[] = {0, 1, 2, 1, 2, 3};
362     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
363     glClear(GL_COLOR_BUFFER_BIT);
364 
365     size_t indexDataWidth16 = 6 * sizeof(GLushort);
366 
367     GLuint buffer[2];
368     glGenBuffers(2, buffer);
369 
370     glUseProgram(mProgram);
371     glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
372 
373     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
374     glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
375     glEnableVertexAttribArray(mPositionAttributeLocation);
376 
377     // 8 bit index with aligned offset
378     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[0]);
379     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData8), indexData8, GL_DYNAMIC_DRAW);
380 
381     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(2));
382 
383     // 16 bits index buffer, which unaligned offset
384     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[1]);
385     glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth16, indexData16, GL_DYNAMIC_DRAW);
386 
387     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT,
388                    reinterpret_cast<void *>(indexDataWidth16 / 2));
389 
390     // Check the upper left triangle
391     EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
392 
393     // Check the down right triangle
394     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
395 
396     EXPECT_GL_NO_ERROR();
397 }
398 
399 // Uses index buffer offset and 2 drawElement calls one of the other with different counts,
400 // makes sure the second drawElement call will have its data available.
TEST_P(IndexBufferOffsetTest,DrawWithDifferentCountsSameOffset)401 TEST_P(IndexBufferOffsetTest, DrawWithDifferentCountsSameOffset)
402 {
403     GLubyte indexData[] = {99, 0, 1, 2, 1, 2, 3};
404     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
405     glClear(GL_COLOR_BUFFER_BIT);
406 
407     size_t indexDataWidth = 7 * sizeof(GLubyte);
408 
409     glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexData, GL_DYNAMIC_DRAW);
410     glUseProgram(mProgram);
411 
412     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
413     glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
414     glEnableVertexAttribArray(mPositionAttributeLocation);
415 
416     glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
417 
418     // The first draw draws the first triangle, and the second draws a quad.
419     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(1));
420     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(1));
421 
422     // Check the upper left triangle
423     EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
424 
425     // Check the down right triangle
426     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
427 
428     EXPECT_GL_NO_ERROR();
429 }
430 
431 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(IndexBufferOffsetTest);
432 
433 ANGLE_INSTANTIATE_TEST_ES3(IndexBufferOffsetTestES3);
434