| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "gpu/command_buffer/client/vertex_array_object_manager.h" | |
| #include <GLES2/gl2ext.h> | |
| #include <GLES3/gl3.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <memory> | |
| #include "testing/gtest/include/gtest/gtest.h" | |
| namespace gpu { | |
| namespace gles2 { | |
| class VertexArrayObjectManagerTest : public testing::Test { | |
| protected: | |
| static const GLuint kMaxAttribs = 4; | |
| static const GLuint kClientSideArrayBuffer = 0x1234; | |
| static const GLuint kClientSideElementArrayBuffer = 0x1235; | |
| static const bool kSupportClientSideArrays = true; | |
| void SetUp() override { | |
| manager_.reset(new VertexArrayObjectManager( | |
| kMaxAttribs, | |
| kClientSideArrayBuffer, | |
| kClientSideElementArrayBuffer, | |
| kSupportClientSideArrays)); | |
| } | |
| void TearDown() override {} | |
| std::unique_ptr<VertexArrayObjectManager> manager_; | |
| }; | |
| // GCC requires these declarations, but MSVC requires they not be present | |
| #ifndef _MSC_VER | |
| const GLuint VertexArrayObjectManagerTest::kMaxAttribs; | |
| const GLuint VertexArrayObjectManagerTest::kClientSideArrayBuffer; | |
| const GLuint VertexArrayObjectManagerTest::kClientSideElementArrayBuffer; | |
| #endif | |
| TEST_F(VertexArrayObjectManagerTest, Basic) { | |
| EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers()); | |
| // Check out of bounds access. | |
| uint32_t param; | |
| void* ptr; | |
| EXPECT_FALSE(manager_->GetVertexAttrib( | |
| kMaxAttribs, GL_VERTEX_ATTRIB_ARRAY_ENABLED, ¶m)); | |
| EXPECT_FALSE(manager_->GetAttribPointer( | |
| kMaxAttribs, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr)); | |
| // Check defaults. | |
| for (GLuint ii = 0; ii < kMaxAttribs; ++ii) { | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| ii, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, ¶m)); | |
| EXPECT_EQ(0u, param); | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| ii, GL_VERTEX_ATTRIB_ARRAY_ENABLED, ¶m)); | |
| EXPECT_EQ(0u, param); | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| ii, GL_VERTEX_ATTRIB_ARRAY_SIZE, ¶m)); | |
| EXPECT_EQ(4u, param); | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| ii, GL_VERTEX_ATTRIB_ARRAY_TYPE, ¶m)); | |
| EXPECT_EQ(static_cast<uint32_t>(GL_FLOAT), param); | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| ii, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, ¶m)); | |
| EXPECT_EQ(0u, param); | |
| EXPECT_TRUE(manager_->GetAttribPointer( | |
| ii, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr)); | |
| EXPECT_TRUE(NULL == ptr); | |
| } | |
| } | |
| TEST_F(VertexArrayObjectManagerTest, UnbindBuffer) { | |
| const GLuint kBufferToUnbind = 123; | |
| const GLuint kBufferToRemain = 456; | |
| const GLuint kElementArray = 789; | |
| bool changed = false; | |
| GLuint ids[2] = { 1, 3, }; | |
| manager_->GenVertexArrays(arraysize(ids), ids); | |
| // Bind buffers to attribs on 2 vaos. | |
| for (size_t ii = 0; ii < arraysize(ids); ++ii) { | |
| EXPECT_TRUE(manager_->BindVertexArray(ids[ii], &changed)); | |
| EXPECT_TRUE(manager_->SetAttribPointer( | |
| kBufferToUnbind, 0, 4, GL_FLOAT, false, 0, 0, GL_FALSE)); | |
| EXPECT_TRUE(manager_->SetAttribPointer( | |
| kBufferToRemain, 1, 4, GL_FLOAT, false, 0, 0, GL_FALSE)); | |
| EXPECT_TRUE(manager_->SetAttribPointer( | |
| kBufferToUnbind, 2, 4, GL_FLOAT, false, 0, 0, GL_FALSE)); | |
| EXPECT_TRUE(manager_->SetAttribPointer( | |
| kBufferToRemain, 3, 4, GL_FLOAT, false, 0, 0, GL_FALSE)); | |
| for (size_t jj = 0; jj < 4u; ++jj) { | |
| manager_->SetAttribEnable(jj, true); | |
| } | |
| manager_->BindElementArray(kElementArray); | |
| } | |
| EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers()); | |
| EXPECT_TRUE(manager_->BindVertexArray(ids[0], &changed)); | |
| // Unbind the buffer. | |
| manager_->UnbindBuffer(kBufferToUnbind); | |
| manager_->UnbindBuffer(kElementArray); | |
| // The attribs are still enabled but their buffer is 0. | |
| EXPECT_TRUE(manager_->HaveEnabledClientSideBuffers()); | |
| // Check the status of the bindings. | |
| static const uint32_t expected[][4] = { | |
| { | |
| 0, kBufferToRemain, 0, kBufferToRemain, | |
| }, | |
| { | |
| kBufferToUnbind, kBufferToRemain, kBufferToUnbind, kBufferToRemain, | |
| }, | |
| }; | |
| static const GLuint expected_element_array[] = { | |
| 0, kElementArray, | |
| }; | |
| for (size_t ii = 0; ii < arraysize(ids); ++ii) { | |
| EXPECT_TRUE(manager_->BindVertexArray(ids[ii], &changed)); | |
| for (size_t jj = 0; jj < 4; ++jj) { | |
| uint32_t param = 1; | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| jj, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, ¶m)); | |
| EXPECT_EQ(expected[ii][jj], param) | |
| << "id: " << ids[ii] << ", attrib: " << jj; | |
| } | |
| EXPECT_EQ(expected_element_array[ii], | |
| manager_->bound_element_array_buffer()); | |
| } | |
| // The vao that was not bound still has all service side bufferws. | |
| EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers()); | |
| // Make sure unbinding 0 does not effect count incorrectly. | |
| EXPECT_TRUE(manager_->BindVertexArray(0, &changed)); | |
| EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers()); | |
| manager_->SetAttribEnable(2, true); | |
| manager_->UnbindBuffer(0); | |
| manager_->SetAttribEnable(2, false); | |
| EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers()); | |
| } | |
| TEST_F(VertexArrayObjectManagerTest, GetSet) { | |
| const char* dummy = "dummy"; | |
| const void* p = reinterpret_cast<const void*>(dummy); | |
| manager_->SetAttribEnable(1, true); | |
| manager_->SetAttribPointer(123, 1, 3, GL_BYTE, true, 3, p, GL_TRUE); | |
| uint32_t param; | |
| void* ptr; | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| 1, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, ¶m)); | |
| EXPECT_EQ(123u, param); | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| 1, GL_VERTEX_ATTRIB_ARRAY_ENABLED, ¶m)); | |
| EXPECT_NE(0u, param); | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| 1, GL_VERTEX_ATTRIB_ARRAY_SIZE, ¶m)); | |
| EXPECT_EQ(3u, param); | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| 1, GL_VERTEX_ATTRIB_ARRAY_TYPE, ¶m)); | |
| EXPECT_EQ(static_cast<uint32_t>(GL_BYTE), param); | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| 1, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, ¶m)); | |
| EXPECT_NE(0u, param); | |
| EXPECT_TRUE(manager_->GetVertexAttrib( | |
| 1, GL_VERTEX_ATTRIB_ARRAY_INTEGER, ¶m)); | |
| EXPECT_EQ(1u, param); | |
| EXPECT_TRUE(manager_->GetAttribPointer( | |
| 1, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr)); | |
| EXPECT_EQ(p, ptr); | |
| // Check that getting the divisor is passed to the service. | |
| // This is because the divisor is an optional feature which | |
| // only the service can validate. | |
| EXPECT_FALSE(manager_->GetVertexAttrib( | |
| 0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE, ¶m)); | |
| } | |
| TEST_F(VertexArrayObjectManagerTest, HaveEnabledClientSideArrays) { | |
| // Check turning on an array. | |
| manager_->SetAttribEnable(1, true); | |
| EXPECT_TRUE(manager_->HaveEnabledClientSideBuffers()); | |
| // Check turning off an array. | |
| manager_->SetAttribEnable(1, false); | |
| EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers()); | |
| // Check turning on an array and assigning a buffer. | |
| manager_->SetAttribEnable(1, true); | |
| manager_->SetAttribPointer(123, 1, 3, GL_BYTE, true, 3, NULL, GL_FALSE); | |
| EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers()); | |
| // Check unassigning a buffer. | |
| manager_->SetAttribPointer(0, 1, 3, GL_BYTE, true, 3, NULL, GL_FALSE); | |
| EXPECT_TRUE(manager_->HaveEnabledClientSideBuffers()); | |
| // Check disabling the array. | |
| manager_->SetAttribEnable(1, false); | |
| EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers()); | |
| } | |
| TEST_F(VertexArrayObjectManagerTest, BindElementArray) { | |
| bool changed = false; | |
| GLuint ids[2] = { 1, 3, }; | |
| manager_->GenVertexArrays(arraysize(ids), ids); | |
| // Check the default element array is 0. | |
| EXPECT_EQ(0u, manager_->bound_element_array_buffer()); | |
| // Check binding the same array does not need a service call. | |
| EXPECT_FALSE(manager_->BindElementArray(0u)); | |
| // Check binding a new element array requires a service call. | |
| EXPECT_TRUE(manager_->BindElementArray(55u)); | |
| // Check the element array was bound. | |
| EXPECT_EQ(55u, manager_->bound_element_array_buffer()); | |
| // Check binding the same array does not need a service call. | |
| EXPECT_FALSE(manager_->BindElementArray(55u)); | |
| // Check with a new vao. | |
| EXPECT_TRUE(manager_->BindVertexArray(1, &changed)); | |
| // Check the default element array is 0. | |
| EXPECT_EQ(0u, manager_->bound_element_array_buffer()); | |
| // Check binding a new element array requires a service call. | |
| EXPECT_TRUE(manager_->BindElementArray(11u)); | |
| // Check the element array was bound. | |
| EXPECT_EQ(11u, manager_->bound_element_array_buffer()); | |
| // Check binding the same array does not need a service call. | |
| EXPECT_FALSE(manager_->BindElementArray(11u)); | |
| // check switching vao bindings returns the correct element array. | |
| EXPECT_TRUE(manager_->BindVertexArray(3, &changed)); | |
| EXPECT_EQ(0u, manager_->bound_element_array_buffer()); | |
| EXPECT_TRUE(manager_->BindVertexArray(0, &changed)); | |
| EXPECT_EQ(55u, manager_->bound_element_array_buffer()); | |
| EXPECT_TRUE(manager_->BindVertexArray(1, &changed)); | |
| EXPECT_EQ(11u, manager_->bound_element_array_buffer()); | |
| } | |
| TEST_F(VertexArrayObjectManagerTest, GenBindDelete) { | |
| // Check unknown array fails. | |
| bool changed = false; | |
| EXPECT_FALSE(manager_->BindVertexArray(123, &changed)); | |
| EXPECT_FALSE(changed); | |
| GLuint ids[2] = { 1, 3, }; | |
| manager_->GenVertexArrays(arraysize(ids), ids); | |
| // Check Genned arrays succeed. | |
| EXPECT_TRUE(manager_->BindVertexArray(1, &changed)); | |
| EXPECT_TRUE(changed); | |
| EXPECT_TRUE(manager_->BindVertexArray(3, &changed)); | |
| EXPECT_TRUE(changed); | |
| // Check binding the same array returns changed as false. | |
| EXPECT_TRUE(manager_->BindVertexArray(3, &changed)); | |
| EXPECT_FALSE(changed); | |
| // Check deleted ararys fail to bind | |
| manager_->DeleteVertexArrays(2, ids); | |
| EXPECT_FALSE(manager_->BindVertexArray(1, &changed)); | |
| EXPECT_FALSE(changed); | |
| EXPECT_FALSE(manager_->BindVertexArray(3, &changed)); | |
| EXPECT_FALSE(changed); | |
| // Check binding 0 returns changed as false since it's | |
| // already bound. | |
| EXPECT_TRUE(manager_->BindVertexArray(0, &changed)); | |
| EXPECT_FALSE(changed); | |
| } | |
| TEST_F(VertexArrayObjectManagerTest, IsReservedId) { | |
| EXPECT_TRUE(manager_->IsReservedId(kClientSideArrayBuffer)); | |
| EXPECT_TRUE(manager_->IsReservedId(kClientSideElementArrayBuffer)); | |
| EXPECT_FALSE(manager_->IsReservedId(0)); | |
| EXPECT_FALSE(manager_->IsReservedId(1)); | |
| EXPECT_FALSE(manager_->IsReservedId(2)); | |
| } | |
| } // namespace gles2 | |
| } // namespace gpu | |