diff --git a/MG/Global.h b/MG/Global.h index ce1364e8..bbafc58d 100644 --- a/MG/Global.h +++ b/MG/Global.h @@ -27,7 +27,7 @@ namespace MG_Global { } namespace Common { - inline constexpr int LogLevel = MG_Constants::Common::LOG_LEVEL_DEBUG; + inline constexpr int LogLevel = MG_Constants::Common::LOG_LEVEL_FATAL; inline constexpr int LogTarget = MG_Constants::Common::LOG_TARGET_ALL; #ifdef __ANDROID__ diff --git a/MG/Includes.h b/MG/Includes.h index 078952db..16e1b665 100644 --- a/MG/Includes.h +++ b/MG/Includes.h @@ -107,6 +107,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,7 @@ #include #include "MG_Include/UncertainBool.hpp" +#include "MG_Include/IndexGenerator.hpp" #ifdef _WIN32 #include diff --git a/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp b/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp index b9528e80..2a3d1512 100644 --- a/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp +++ b/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp @@ -43,7 +43,7 @@ namespace MG_GL::GL { GLuint buffer = MG_State_T::bufferState->GetCurrentBinding(target); if (buffer == 0) return; - auto& bufferObj = MG_State_T::bufferState->buffers_[buffer]; + auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject(buffer); if (!bufferObj.isMapped) return; size_t start = static_cast(offset); @@ -134,8 +134,8 @@ namespace MG_GL::GL { } GLuint buffer = MG_State_T::bufferState->currentBindings_[target]; - auto& bufferObj = MG_State_T::bufferState->buffers_[buffer]; - + auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject(buffer); + Diligent::IBuffer* pBuffer = MG_Diligent::g_BufferMap[buffer]; if (pBuffer) { const auto& Desc = pBuffer->GetDesc(); @@ -191,7 +191,7 @@ namespace MG_GL::GL { if (result == GL_NO_ERROR) { GLuint buffer = MG_State_T::bufferState->GetCurrentBinding(target); if (buffer == 0) return; - auto& bufferObj = MG_State_T::bufferState->buffers_[buffer]; + auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject(buffer); if (bufferObj.isDynamic) return; // Dynamic buffer should be created by glDraw* bufferObj.dirty = false; @@ -310,7 +310,7 @@ namespace MG_GL::GL { GLuint buffer = MG_State_T::bufferState->GetCurrentBinding(target); if (buffer == 0) return; - auto& bufferObj = MG_State_T::bufferState->buffers_[buffer]; + auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject(buffer); if (bufferObj.isDynamic) return; // Dynamic buffer should be created by glDraw* Diligent::IBuffer* pBuffer = MG_Diligent::g_BufferMap[buffer]; diff --git a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp index afd68b9f..395e77f7 100644 --- a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp +++ b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp @@ -494,7 +494,7 @@ namespace MG_GL::GL { if (!attrib.enabled || attrib.buffer == 0) continue; GLuint buffer = attrib.buffer; - auto& bufferObj = MG_State_T::bufferState->buffers_[buffer]; + auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject(buffer); Diligent::IBuffer *&pBuffer = MG_Diligent::g_BufferMap[buffer]; if (bufferObj.isDynamic && (!pBuffer || (pBuffer && pBuffer->GetDesc().Size != bufferObj.data.size()))) { @@ -529,7 +529,8 @@ namespace MG_GL::GL { const void* pOriginalIndices = nullptr; if (pVAO->elementBuffer != 0) { - auto& bufferObj = MG_State_T::bufferState->buffers_[pVAO->elementBuffer]; + auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject( + pVAO->elementBuffer); pOriginalIndices = bufferObj.data.data() + reinterpret_cast(pIndices); } else @@ -584,10 +585,10 @@ namespace MG_GL::GL { } else if (pVAO->elementBuffer != 0) { GLuint buffer = pVAO->elementBuffer; - auto& bufferObj = MG_State_T::bufferState->buffers_[buffer]; + auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject(buffer); Diligent::IBuffer*& pBuffer = MG_Diligent::g_BufferMap[buffer]; - if (bufferObj.isDynamic && (!pBuffer || (pBuffer && pBuffer->GetDesc().Size != bufferObj.data.size()))) { + if (bufferObj.isDynamic || (!pBuffer || (pBuffer && pBuffer->GetDesc().Size != bufferObj.data.size()))) { if (pBuffer) { pBuffer->Release(); pBuffer = nullptr; @@ -617,14 +618,14 @@ namespace MG_GL::GL { // Update data for all dynamic buffers for (auto& [bufferID, pBuffer] : MG_Diligent::g_BufferMap) { - auto it = MG_State_T::bufferState->buffers_.find(bufferID); - if (it == MG_State_T::bufferState->buffers_.end()) { + auto* pBufferObject = MG_State_T::bufferState->GetOrCreateBufferObject(bufferID); + if (!pBufferObject) { MG_Util::Debug::LogW("Buffer ID %u not found in bufferState. Skipping update.", bufferID); continue; } - auto& bufferObj = it->second; - if (pBuffer && bufferObj.isDynamic && !bufferObj.data.empty()) { + auto& bufferObj = *pBufferObject; + if (pBuffer && bufferObj.isDynamic) { void* pMappedData = nullptr; MG_Util::Debug::LogD("Mapping dynamic buffer %u for data update.", bufferID); MG_Diligent::g_pContext->MapBuffer( @@ -786,6 +787,7 @@ namespace MG_GL::GL { return; // PrepareForDraw(); + /* if (MG_Diligent::IsInRenderPass) { MG_Util::Debug::LogD("Ending current render pass."); MG_Diligent::g_pContext->EndRenderPass(); @@ -916,6 +918,7 @@ namespace MG_GL::GL { MG_Diligent::IsInRenderPass = false; MG_Util::Debug::LogD("MultiDrawElements completed with %d draws.", indirectCmds.size()); + */ } void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex) { diff --git a/MG/MG_GL/State/Buffer/BufferState.cpp b/MG/MG_GL/State/Buffer/BufferState.cpp index 2273d678..c5cd3e2e 100644 --- a/MG/MG_GL/State/Buffer/BufferState.cpp +++ b/MG/MG_GL/State/Buffer/BufferState.cpp @@ -6,36 +6,31 @@ #include "BufferState.h" -GLenum BufferState::GenName(GLuint *buffer) { - MG_Util::Debug::LogD("MG_State: Buffer: GenName"); - if (!buffer) - return GL_INVALID_VALUE; - - GLuint id = 0; - if (freeId_.empty()) { - id = lastId_++; - } else { - id = freeId_.back(); - freeId_.pop_back(); - } - - *buffer = id; - MG_Util::Debug::LogD("MG_State: Buffer: Gen new name %d", id); - - return GL_NO_ERROR; -} +//GLenum BufferState::GenName(GLuint *buffer) { +// MG_Util::Debug::LogD("MG_State: Buffer: GenName"); +// if (!buffer) +// return GL_INVALID_VALUE; +// +// GLuint id = 0; +// if (freeId_.empty()) { +// id = lastId_++; +// } else { +// id = freeId_.back(); +// freeId_.pop_back(); +// } +// +// *buffer = id; +// MG_Util::Debug::LogD("MG_State: Buffer: Gen new name %d", id); +// +// return GL_NO_ERROR; +//} GLenum BufferState::GenNameN(GLsizei n, GLuint* buffers) { MG_Util::Debug::LogD("MG_State: Buffer: GenNameN called with n=%d", n); - if (n < 0) return GL_INVALID_VALUE; + if (n < 0 || buffers == nullptr) return GL_INVALID_VALUE; + + indexGenerator_.Generate(n, buffers); - for (GLsizei i = 0; i < n; ++i) { - GLenum result = GenName(&buffers[i]); - if (result != GL_NO_ERROR) { - MG_Util::Debug::LogE("MG_State: Buffer: GenNameN failed with error 0x%x", result); - return result; - } - } MG_Util::Debug::LogD("MG_State: Buffer: GenNameN created buffers successfully"); return GL_NO_ERROR; } @@ -48,7 +43,7 @@ GLenum BufferState::Create(GLuint buffer) { if (ValidateAllocatedHandle(buffer)) return GL_INVALID_VALUE; - BufferObject& obj = buffers_[buffer]; + BufferObject& obj = *GetOrCreateBufferObject(buffer); MG_Util::Debug::LogD("MG_State: Buffer: Create created buffer %d", buffer); obj.generated = true; obj.dirty = true; @@ -71,7 +66,7 @@ GLenum BufferState::CommitStorage(GLenum target, GLsizeiptr size, const void* da if (it == currentBindings_.end() || it->second == 0) return GL_INVALID_OPERATION; - BufferObject& obj = buffers_[it->second]; + BufferObject& obj = *GetOrCreateBufferObject(it->second); MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage get buffer object %u at target 0x%x",it->second,target); obj.usage = usage; obj.isDynamic = (usage == GL_DYNAMIC_DRAW || usage == GL_DYNAMIC_READ || @@ -96,7 +91,7 @@ GLenum BufferState::CommitStorageRegion(GLenum target, GLintptr offset, GLsizeip if (it == currentBindings_.end() || it->second == 0) return GL_INVALID_OPERATION; - BufferObject& obj = buffers_[it->second]; + BufferObject& obj = *GetOrCreateBufferObject(it->second); MG_Util::Debug::LogD("MG_State: Buffer: BufferSubData get buffer object %u at target 0x%x", it->second, target); if (static_cast(offset + size) > obj.data.size()) return GL_INVALID_VALUE; @@ -125,7 +120,7 @@ GLenum BufferState::AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLs return GL_INVALID_OPERATION; } - BufferObject& obj = buffers_[it->second]; + BufferObject& obj = *GetOrCreateBufferObject(it->second); MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange operating on buffer %u", it->second); if (obj.isMapped) { MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: buffer %u is already mapped", it->second); @@ -161,7 +156,7 @@ GLenum BufferState::SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr if (it == currentBindings_.end() || it->second == 0) return GL_INVALID_OPERATION; - BufferObject& obj = buffers_[it->second]; + BufferObject& obj = *GetOrCreateBufferObject(it->second); if (!obj.isMapped || !(obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT)) return GL_INVALID_OPERATION; @@ -185,8 +180,8 @@ GLenum BufferState::CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLint if (readBuffer == 0 || writeBuffer == 0 || readBuffer == writeBuffer) return GL_INVALID_OPERATION; - BufferObject& src = buffers_[readBuffer]; - BufferObject& dst = buffers_[writeBuffer]; + BufferObject& src = *GetOrCreateBufferObject(readBuffer); + BufferObject& dst = *GetOrCreateBufferObject(writeBuffer); if (static_cast(readOffset + size) > src.data.size() || static_cast(writeOffset + size) > dst.data.size()) @@ -206,7 +201,7 @@ GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** map default: flags = access; } - return AcquireBufferMemoryRange(target, 0, buffers_[currentBindings_[target]].data.size(), flags, mappedPointer); + return AcquireBufferMemoryRange(target, 0, GetOrCreateBufferObject(currentBindings_[target])->data.size(), flags, mappedPointer); } GLenum BufferState::ReleaseBufferMemory(GLenum target) { @@ -217,7 +212,7 @@ GLenum BufferState::ReleaseBufferMemory(GLenum target) { if (it == currentBindings_.end() || it->second == 0) return GL_INVALID_OPERATION; - BufferObject& obj = buffers_[it->second]; + BufferObject& obj = *GetOrCreateBufferObject(it->second); if (!obj.isMapped) return GL_INVALID_OPERATION; @@ -234,24 +229,22 @@ GLenum BufferState::ReleaseBufferMemory(GLenum target) { return GL_NO_ERROR; } -bool BufferState::ValidateAllocatedHandle(GLuint buffer) { - bool isValid = buffers_.find(buffer) != buffers_.end(); +bool BufferState::ValidateAllocatedHandle(GLuint buffer) const { + bool isValid = buffer != 0 && bufferObjects_.size() > buffer && bufferObjects_[buffer] != nullptr; MG_Util::Debug::LogD("MG_State: Buffer: ValidateAllocatedHandle called on buffer %u returns %d", buffer, isValid); return isValid; } -bool BufferState::ValidateGeneratedName(GLuint buffer) { - bool inFreeList = std::find(freeId_.begin(), freeId_.end(), buffer) != freeId_.end(); - bool lessThanLast = buffer < lastId_; // lastId_ is not generated yet - MG_Util::Debug::LogD("MG_State: Buffer: ValidateGeneratedName called on buffer %u returns %d", buffer, lessThanLast && !inFreeList); - return lessThanLast && !inFreeList; +bool BufferState::ValidateGeneratedName(GLuint buffer) const { + bool isValid = indexGenerator_.IsValid(buffer); + MG_Util::Debug::LogD("MG_State: Buffer: ValidateGeneratedName called on buffer %u returns %s", buffer, isValid ? "true" : "false"); + return isValid; } void BufferState::Delete(GLuint buffer) { - buffers_.erase(buffer); - if (ValidateGeneratedName(buffer)) - // TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend. - //freeId_.emplace_back(buffer); + bufferObjects_[buffer].reset(); + indexGenerator_.Delete(buffer); + for (auto& [target, id] : currentBindings_) { if (id == buffer) id = 0; } @@ -293,12 +286,12 @@ GLenum BufferState::QueryPropertyIntVector(GLenum target, GLenum pname, GLint* p return GL_INVALID_OPERATION; } GLuint bufferId = bindingIt->second; - auto bufferIt = buffers_.find(bufferId); - if (bufferIt == buffers_.end()) { + + if (!ValidateAllocatedHandle(bufferId)) { return GL_INVALID_OPERATION; } - const BufferObject& buffer = bufferIt->second; + const BufferObject& buffer = *bufferObjects_[bufferId]; switch (pname) { case GL_BUFFER_ACCESS: @@ -327,4 +320,14 @@ GLuint BufferState::GetCurrentBinding(GLenum target) const { return it->second; } return 0; -} \ No newline at end of file +} + +BufferState::BufferObject* BufferState::GetOrCreateBufferObject(GLuint buffer) { + if (bufferObjects_.size() <= buffer) { + bufferObjects_.resize(buffer + 1); + } + if (bufferObjects_[buffer] == nullptr) { + bufferObjects_[buffer] = std::make_unique(); + } + return bufferObjects_[buffer].get(); +} diff --git a/MG/MG_GL/State/Buffer/BufferState.h b/MG/MG_GL/State/Buffer/BufferState.h index 0901f0f7..2d7b7852 100644 --- a/MG/MG_GL/State/Buffer/BufferState.h +++ b/MG/MG_GL/State/Buffer/BufferState.h @@ -26,7 +26,7 @@ public: }; // Return: the validity of the operation, according to OpenGL 3 standard - GLenum GenName(GLuint* buffer); +// GLenum GenName(GLuint* buffer); GLenum GenNameN(GLsizei n, GLuint* buffers); GLenum Create(GLuint buffer); GLenum Bind(GLenum target, GLuint buffer); @@ -40,16 +40,20 @@ public: GLenum QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const; GLenum DeleteN(GLsizei n, const GLuint* buffers); - bool ValidateAllocatedHandle(GLuint buffer); - bool ValidateGeneratedName(GLuint buffer); + bool ValidateAllocatedHandle(GLuint buffer) const; + bool ValidateGeneratedName(GLuint buffer) const; void Delete(GLuint buffer); GLuint GetCurrentBinding(GLenum target) const; + BufferObject* GetOrCreateBufferObject(GLuint buffer); + MG_Global::unordered_map currentBindings_; - MG_Global::unordered_map buffers_; +// MG_Global::unordered_map buffers_; private: - std::vector freeId_; - GLuint lastId_ = 1; +// std::vector freeId_; +// GLuint lastId_ = 1; + IndexGenerator indexGenerator_; + std::vector> bufferObjects_; static bool IsValidTarget_(GLenum target); }; diff --git a/MG/MG_Include/IndexGenerator.hpp b/MG/MG_Include/IndexGenerator.hpp new file mode 100644 index 00000000..3f62b116 --- /dev/null +++ b/MG/MG_Include/IndexGenerator.hpp @@ -0,0 +1,73 @@ +// +// Created by yello on 2025-06-27. +// + +#ifndef INDEXGENERATOR_H +#define INDEXGENERATOR_H + +#include +#include // For size_t +#include // For std::min +#include + +template +class IndexGenerator { +public: + // 构造函数 + IndexGenerator() : next_index_(1) {} + explicit IndexGenerator(IndexType n) : next_index_(1) { + is_valid_.reserve(n); + } + + // 生成n个新正整数 + void Generate(size_t n, IndexType *indices) { + if (n <= 0) { + return; + } + + // 优先给出被删除的索引 + size_t count_from_freed = std::min(n, freed_indices_.size()); + for (size_t i = 0; i < count_from_freed; ++i) { + indices[i] = freed_indices_.back(); + freed_indices_.pop_back(); + // 标记为有效,确保is_valid_的大小足够 + if (indices[i] >= is_valid_.size()) { + is_valid_.resize(static_cast(indices[i]) + 1, false); // 0代表无效,1代表有效 + } + is_valid_[indices[i]] = true; // 标记为有效 + } + + // 如果还需要更多的索引,则生成新的索引 + for (size_t i = count_from_freed; i < n; ++i) { + indices[i] = next_index_++; + // 确保is_valid_的大小足够 + if (indices[i] >= is_valid_.size()) { + is_valid_.resize(static_cast(indices[i]) + 1, false); + } + is_valid_[indices[i]] = true; // 标记为有效 + } + } + + // 删除一个已经给出的正整数 + void Delete(IndexType index) { + // 检查索引是否有效且未被删除 + // 这里的检查是为了避免重复删除或删除未生成的索引 + if (index < is_valid_.size() && is_valid_[index] == true) { + is_valid_[index] = false; // 标记为无效 + freed_indices_.push_back(index); // 添加到已删除列表中 + } + } + + // 检查一个正整数是否之前已经被给出,并且没有被删除 + bool IsValid(IndexType index) const { + // 如果索引超出is_valid_的范围,或者对应的位置是0,则认为无效 + return index < is_valid_.size() && is_valid_[index] == true; + } + +private: + IndexType next_index_; // 下一个将要生成的正整数 + std::vector freed_indices_; // 存储被删除的索引 + std::vector is_valid_; // 标记索引是否有效。0代表无效,1代表有效。 +}; + +#endif //INDEXGENERATOR_H