Lingfeng Yang | 0e6868f | 2020-11-03 12:32:59 -0800 | [diff] [blame] | 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 | |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 23 | namespace gfxstream { |
| 24 | namespace gl { |
| 25 | namespace { |
Lingfeng Yang | 0e6868f | 2020-11-03 12:32:59 -0800 | [diff] [blame] | 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: |
| 59 | virtual void stateCheck(GlVertexAttrib expected) override { |
| 60 | EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_ENABLED, |
| 61 | expected.enabled)); |
| 62 | } |
| 63 | |
| 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 | |
| 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: |
| 88 | testing::AssertionResult compareFloatParameter(GLenum paramName, |
| 89 | GLfloat expected) { |
| 90 | std::vector<GLfloat> v = {expected}; |
| 91 | return compareFloatParameter(paramName, v); |
| 92 | } |
| 93 | |
| 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 | |
| 107 | testing::AssertionResult compareIntParameter(GLenum paramName, |
| 108 | GLint expected) { |
| 109 | std::vector<GLint> v = {expected}; |
| 110 | return compareIntParameter(paramName, v); |
| 111 | } |
| 112 | |
| 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: |
| 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 | |
| 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: |
| 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 | |
| 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: |
| 232 | void stateCheck(GlVertexAttrib expected) override { |
| 233 | SnapshotGlVertexAttribArrayTest::stateCheck(expected); |
| 234 | } |
| 235 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 307 | } // namespace |
| 308 | } // namespace gl |
| 309 | } // namespace gfxstream |