1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "GLSnapshotTestStateUtils.h"
16 #include "GLSnapshotTesting.h"
17 #include "OpenGLTestContext.h"
18 
19 #include <gtest/gtest.h>
20 
21 #include <algorithm>
22 
23 namespace gfxstream {
24 namespace gl {
25 namespace {
26 
27 enum class GlVertexAttribMode { SingleValue = 0, Array = 1, Buffer = 2 };
28 
29 struct GlVertexAttrib {
30     GlVertexAttribMode mode;
31     GlValues values;
32     GLint size;
33     GLenum type;
34     GLboolean normalized;
35     GLsizei stride;
36     GLboolean enabled;
37     GLvoid* pointer;
38     GLuint bufferBinding;
39 };
40 
41 static const GlVertexAttrib kGLES2DefaultVertexAttrib = {
42         .mode = GlVertexAttribMode::SingleValue,
43         .values = {.ints = {}, .floats = {0, 0, 0, 1}},
44         .size = 4,
45         .type = GL_FLOAT,
46         .normalized = GL_FALSE,
47         .stride = 0,
48         .enabled = GL_FALSE,
49         .pointer = nullptr,
50         .bufferBinding = 0};
51 
52 static const GlBufferData kTestAttachedBuffer = {.size = 16,
53                                                  .bytes = nullptr,
54                                                  .usage = GL_STATIC_DRAW};
55 
56 class SnapshotGlVertexAttributesTest
57     : public SnapshotSetValueTest<GlVertexAttrib> {
58 public:
stateCheck(GlVertexAttrib expected)59     virtual void stateCheck(GlVertexAttrib expected) override {
60         EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_ENABLED,
61                                         expected.enabled));
62     }
63 
stateChange()64     virtual void stateChange() override {
65         GlVertexAttrib changed = *m_changed_value;
66         if (changed.enabled) {
67             gl->glEnableVertexAttribArray(m_index);
68         } else {
69             gl->glDisableVertexAttribArray(m_index);
70         }
71         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
72     }
73 
selectIndex(GLuint index)74     void selectIndex(GLuint index) {
75         GLint maxAttribs;
76         gl->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
77         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
78         if (index >= maxAttribs) {
79             fprintf(stderr,
80                     "cannot select index %d: GL_MAX_VERTEX_ATTRIBS is %d.\n",
81                     index, maxAttribs);
82             return;
83         }
84         m_index = index;
85     }
86 
87 protected:
compareFloatParameter(GLenum paramName,GLfloat expected)88     testing::AssertionResult compareFloatParameter(GLenum paramName,
89                                                    GLfloat expected) {
90         std::vector<GLfloat> v = {expected};
91         return compareFloatParameter(paramName, v);
92     }
93 
compareFloatParameter(GLenum paramName,const std::vector<GLfloat> & expected)94     testing::AssertionResult compareFloatParameter(
95             GLenum paramName,
96             const std::vector<GLfloat>& expected) {
97         std::vector<GLfloat> values;
98         values.resize(std::max((GLuint)4, (GLuint)expected.size()));
99         gl->glGetVertexAttribfv(m_index, paramName, &(values[0]));
100         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
101         return compareVector<GLfloat>(
102                 expected, values,
103                 "float(s) for parameter " + describeGlEnum(paramName) +
104                         " of vertex attribute " + std::to_string(m_index));
105     }
106 
compareIntParameter(GLenum paramName,GLint expected)107     testing::AssertionResult compareIntParameter(GLenum paramName,
108                                                  GLint expected) {
109         std::vector<GLint> v = {expected};
110         return compareIntParameter(paramName, v);
111     }
112 
compareIntParameter(GLenum paramName,const std::vector<GLint> & expected)113     testing::AssertionResult compareIntParameter(
114             GLenum paramName,
115             const std::vector<GLint>& expected) {
116         std::vector<GLint> values;
117         values.resize(std::max((GLuint)4, (GLuint)expected.size()));
118         gl->glGetVertexAttribiv(m_index, paramName, &(values[0]));
119         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
120         return compareVector<GLint>(
121                 expected, values,
122                 "int(s) for parameter " + describeGlEnum(paramName) +
123                         " of vertex attribute " + std::to_string(m_index));
124     }
125 
126     GLuint m_index = 0;
127 };
128 
129 class SnapshotGlVertexAttribSingleValueTest
130     : public SnapshotGlVertexAttributesTest {
131 public:
stateCheck(GlVertexAttrib expected)132     void stateCheck(GlVertexAttrib expected) override {
133         SnapshotGlVertexAttributesTest::stateCheck(expected);
134 
135         // check current element value
136         switch (expected.type) {
137             case GL_BYTE:
138             case GL_UNSIGNED_BYTE:
139             case GL_SHORT:
140             case GL_UNSIGNED_SHORT:
141             case GL_FIXED:
142                 EXPECT_TRUE(compareIntParameter(GL_CURRENT_VERTEX_ATTRIB,
143                                                 expected.values.ints));
144                 break;
145             case GL_FLOAT:
146                 EXPECT_TRUE(compareFloatParameter(GL_CURRENT_VERTEX_ATTRIB,
147                                                   expected.values.floats));
148                 break;
149             default:
150                 ADD_FAILURE() << "Unexpected type " << expected.type
151                               << " for vertex attribute " << m_index;
152         }
153     }
154 
stateChange()155     void stateChange() override {
156         SnapshotGlVertexAttributesTest::stateChange();
157         GlVertexAttrib changed = *m_changed_value;
158         switch (changed.type) {
159             case GL_BYTE:
160             case GL_UNSIGNED_BYTE:
161             case GL_SHORT:
162             case GL_UNSIGNED_SHORT:
163             case GL_FIXED:
164                 // TODO(benzene): support GLES3+
165                 FAIL() << "GLES2 only supports float vertex attributes "
166                           "(VertexAttrib{1234}f).";
167             case GL_FLOAT:
168                 switch (changed.values.floats.size()) {
169                     case 1:
170                         gl->glVertexAttrib1fv(
171                                 m_index, (GLfloat*)&changed.values.floats[0]);
172                         break;
173                     case 2:
174                         gl->glVertexAttrib2fv(
175                                 m_index, (GLfloat*)&changed.values.floats[0]);
176                         break;
177                     case 3:
178                         gl->glVertexAttrib3fv(
179                                 m_index, (GLfloat*)&changed.values.floats[0]);
180                         break;
181                     case 4:
182                         gl->glVertexAttrib4fv(
183                                 m_index, (GLfloat*)&changed.values.floats[0]);
184                         break;
185                     default:
186                         ADD_FAILURE() << "Unsupported size " << changed.size
187                                       << " for vertex attribute " << m_index;
188                 }
189                 break;
190             default:
191                 ADD_FAILURE() << "Unsupported type " << changed.type
192                               << " for vertex attribute " << m_index;
193         }
194     }
195 };
196 
197 class SnapshotGlVertexAttribArrayTest : public SnapshotGlVertexAttributesTest {
198 public:
stateCheck(GlVertexAttrib expected)199     virtual void stateCheck(GlVertexAttrib expected) override {
200         SnapshotGlVertexAttributesTest::stateCheck(expected);
201         // check parameters
202         EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_SIZE,
203                                         expected.size));
204         EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_TYPE,
205                                         expected.type));
206         EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_STRIDE,
207                                         expected.stride));
208         EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
209                                         expected.normalized));
210         EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
211                                         expected.bufferBinding));
212 
213         GLvoid* pointer;
214         gl->glGetVertexAttribPointerv(m_index, GL_VERTEX_ATTRIB_ARRAY_POINTER,
215                                       &pointer);
216         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
217         EXPECT_EQ(expected.pointer, pointer);
218     }
219 
stateChange()220     virtual void stateChange() override {
221         SnapshotGlVertexAttributesTest::stateChange();
222         GlVertexAttrib changed = *m_changed_value;
223         gl->glVertexAttribPointer(m_index, changed.size, changed.type,
224                                   changed.normalized, changed.stride,
225                                   changed.pointer);
226     }
227 };
228 
229 class SnapshotGlVertexAttribBufferTest
230     : public SnapshotGlVertexAttribArrayTest {
231 public:
stateCheck(GlVertexAttrib expected)232     void stateCheck(GlVertexAttrib expected) override {
233         SnapshotGlVertexAttribArrayTest::stateCheck(expected);
234     }
235 
stateChange()236     void stateChange() override {
237         GlVertexAttrib changed = *m_changed_value;
238 
239         // Set up buffer to be bound before glVertexAttribPointer,
240         // which will copy ARRAY_BUFFER_BINDING into the attrib's binding
241         if (gl->glIsBuffer(changed.bufferBinding) == GL_TRUE) {
242             gl->glBindBuffer(GL_ARRAY_BUFFER, changed.bufferBinding);
243             EXPECT_EQ(GL_NO_ERROR, gl->glGetError())
244                     << "Failed to bind buffer " << changed.bufferBinding;
245             GLint bindresult;
246             gl->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &bindresult);
247             EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
248         } else {
249             ADD_FAILURE() << "Tried to bind buffer with vertex attributes but "
250                           << changed.bufferBinding << " is not a valid buffer.";
251         }
252 
253         SnapshotGlVertexAttribArrayTest::stateChange();
254 
255         if (changed.bufferBinding != 0) {
256             // Clear the array buffer binding
257             gl->glBindBuffer(GL_ARRAY_BUFFER, 0);
258             EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
259 
260             GLint bindresult;
261             gl->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &bindresult);
262             EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
263         }
264     }
265 };
266 
TEST_F(SnapshotGlVertexAttribSingleValueTest,PreserveCurrentFloatAttrib)267 TEST_F(SnapshotGlVertexAttribSingleValueTest, PreserveCurrentFloatAttrib) {
268     selectIndex(31);
269     GlVertexAttrib testAttrib = kGLES2DefaultVertexAttrib;
270     testAttrib.values = {.ints = {}, .floats = {.1, .3}},
271     setExpectedValues(kGLES2DefaultVertexAttrib, testAttrib);
272     doCheckedSnapshot();
273 }
274 
TEST_F(SnapshotGlVertexAttribArrayTest,DISABLED_PreserveArrayProperties)275 TEST_F(SnapshotGlVertexAttribArrayTest, DISABLED_PreserveArrayProperties) {
276     selectIndex(5);
277     GLfloat testArrayContents[] = {2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f};
278     GlVertexAttrib arrayAttrib = kGLES2DefaultVertexAttrib;
279     arrayAttrib.mode = GlVertexAttribMode::Array;
280     arrayAttrib.size = 3;
281     arrayAttrib.stride = sizeof(GLfloat) * 3;
282     arrayAttrib.normalized = GL_TRUE;
283     arrayAttrib.enabled = GL_TRUE;
284     arrayAttrib.pointer = testArrayContents;
285     setExpectedValues(kGLES2DefaultVertexAttrib, arrayAttrib);
286     doCheckedSnapshot();
287 }
288 
TEST_F(SnapshotGlVertexAttribBufferTest,AttachArrayBuffer)289 TEST_F(SnapshotGlVertexAttribBufferTest, AttachArrayBuffer) {
290     selectIndex(15);
291     GLfloat testBuffContents[] = {
292             0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f,
293             0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f,
294     };
295     GlBufferData data = kTestAttachedBuffer;
296     data.bytes = testBuffContents;
297     GLuint buffer = createBuffer(gl, data);
298     GlVertexAttrib withBuffer = kGLES2DefaultVertexAttrib;
299     withBuffer.mode = GlVertexAttribMode::Buffer;
300     withBuffer.enabled = GL_TRUE;
301     withBuffer.pointer = reinterpret_cast<GLvoid*>(2);  // offset
302     withBuffer.bufferBinding = buffer;
303     setExpectedValues(kGLES2DefaultVertexAttrib, withBuffer);
304     doCheckedSnapshot();
305 }
306 
307 }  // namespace
308 }  // namespace gl
309 }  // namespace gfxstream
310