// Copyright (C) 2018 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "GLSnapshotTestStateUtils.h" #include "GLSnapshotTesting.h" #include "OpenGLTestContext.h" #include #include namespace gfxstream { namespace gl { namespace { enum class GlVertexAttribMode { SingleValue = 0, Array = 1, Buffer = 2 }; struct GlVertexAttrib { GlVertexAttribMode mode; GlValues values; GLint size; GLenum type; GLboolean normalized; GLsizei stride; GLboolean enabled; GLvoid* pointer; GLuint bufferBinding; }; static const GlVertexAttrib kGLES2DefaultVertexAttrib = { .mode = GlVertexAttribMode::SingleValue, .values = {.ints = {}, .floats = {0, 0, 0, 1}}, .size = 4, .type = GL_FLOAT, .normalized = GL_FALSE, .stride = 0, .enabled = GL_FALSE, .pointer = nullptr, .bufferBinding = 0}; static const GlBufferData kTestAttachedBuffer = {.size = 16, .bytes = nullptr, .usage = GL_STATIC_DRAW}; class SnapshotGlVertexAttributesTest : public SnapshotSetValueTest { public: virtual void stateCheck(GlVertexAttrib expected) override { EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_ENABLED, expected.enabled)); } virtual void stateChange() override { GlVertexAttrib changed = *m_changed_value; if (changed.enabled) { gl->glEnableVertexAttribArray(m_index); } else { gl->glDisableVertexAttribArray(m_index); } EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); } void selectIndex(GLuint index) { GLint maxAttribs; gl->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); if (index >= maxAttribs) { fprintf(stderr, "cannot select index %d: GL_MAX_VERTEX_ATTRIBS is %d.\n", index, maxAttribs); return; } m_index = index; } protected: testing::AssertionResult compareFloatParameter(GLenum paramName, GLfloat expected) { std::vector v = {expected}; return compareFloatParameter(paramName, v); } testing::AssertionResult compareFloatParameter( GLenum paramName, const std::vector& expected) { std::vector values; values.resize(std::max((GLuint)4, (GLuint)expected.size())); gl->glGetVertexAttribfv(m_index, paramName, &(values[0])); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); return compareVector( expected, values, "float(s) for parameter " + describeGlEnum(paramName) + " of vertex attribute " + std::to_string(m_index)); } testing::AssertionResult compareIntParameter(GLenum paramName, GLint expected) { std::vector v = {expected}; return compareIntParameter(paramName, v); } testing::AssertionResult compareIntParameter( GLenum paramName, const std::vector& expected) { std::vector values; values.resize(std::max((GLuint)4, (GLuint)expected.size())); gl->glGetVertexAttribiv(m_index, paramName, &(values[0])); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); return compareVector( expected, values, "int(s) for parameter " + describeGlEnum(paramName) + " of vertex attribute " + std::to_string(m_index)); } GLuint m_index = 0; }; class SnapshotGlVertexAttribSingleValueTest : public SnapshotGlVertexAttributesTest { public: void stateCheck(GlVertexAttrib expected) override { SnapshotGlVertexAttributesTest::stateCheck(expected); // check current element value switch (expected.type) { case GL_BYTE: case GL_UNSIGNED_BYTE: case GL_SHORT: case GL_UNSIGNED_SHORT: case GL_FIXED: EXPECT_TRUE(compareIntParameter(GL_CURRENT_VERTEX_ATTRIB, expected.values.ints)); break; case GL_FLOAT: EXPECT_TRUE(compareFloatParameter(GL_CURRENT_VERTEX_ATTRIB, expected.values.floats)); break; default: ADD_FAILURE() << "Unexpected type " << expected.type << " for vertex attribute " << m_index; } } void stateChange() override { SnapshotGlVertexAttributesTest::stateChange(); GlVertexAttrib changed = *m_changed_value; switch (changed.type) { case GL_BYTE: case GL_UNSIGNED_BYTE: case GL_SHORT: case GL_UNSIGNED_SHORT: case GL_FIXED: // TODO(benzene): support GLES3+ FAIL() << "GLES2 only supports float vertex attributes " "(VertexAttrib{1234}f)."; case GL_FLOAT: switch (changed.values.floats.size()) { case 1: gl->glVertexAttrib1fv( m_index, (GLfloat*)&changed.values.floats[0]); break; case 2: gl->glVertexAttrib2fv( m_index, (GLfloat*)&changed.values.floats[0]); break; case 3: gl->glVertexAttrib3fv( m_index, (GLfloat*)&changed.values.floats[0]); break; case 4: gl->glVertexAttrib4fv( m_index, (GLfloat*)&changed.values.floats[0]); break; default: ADD_FAILURE() << "Unsupported size " << changed.size << " for vertex attribute " << m_index; } break; default: ADD_FAILURE() << "Unsupported type " << changed.type << " for vertex attribute " << m_index; } } }; class SnapshotGlVertexAttribArrayTest : public SnapshotGlVertexAttributesTest { public: virtual void stateCheck(GlVertexAttrib expected) override { SnapshotGlVertexAttributesTest::stateCheck(expected); // check parameters EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_SIZE, expected.size)); EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_TYPE, expected.type)); EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_STRIDE, expected.stride)); EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, expected.normalized)); EXPECT_TRUE(compareIntParameter(GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, expected.bufferBinding)); GLvoid* pointer; gl->glGetVertexAttribPointerv(m_index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &pointer); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); EXPECT_EQ(expected.pointer, pointer); } virtual void stateChange() override { SnapshotGlVertexAttributesTest::stateChange(); GlVertexAttrib changed = *m_changed_value; gl->glVertexAttribPointer(m_index, changed.size, changed.type, changed.normalized, changed.stride, changed.pointer); } }; class SnapshotGlVertexAttribBufferTest : public SnapshotGlVertexAttribArrayTest { public: void stateCheck(GlVertexAttrib expected) override { SnapshotGlVertexAttribArrayTest::stateCheck(expected); } void stateChange() override { GlVertexAttrib changed = *m_changed_value; // Set up buffer to be bound before glVertexAttribPointer, // which will copy ARRAY_BUFFER_BINDING into the attrib's binding if (gl->glIsBuffer(changed.bufferBinding) == GL_TRUE) { gl->glBindBuffer(GL_ARRAY_BUFFER, changed.bufferBinding); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()) << "Failed to bind buffer " << changed.bufferBinding; GLint bindresult; gl->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &bindresult); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); } else { ADD_FAILURE() << "Tried to bind buffer with vertex attributes but " << changed.bufferBinding << " is not a valid buffer."; } SnapshotGlVertexAttribArrayTest::stateChange(); if (changed.bufferBinding != 0) { // Clear the array buffer binding gl->glBindBuffer(GL_ARRAY_BUFFER, 0); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); GLint bindresult; gl->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &bindresult); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); } } }; TEST_F(SnapshotGlVertexAttribSingleValueTest, PreserveCurrentFloatAttrib) { selectIndex(31); GlVertexAttrib testAttrib = kGLES2DefaultVertexAttrib; testAttrib.values = {.ints = {}, .floats = {.1, .3}}, setExpectedValues(kGLES2DefaultVertexAttrib, testAttrib); doCheckedSnapshot(); } TEST_F(SnapshotGlVertexAttribArrayTest, DISABLED_PreserveArrayProperties) { selectIndex(5); GLfloat testArrayContents[] = {2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f}; GlVertexAttrib arrayAttrib = kGLES2DefaultVertexAttrib; arrayAttrib.mode = GlVertexAttribMode::Array; arrayAttrib.size = 3; arrayAttrib.stride = sizeof(GLfloat) * 3; arrayAttrib.normalized = GL_TRUE; arrayAttrib.enabled = GL_TRUE; arrayAttrib.pointer = testArrayContents; setExpectedValues(kGLES2DefaultVertexAttrib, arrayAttrib); doCheckedSnapshot(); } TEST_F(SnapshotGlVertexAttribBufferTest, AttachArrayBuffer) { selectIndex(15); GLfloat testBuffContents[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, }; GlBufferData data = kTestAttachedBuffer; data.bytes = testBuffContents; GLuint buffer = createBuffer(gl, data); GlVertexAttrib withBuffer = kGLES2DefaultVertexAttrib; withBuffer.mode = GlVertexAttribMode::Buffer; withBuffer.enabled = GL_TRUE; withBuffer.pointer = reinterpret_cast(2); // offset withBuffer.bufferBinding = buffer; setExpectedValues(kGLES2DefaultVertexAttrib, withBuffer); doCheckedSnapshot(); } } // namespace } // namespace gl } // namespace gfxstream