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 // DrawElementsTest:
7 //   Tests for indexed draws.
8 //
9 
10 #include "test_utils/ANGLETest.h"
11 
12 using namespace angle;
13 
14 namespace
15 {
16 
17 class DrawElementsTest : public ANGLETest
18 {
19   protected:
DrawElementsTest()20     DrawElementsTest() : mProgram(0u)
21     {
22         setWindowWidth(64);
23         setWindowHeight(64);
24         setConfigRedBits(8);
25         setConfigGreenBits(8);
26     }
27 
~DrawElementsTest()28     ~DrawElementsTest()
29     {
30         for (GLuint indexBuffer : mIndexBuffers)
31         {
32             if (indexBuffer != 0)
33             {
34                 glDeleteBuffers(1, &indexBuffer);
35             }
36         }
37 
38         for (GLuint vertexArray : mVertexArrays)
39         {
40             if (vertexArray != 0)
41             {
42                 glDeleteVertexArrays(1, &vertexArray);
43             }
44         }
45 
46         for (GLuint vertexBuffer : mVertexBuffers)
47         {
48             if (vertexBuffer != 0)
49             {
50                 glDeleteBuffers(1, &vertexBuffer);
51             }
52         }
53 
54         if (mProgram != 0u)
55         {
56             glDeleteProgram(mProgram);
57         }
58     }
59 
60     std::vector<GLuint> mIndexBuffers;
61     std::vector<GLuint> mVertexArrays;
62     std::vector<GLuint> mVertexBuffers;
63     GLuint mProgram;
64 };
65 
66 // Test a state desync that can occur when using a streaming index buffer in GL in concert with
67 // deleting the applied index buffer.
TEST_P(DrawElementsTest,DeletingAfterStreamingIndexes)68 TEST_P(DrawElementsTest, DeletingAfterStreamingIndexes)
69 {
70     // Init program
71     const std::string &vertexShader =
72         "attribute vec2 position;\n"
73         "attribute vec2 testFlag;\n"
74         "varying vec2 v_data;\n"
75         "void main() {\n"
76         "  gl_Position = vec4(position, 0, 1);\n"
77         "  v_data = testFlag;\n"
78         "}";
79 
80     const std::string &fragmentShader =
81         "varying highp vec2 v_data;\n"
82         "void main() {\n"
83         "  gl_FragColor = vec4(v_data, 0, 1);\n"
84         "}";
85 
86     mProgram = CompileProgram(vertexShader, fragmentShader);
87     ASSERT_NE(0u, mProgram);
88     glUseProgram(mProgram);
89 
90     GLint positionLocation = glGetAttribLocation(mProgram, "position");
91     ASSERT_NE(-1, positionLocation);
92 
93     GLint testFlagLocation = glGetAttribLocation(mProgram, "testFlag");
94     ASSERT_NE(-1, testFlagLocation);
95 
96     mIndexBuffers.resize(3u);
97     glGenBuffers(3, &mIndexBuffers[0]);
98 
99     mVertexArrays.resize(2);
100     glGenVertexArrays(2, &mVertexArrays[0]);
101 
102     mVertexBuffers.resize(2);
103     glGenBuffers(2, &mVertexBuffers[0]);
104 
105     std::vector<GLuint> indexData[2];
106     indexData[0].push_back(0);
107     indexData[0].push_back(1);
108     indexData[0].push_back(2);
109     indexData[0].push_back(2);
110     indexData[0].push_back(3);
111     indexData[0].push_back(0);
112 
113     indexData[1] = indexData[0];
114     for (GLuint &item : indexData[1])
115     {
116         item += 4u;
117     }
118 
119     std::vector<GLfloat> positionData;
120     // quad verts
121     positionData.push_back(-1.0f);
122     positionData.push_back(1.0f);
123     positionData.push_back(-1.0f);
124     positionData.push_back(-1.0f);
125     positionData.push_back(1.0f);
126     positionData.push_back(-1.0f);
127     positionData.push_back(1.0f);
128     positionData.push_back(1.0f);
129 
130     // Repeat position data
131     positionData.push_back(-1.0f);
132     positionData.push_back(1.0f);
133     positionData.push_back(-1.0f);
134     positionData.push_back(-1.0f);
135     positionData.push_back(1.0f);
136     positionData.push_back(-1.0f);
137     positionData.push_back(1.0f);
138     positionData.push_back(1.0f);
139 
140     std::vector<GLfloat> testFlagData;
141     // red
142     testFlagData.push_back(1.0f);
143     testFlagData.push_back(0.0f);
144     testFlagData.push_back(1.0f);
145     testFlagData.push_back(0.0f);
146     testFlagData.push_back(1.0f);
147     testFlagData.push_back(0.0f);
148     testFlagData.push_back(1.0f);
149     testFlagData.push_back(0.0f);
150 
151     // green
152     testFlagData.push_back(0.0f);
153     testFlagData.push_back(1.0f);
154     testFlagData.push_back(0.0f);
155     testFlagData.push_back(1.0f);
156     testFlagData.push_back(0.0f);
157     testFlagData.push_back(1.0f);
158     testFlagData.push_back(0.0f);
159     testFlagData.push_back(1.0f);
160 
161     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
162     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[0].size(), &indexData[0][0],
163                  GL_STATIC_DRAW);
164 
165     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[2]);
166     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[0].size(), &indexData[0][0],
167                  GL_STATIC_DRAW);
168 
169     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[1]);
170     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[1].size(), &indexData[1][0],
171                  GL_STATIC_DRAW);
172 
173     // Initialize first vertex array with second index buffer
174     glBindVertexArray(mVertexArrays[0]);
175 
176     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[1]);
177     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
178     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0],
179                  GL_STATIC_DRAW);
180     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
181     glEnableVertexAttribArray(positionLocation);
182 
183     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
184     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * testFlagData.size(), &testFlagData[0],
185                  GL_STATIC_DRAW);
186     glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
187     glEnableVertexAttribArray(testFlagLocation);
188 
189     // Initialize second vertex array with first index buffer
190     glBindVertexArray(mVertexArrays[1]);
191 
192     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
193 
194     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
195     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
196     glEnableVertexAttribArray(positionLocation);
197 
198     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
199     glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
200     glEnableVertexAttribArray(testFlagLocation);
201 
202     ASSERT_GL_NO_ERROR();
203 
204     glBindVertexArray(mVertexArrays[0]);
205     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
206     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
207 
208     glBindVertexArray(mVertexArrays[1]);
209     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
210     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
211 
212     glBindVertexArray(mVertexArrays[0]);
213     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
214     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
215 
216     // Trigger the bug here.
217     glDeleteBuffers(1, &mIndexBuffers[2]);
218 
219     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
220     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
221 
222     ASSERT_GL_NO_ERROR();
223 }
224 
225 ANGLE_INSTANTIATE_TEST(DrawElementsTest, ES3_OPENGL(), ES3_OPENGLES());
226 }
227