From 0d73120d156e5a5bc027bbc2ecd8d3fd8c563dd3 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 18 Jul 2025 10:00:25 +0800 Subject: [PATCH] [Feat] (MG_State/Buffer): separate UploadData() into Resize()+UploadData() --- .../GLState/BufferState/BufferObject.h | 6 ++- .../GLState/BufferState/BufferState.cpp | 22 ++++++++--- MobileGL/MG_Test/Buffer/BufferTest.cpp | 26 ++++++++++++- MobileGL/MG_Util/Types.h | 37 +++++++++++-------- 4 files changed, 67 insertions(+), 24 deletions(-) diff --git a/MobileGL/MG_State/GLState/BufferState/BufferObject.h b/MobileGL/MG_State/GLState/BufferState/BufferObject.h index e1e894bd..bb55fc25 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferObject.h +++ b/MobileGL/MG_State/GLState/BufferState/BufferObject.h @@ -66,7 +66,8 @@ namespace MobileGL { public: using TargetEnum = BufferTarget; - void UploadData(DataPtr data); + void Resize(SizeT size); + void UploadData(DataPtr data, SizeT atOffset); void SetUsage(BufferUsage usage); SizeT GetSize() const; BufferUsage GetUsage() const; @@ -82,7 +83,8 @@ namespace MobileGL { Data m_data; Bool m_isMapped; BufferMappingAccessBit m_mappingAccess; - UniquePtr m_dirtyRange; + // UniquePtr m_dirtyRange; + Range1D m_dirtyRange; }; } } diff --git a/MobileGL/MG_State/GLState/BufferState/BufferState.cpp b/MobileGL/MG_State/GLState/BufferState/BufferState.cpp index 325098c8..462190d9 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferState.cpp +++ b/MobileGL/MG_State/GLState/BufferState/BufferState.cpp @@ -4,11 +4,21 @@ namespace MobileGL { namespace MG_State { namespace GLState { // BufferObject - void BufferObject::UploadData(DataPtr data) { - m_size = data.size; - memcpy(m_data.data(), data.data, data.size); - m_dirtyRange = MakeUnique(0, m_size); - m_dirtyRange->UnionUpdate(0, m_size); + void BufferObject::Resize(SizeT size) { + m_size = size; + // Always reserve to power-of-2 size to amortize reallocation cost + m_data.reserve(std::bit_ceil(size)); + m_data.resize(size); + // no dirty range == discard all data + m_dirtyRange.Update(0, 0); + } + + void BufferObject::UploadData(DataPtr data, SizeT atOffset) { + assert(atOffset + data.size <= m_size); + // m_size = data.size; + memcpy(m_data.data() + atOffset, data.data, data.size); + // m_dirtyRange = MakeUnique(0, m_size); + m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size - 1); } void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) { @@ -39,7 +49,7 @@ namespace MobileGL { } Range1D BufferObject::GetDirtyRange() const { - return *m_dirtyRange; + return m_dirtyRange; } Bool BufferObject::IsMapped() const { diff --git a/MobileGL/MG_Test/Buffer/BufferTest.cpp b/MobileGL/MG_Test/Buffer/BufferTest.cpp index 3e82e078..264c8e96 100644 --- a/MobileGL/MG_Test/Buffer/BufferTest.cpp +++ b/MobileGL/MG_Test/Buffer/BufferTest.cpp @@ -31,4 +31,28 @@ TEST_F(BufferTest, Binding) { indexSlot.Bind(obj2); ASSERT_TRUE(arraySlot.GetBoundObject() == obj2); ASSERT_TRUE(indexSlot.GetBoundObject() == obj2); -} \ No newline at end of file +} + +TEST_F(BufferTest, PingPong) { + auto& readSlot = glContext.GetBufferBindingSlot(BufferTarget::CopyRead); + auto& writeSlot = glContext.GetBufferBindingSlot(BufferTarget::CopyWrite); + { + auto bufferNames = glContext.GenBufferNames(1); + auto bufObj = glContext.CreateBufferObject(bufferNames[0]); + + writeSlot.Bind(bufObj); + readSlot.Bind(bufObj); + } + + auto bufWrite = writeSlot.GetBoundObject(); + + Vector data { 1, 2, 3, 4, 5 }; + + bufWrite->Resize(data.size()); + DataPtr ptr { .data = data.data(), .size = data.size() }; + bufWrite->UploadData(ptr, 0); + + auto bufRead = readSlot.GetBoundObject(); + void* p = bufRead->AcquireMemory(true, true, false); + ASSERT_TRUE(memcmp(data.data(), p, data.size()) == 0); +} diff --git a/MobileGL/MG_Util/Types.h b/MobileGL/MG_Util/Types.h index 69438aa7..3be46c7d 100644 --- a/MobileGL/MG_Util/Types.h +++ b/MobileGL/MG_Util/Types.h @@ -71,33 +71,40 @@ namespace MobileGL { Fixed32 }; + // represents a range of [start, end) struct Range1D { - const SizeT maxEnd; - const SizeT minStart; - SizeT start; - SizeT end; + // const SizeT maxEnd; + // const SizeT minStart; + SizeT start = 0; + SizeT end = 0; - Range1D(SizeT minStart_, SizeT maxEnd_) - : minStart(minStart_), maxEnd(maxEnd_), start(minStart_), end(minStart_) { - if (minStart_ >= maxEnd_) { - throw RuntimeError("Invalid range: minStart must be less than maxEnd"); - } + // Range1D(SizeT minStart_, SizeT maxEnd_) + // : minStart(minStart_), maxEnd(maxEnd_), start(minStart_), end(minStart_) { + // if (minStart_ >= maxEnd_) { + // throw RuntimeError("Invalid range: minStart must be less than maxEnd"); + // } + // } + + void Update(SizeT newStart, SizeT newEnd) { + assert(newStart <= newEnd); + start = newStart; + end = newEnd; } void UnionUpdate(SizeT newStart, SizeT newEnd) { - if (newStart < minStart || newEnd > maxEnd) { - throw RuntimeError("Range exceeds bounds"); - } + // if (newStart < minStart || newEnd > maxEnd) { + // throw RuntimeError("Range exceeds bounds"); + // } + assert(newStart <= newEnd); start = std::min(start, newStart); end = std::max(end, newEnd); } void IntersectionUpdate(SizeT newStart, SizeT newEnd) { + assert(newStart <= newEnd); start = std::max(start, newStart); end = std::min(end, newEnd); - if (start > end) { - throw RuntimeError("Invalid intersection: start must be less than end"); - } + assert(start <= end); } };