diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp index 7bedc086..6100cda3 100644 --- a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp @@ -384,13 +384,6 @@ namespace MobileGL { auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); bindingSlot.Bind(bufferObject); - - if (bufferTarget == BufferTarget::Index) { - auto currentVAO = MG_State::pGLContext->GetBoundVertexArray(); - if (currentVAO) { - currentVAO->BindElementBuffer(bufferObject); - } - } } void GenBuffers_State(GLsizei n, GLuint* buffers) { diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp b/MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp index 7ff17337..82430131 100644 --- a/MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp +++ b/MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp @@ -3,17 +3,25 @@ namespace MobileGL::MG_Impl::GLImpl { namespace BufferImpl { bool ValidateBufferTarget(BufferTarget target) { - if (target != BufferTarget::Unknown) - return true; + if (target == BufferTarget::Unknown) { + using namespace MG_Util; + String bufferTargetStr = ConvertBufferTargetToString(target); + String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target)); + MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget", + std::format("Target {} ({}) is not valid.", + bufferTargetStr, glTargetStr))); + return false; + } + + if (target == BufferTarget::Index && MG_State::pGLContext->GetBoundVertexArray() == nullptr) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget", + "No vertex array object is bound.")); + return false; + } - using namespace MG_Util; - String bufferTargetStr = ConvertBufferTargetToString(target); - String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target)); - MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, - MakeShared("MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget", - std::format("Target {} ({}) is not valid.", - bufferTargetStr, glTargetStr))); - return false; + return true; } bool ValidateBufferName(Uint index) { diff --git a/MobileGL/MG_Impl/GLImpl/VertexArray/Validators.cpp b/MobileGL/MG_Impl/GLImpl/VertexArray/Validators.cpp index 657759a5..3a6c6593 100644 --- a/MobileGL/MG_Impl/GLImpl/VertexArray/Validators.cpp +++ b/MobileGL/MG_Impl/GLImpl/VertexArray/Validators.cpp @@ -16,6 +16,7 @@ namespace MobileGL::MG_Impl::GLImpl { MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MakeShared("MG_Impl/GLImpl", "ValidateVertexArrayName", std::format("Vertex array name {} is not valid.", index))); + return false; } return true; } diff --git a/MobileGL/MG_State/GLState/BufferState/BufferState.cpp b/MobileGL/MG_State/GLState/BufferState/BufferState.cpp index 6a2a30f1..0dec2446 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferState.cpp +++ b/MobileGL/MG_State/GLState/BufferState/BufferState.cpp @@ -5,8 +5,8 @@ namespace MobileGL { namespace GLState { BufferState::BufferState() : m_indexGenerator(1024, 1) { - for (SizeT i = 0; i < (SizeT)BufferTarget::BufferTargetCount; ++i) { - m_bindingSlots[i] = BindingSlot((BufferTarget)i); + for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { + m_bindingSlots[i] = BindingSlot(GlobalBufferTargets[i]); } } @@ -31,14 +31,18 @@ namespace MobileGL { } BindingSlot& BufferState::GetBindingSlot(BufferTarget target) { - return m_bindingSlots[(SizeT)target]; + for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { + if (m_bindingSlots[i].GetTarget() == target) { + return m_bindingSlots[i]; + } + } } void BufferState::MarkBufferObjectForDeletion(Uint index) { if (m_indexGenerator.IsValid(index)) { auto it = m_bufferObjects.find(index); if (it != m_bufferObjects.end()) { - for (SizeT i = 0; i < (SizeT)BufferTarget::BufferTargetCount; ++i) { + for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { if (m_bindingSlots[i].GetBoundObject() == it->second) { m_bindingSlots[i].Bind(nullptr); } diff --git a/MobileGL/MG_State/GLState/BufferState/BufferState.h b/MobileGL/MG_State/GLState/BufferState/BufferState.h index d12f6347..eb0a9dd4 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferState.h +++ b/MobileGL/MG_State/GLState/BufferState/BufferState.h @@ -3,6 +3,21 @@ namespace MobileGL { namespace MG_State { namespace GLState { + constexpr const auto GlobalBufferTargets = ToArray( + BufferTarget::Vertex, + BufferTarget::Uniform, + BufferTarget::CopyRead, + BufferTarget::CopyWrite, + BufferTarget::PixelPack, + BufferTarget::PixelUnpack, + BufferTarget::Query, + BufferTarget::Texture, + BufferTarget::TransformFeedback, + BufferTarget::AtomicCounter, + BufferTarget::DispatchIndirect, + BufferTarget::DrawIndirect, + BufferTarget::ShaderStorage); + class BufferState { public: BufferState(); @@ -18,7 +33,7 @@ namespace MobileGL { private: UnorderedMap> m_bufferObjects; IndexGenerator m_indexGenerator; - Array, (SizeT)BufferTarget::BufferTargetCount> m_bindingSlots; + Array, GlobalBufferTargets.size()> m_bindingSlots; }; } } diff --git a/MobileGL/MG_State/GLState/Core.cpp b/MobileGL/MG_State/GLState/Core.cpp index a606cfcf..54f75164 100644 --- a/MobileGL/MG_State/GLState/Core.cpp +++ b/MobileGL/MG_State/GLState/Core.cpp @@ -46,6 +46,10 @@ namespace MobileGL { } BindingSlot& GLContext::GetBufferBindingSlot(BufferTarget target) { + if (target == BufferTarget::Index) { + return m_vertexArrayState.GetBoundVertexArray()->GetIndexBufferBindingSlot(); + } + return m_bufferState.GetBindingSlot(target); } @@ -54,6 +58,21 @@ namespace MobileGL { } void GLContext::MarkBufferObjectForDeletion(Uint index) { + if (ValidateBufferObject(index)) { + auto bufferObject = m_bufferState.GetBufferObject(index); + for (SizeT i = 0; i < m_vertexArrayState.GetAllVertexArrays().size(); ++i) { + auto vao = m_vertexArrayState.GetAllVertexArrays()[i]; + if (vao->GetIndexBufferBindingSlot().GetBoundObject() == bufferObject) { + vao->GetIndexBufferBindingSlot().Bind(nullptr); + } + for (SizeT j = 0; j < VertexArrayObject::MAX_VERTEX_ATTRIBS; ++j) { + if (vao->GetAttribute(j).Buffer == bufferObject) { + vao->BindAttributeBuffer(j, nullptr); + } + } + } + } + m_bufferState.MarkBufferObjectForDeletion(index); } diff --git a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp index 9a41d0cf..0378b1db 100644 --- a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp +++ b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp @@ -53,12 +53,8 @@ namespace MobileGL { m_attributes[index].Buffer = buffer; } - void VertexArrayObject::BindElementBuffer(const SharedPtr& buffer) { - m_elementBuffer = buffer; - } - - SharedPtr VertexArrayObject::GetElementBuffer() const { - return m_elementBuffer; + BindingSlot& VertexArrayObject::GetIndexBufferBindingSlot() { + return m_indexBufferBindingSlot; } const VertexAttribute& VertexArrayObject::GetAttribute(Uint index) const { diff --git a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.h b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.h index be8fc26f..00007550 100644 --- a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.h +++ b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.h @@ -28,14 +28,13 @@ namespace MobileGL { void BindAttributeBuffer(Uint index, const SharedPtr& buffer); - void BindElementBuffer(const SharedPtr& buffer); - SharedPtr GetElementBuffer() const; + BindingSlot& GetIndexBufferBindingSlot(); const VertexAttribute& GetAttribute(Uint index) const; private: Array m_attributes; - SharedPtr m_elementBuffer; + BindingSlot m_indexBufferBindingSlot; }; } } diff --git a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.cpp b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.cpp index daa0f1ce..2ff2500f 100644 --- a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.cpp +++ b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.cpp @@ -65,6 +65,15 @@ namespace MobileGL { SharedPtr VertexArrayState::GetBoundVertexArray() { return m_boundVertexArray; } + + Vector> VertexArrayState::GetAllVertexArrays() { + Vector> arrays; + arrays.reserve(m_vertexArrays.size()); + for (const auto& pair : m_vertexArrays) { + arrays.push_back(pair.second); + } + return arrays; + } } } } diff --git a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.h b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.h index dac66978..d6b8707a 100644 --- a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.h +++ b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.h @@ -15,6 +15,7 @@ namespace MobileGL { bool ValidateName(Uint index) const; bool ValidateVertexArrayObject(Uint index) const; SharedPtr GetBoundVertexArray(); + Vector> GetAllVertexArrays(); private: UnorderedMap> m_vertexArrays; diff --git a/MobileGL/MG_Test/Buffer/BufferTest.cpp b/MobileGL/MG_Test/Buffer/BufferTest.cpp index 288ced90..8c80e955 100644 --- a/MobileGL/MG_Test/Buffer/BufferTest.cpp +++ b/MobileGL/MG_Test/Buffer/BufferTest.cpp @@ -15,7 +15,7 @@ protected: TEST_F(BufferTest, Binding) { auto bufferNames = glContext.GenBufferNames(3); auto& arraySlot = glContext.GetBufferBindingSlot(BufferTarget::Vertex); - auto& indexSlot = glContext.GetBufferBindingSlot(BufferTarget::Index); + auto& indexSlot = glContext.GetBufferBindingSlot(BufferTarget::Uniform); auto obj0 = glContext.CreateBufferObject(bufferNames[0]); auto obj1 = glContext.CreateBufferObject(bufferNames[1]); @@ -73,7 +73,7 @@ TEST_F(BufferTest, GenerateManyNames_NoPrematureCreation) { for (SizeT idx : indices) { GLuint name = names[idx]; auto bufObj = glContext.CreateBufferObject(name); - auto& slot = glContext.GetBufferBindingSlot(BufferTarget::Index); + auto& slot = glContext.GetBufferBindingSlot(BufferTarget::Uniform); slot.Bind(bufObj); Vector data = { static_cast(idx + 1), static_cast(idx + 2) }; @@ -483,12 +483,12 @@ TEST_F(GeneralBufferTest, General_GeneralTest_1) { const float vertexData[] = { 0.1f, 0.2f, 0.3f, 1.0f }; BufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertexData), vertexData); - BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + BindBuffer(GL_UNIFORM_BUFFER, ibo); const uint16_t indexData[] = { 0, 1, 2, 3, 0 }; - BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData), indexData, GL_STATIC_DRAW); + BufferData(GL_UNIFORM_BUFFER, sizeof(indexData), indexData, GL_STATIC_DRAW); const uint16_t newIndices[] = { 4, 5 }; - BufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2 * sizeof(uint16_t), + BufferSubData(GL_UNIFORM_BUFFER, 2 * sizeof(uint16_t), sizeof(newIndices), newIndices); BindBuffer(GL_COPY_READ_BUFFER, staging); @@ -498,14 +498,14 @@ TEST_F(GeneralBufferTest, General_GeneralTest_1) { CopyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, 0, 40, sizeof(stagingData)); - BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - void* fullMap = MapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_WRITE); + BindBuffer(GL_UNIFORM_BUFFER, ibo); + void* fullMap = MapBuffer(GL_UNIFORM_BUFFER, GL_READ_WRITE); ASSERT_NE(fullMap, nullptr); uint16_t* indices = static_cast(fullMap); indices[0] = 10; - EXPECT_TRUE(UnmapBuffer(GL_ELEMENT_ARRAY_BUFFER)); + EXPECT_TRUE(UnmapBuffer(GL_UNIFORM_BUFFER)); BindBuffer(GL_ARRAY_BUFFER, vbo); void* partialMap = MapBufferRange(GL_ARRAY_BUFFER, 20, 8, @@ -535,12 +535,12 @@ TEST_F(GeneralBufferTest, General_GeneralTest_1) { EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); - BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - void* iboMap = MapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY); + BindBuffer(GL_UNIFORM_BUFFER, ibo); + void* iboMap = MapBuffer(GL_UNIFORM_BUFFER, GL_READ_ONLY); const uint16_t* finalIndices = static_cast(iboMap); EXPECT_EQ(finalIndices[0], 10); EXPECT_EQ(finalIndices[2], 4); - EXPECT_TRUE(UnmapBuffer(GL_ELEMENT_ARRAY_BUFFER)); + EXPECT_TRUE(UnmapBuffer(GL_UNIFORM_BUFFER)); DeleteBuffers(1, &staging); diff --git a/MobileGL/MG_Test/VertexArray/VertexArrayTest.cpp b/MobileGL/MG_Test/VertexArray/VertexArrayTest.cpp index dcd8f5b4..edfb9abc 100644 --- a/MobileGL/MG_Test/VertexArray/VertexArrayTest.cpp +++ b/MobileGL/MG_Test/VertexArray/VertexArrayTest.cpp @@ -71,7 +71,7 @@ TEST_F(VertexArrayTest, VertexAttributeSetup) { ASSERT_FALSE(vao->IsAttributeEnabled(1)); } -TEST_F(VertexArrayTest, ElementBufferBinding) { +TEST_F(VertexArrayTest, IndexBufferBinding) { auto vaoNames = glContext.GenVertexArrayNames(1); auto vao = glContext.CreateVertexArrayObject(vaoNames[0]); glContext.BindVertexArray(vaoNames[0]); @@ -86,13 +86,13 @@ TEST_F(VertexArrayTest, ElementBufferBinding) { DataPtr ptr{ .data = indices.data(), .size = byteSize }; ebo->UploadData(ptr, 0); - vao->BindElementBuffer(ebo); - ASSERT_EQ(vao->GetElementBuffer(), ebo); + glContext.GetBufferBindingSlot(BufferTarget::Index).Bind(ebo); + ASSERT_EQ(glContext.GetBufferBindingSlot(BufferTarget::Index).GetBoundObject(), ebo); auto newEboNames = glContext.GenBufferNames(1); auto newEbo = glContext.CreateBufferObject(newEboNames[0]); - vao->BindElementBuffer(newEbo); - ASSERT_EQ(vao->GetElementBuffer(), newEbo); + glContext.GetBufferBindingSlot(BufferTarget::Index).Bind(newEbo); + ASSERT_EQ(glContext.GetBufferBindingSlot(BufferTarget::Index).GetBoundObject(), newEbo); } TEST_F(VertexArrayTest, DeleteVAO) { @@ -281,25 +281,18 @@ TEST_F(GeneralVertexArrayTest, General_VertexAttributeConfiguration) { EXPECT_EQ(GetError(), GL_NO_ERROR); } -TEST_F(GeneralVertexArrayTest, General_ElementBufferBinding) { +TEST_F(GeneralVertexArrayTest, General_IndexBufferBinding) { GLuint vao = CreateVAO(); GLuint ebo = CreateVBO(GL_ELEMENT_ARRAY_BUFFER, 256); auto vaoObj = MG_State::pGLContext->GetVertexArrayObject(vao); ASSERT_NE(vaoObj, nullptr); - ASSERT_NE(vaoObj->GetElementBuffer(), nullptr); - + GLuint newEbo; GenBuffers(1, &newEbo); BindBuffer(GL_ELEMENT_ARRAY_BUFFER, newEbo); - EXPECT_EQ(vaoObj->GetElementBuffer(), MG_State::pGLContext->GetBufferObject(newEbo)); - - GLuint vao2 = CreateVAO(); - GLuint ebo2 = CreateVBO(GL_ELEMENT_ARRAY_BUFFER, 128); - - auto vaoObj2 = MG_State::pGLContext->GetVertexArrayObject(vao2); - EXPECT_NE(vaoObj->GetElementBuffer(), vaoObj2->GetElementBuffer()); + EXPECT_EQ(MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject(), MG_State::pGLContext->GetBufferObject(newEbo)); EXPECT_EQ(GetError(), GL_NO_ERROR); } @@ -394,17 +387,17 @@ TEST_F(GeneralVertexArrayTest, General_ComplexUsage) { EnableVertexAttribArray(2); BindVertexArray(vao1); - auto vaoObj1 = MG_State::pGLContext->GetVertexArrayObject(vao1); EXPECT_TRUE(vaoObj1->IsAttributeEnabled(0)); EXPECT_TRUE(vaoObj1->IsAttributeEnabled(1)); EXPECT_FALSE(vaoObj1->IsAttributeEnabled(2)); - EXPECT_NE(vaoObj1->GetElementBuffer(), nullptr); + EXPECT_NE(MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject(), nullptr); + BindVertexArray(vao2); auto vaoObj2 = MG_State::pGLContext->GetVertexArrayObject(vao2); EXPECT_TRUE(vaoObj2->IsAttributeEnabled(2)); EXPECT_FALSE(vaoObj2->IsAttributeEnabled(0)); - EXPECT_NE(vaoObj2->GetElementBuffer(), nullptr); + EXPECT_NE(MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject(), nullptr); DeleteVertexArrays(1, &vao1); DeleteVertexArrays(1, &vao2); @@ -444,4 +437,68 @@ TEST_F(GeneralVertexArrayTest, General_DeleteBoundVAO) { EXPECT_EQ(GetError(), GL_INVALID_OPERATION); EXPECT_EQ(GetError(), GL_NO_ERROR); -} \ No newline at end of file +} + +TEST_F(GeneralVertexArrayTest, General_ElementBufferBindingPoint) { + GLuint vao1, vao2; + GenVertexArrays(1, &vao1); + GenVertexArrays(1, &vao2); + + GLuint ebo1, ebo2; + GenBuffers(1, &ebo1); + GenBuffers(1, &ebo2); + + BindVertexArray(vao1); + BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo1); + + BindVertexArray(vao2); + BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo2); + + auto vaoObj1 = MG_State::pGLContext->GetVertexArrayObject(vao1); + auto vaoObj2 = MG_State::pGLContext->GetVertexArrayObject(vao2); + EXPECT_EQ(vaoObj1->GetIndexBufferBindingSlot().GetBoundObject(), MG_State::pGLContext->GetBufferObject(ebo1)); + EXPECT_EQ(vaoObj2->GetIndexBufferBindingSlot().GetBoundObject(), MG_State::pGLContext->GetBufferObject(ebo2)); + + BindVertexArray(vao1); + EXPECT_EQ(GetError(), GL_NO_ERROR); + + BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo2); + + EXPECT_EQ(MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject(), + MG_State::pGLContext->GetBufferObject(ebo2)); + + BindVertexArray(vao2); + EXPECT_EQ(MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject(), + MG_State::pGLContext->GetBufferObject(ebo2)); + + BindVertexArray(0); + BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo1); + + EXPECT_EQ(GetError(), GL_INVALID_OPERATION); + + BindVertexArray(vao1); + DeleteVertexArrays(1, &vao1); + + BindVertexArray(vao1); + EXPECT_EQ(GetError(), GL_INVALID_OPERATION); + EXPECT_EQ(GetError(), GL_NO_ERROR); + + EXPECT_EQ(MG_State::pGLContext->GetVertexArrayObject(vao1).get(), nullptr); + + BindVertexArray(vao2); + DeleteBuffers(1, &ebo2); + + EXPECT_EQ(vaoObj2->GetIndexBufferBindingSlot().GetBoundObject().get(), nullptr); + + GLuint ebo3; + GenBuffers(1, &ebo3); + BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo3); + + EXPECT_EQ(vaoObj2->GetIndexBufferBindingSlot().GetBoundObject(), MG_State::pGLContext->GetBufferObject(ebo3)); + + DeleteVertexArrays(1, &vao2); + DeleteBuffers(1, &ebo1); + DeleteBuffers(1, &ebo3); + + EXPECT_EQ(GetError(), GL_NO_ERROR); +} diff --git a/MobileGL/MG_Util/Types.h b/MobileGL/MG_Util/Types.h index 096a5960..6d93880f 100644 --- a/MobileGL/MG_Util/Types.h +++ b/MobileGL/MG_Util/Types.h @@ -47,6 +47,11 @@ namespace MobileGL { inline constexpr void Copy(const T* src, T* dest, SizeT count) { std::copy(src, src + count, dest); } + template + constexpr auto ToArray(Ts&&... elems) { + using E = std::common_type_t; + return std::array{ { std::forward(elems)... } }; + } class RuntimeError : public std::runtime_error { public: using std::runtime_error::runtime_error;