From d553e363a7668ef091d95bc2b1ecd481b71ed601 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 8 Jun 2026 14:08:35 +0800 Subject: [PATCH] [Feat] (MG_Impl/GL_Buffer, MG_State/BufferState, MG_Backend): implement persistent mapping --- .../DirectGLES/BackendObject_DirectGLES.cpp | 2 +- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 1 + MobileGL/MG_Backend/DirectGLES/Managers.cpp | 9 +- MobileGL/MG_Backend/DirectGLES/Managers.h | 4 + .../BackendObject_DirectVulkan.cpp | 2 +- .../DirectVulkan/Renderer/UniformManager.cpp | 1 + .../DirectVulkan/Renderer/VkBufferManager.cpp | 1 + .../DirectVulkan/Renderer/VkBufferObject.cpp | 8 + .../DirectVulkan/Renderer/VulkanRenderer.cpp | 4 +- MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp | 736 ++++++++++++++++-- MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h | 13 + .../MG_Impl/GLImpl/Exporting/Definitions.cpp | 57 +- MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.cpp | 125 ++- MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.h | 3 + .../GLState/BufferState/BufferObject.cpp | 95 ++- .../GLState/BufferState/BufferObject.h | 7 + MobileGL/MG_Test/Buffer/BufferTest.cpp | 151 ++++ MobileGL/MG_Test/Buffer/CMakeLists.txt | 7 + 18 files changed, 1098 insertions(+), 128 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp index 119ba42b..3bb3f6bf 100644 --- a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp @@ -132,7 +132,7 @@ namespace MobileGL::MG_Backend::DirectGLES { V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader, E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store, E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object, - E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture}, + E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture, E_GL_ARB_buffer_storage}, .IsCompatibilityProfile = false // Is Compatibility Profile }, .StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 05447c79..11438aaa 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -106,6 +106,7 @@ namespace MobileGL::MG_Backend::DirectGLES { namespace BufferImpl { void CreateAndSyncBufferObject(const SharedPtr& bufferObject) { + bufferObject->MarkPersistentMappedRangeDirty(); if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return; const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject.get()); diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 144aca17..c8d77b6b 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -748,7 +748,11 @@ namespace MobileGL::MG_Backend::DirectGLES { SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapS, GL_TEXTURE_WRAP_S, WrapMode) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapT, GL_TEXTURE_WRAP_T, WrapMode) - SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapR, GL_TEXTURE_WRAP_R, WrapMode) + if (SupportsWrapR(targetInternal)) { + SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapR, GL_TEXTURE_WRAP_R, WrapMode) + } else { + m_cacheSamplerParameters.wrapR = samplerParams.wrapR; + } SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareFunc, GL_TEXTURE_COMPARE_FUNC, CompareFunc) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareMode, GL_TEXTURE_COMPARE_MODE, CompareMode) if (m_cacheSamplerParameters.minLod != samplerParams.minLod) { @@ -1032,6 +1036,9 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(), MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(), m_syncedFrontendAttachmentVersions[i]); + if (!attachmentObject.IsTexture() && !attachmentObject.IsRenderbuffer()) { + continue; + } GLint objectType = GL_NONE; g_GLESFuncs.glGetFramebufferAttachmentParameteriv( glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType); diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h index fccdc41a..17876da6 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.h +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -166,6 +166,10 @@ namespace MobileGL::MG_Backend::DirectGLES { return true; } + inline Bool SupportsWrapR(TextureTarget target) { + return target == TextureTarget::Texture3D || target == TextureTarget::TextureCubeMap; + } + struct StateTextureBasicInfo { // Used for tracking texture state changes TextureInternalFormat internalFormat = TextureInternalFormat::Unknown; SizeT width = 0; diff --git a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp index 21e1279d..e4b9d1b9 100644 --- a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp @@ -125,7 +125,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader, E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store, E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object, - E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture}, + E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture, E_GL_ARB_buffer_storage}, .IsCompatibilityProfile = false // Is Compatibility Profile }, .StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp index 0a39abdc..5fb54fb1 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp @@ -615,6 +615,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { MOBILEGL_ASSERT(bufferObject != nullptr, "ResolveUniformBufferPayload: no UBO bound at frontend binding %u for block '%s'", frontendBinding, program.GetUniformBlockName(static_cast(blockIndex)).c_str()); + bufferObject->MarkPersistentMappedRangeDirty(); const auto bufferData = bufferObject->GetDataReadOnly(); MOBILEGL_ASSERT(bufferData != nullptr && !bufferData->empty(), diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp index b60f1aa8..541e009d 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp @@ -86,6 +86,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { const auto* bufferData = bufferObject->GetDataReadOnly().get(); MOBILEGL_ASSERT(bufferData != nullptr, "VkBufferManager::SyncResidentBuffer requires frontend buffer data"); + bufferObject->MarkPersistentMappedRangeDirty(); const VkDeviceSize bufferSize = static_cast(bufferObject->GetSize()); if (bufferSize == 0) { diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp index 07818111..bfd3a1a8 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp @@ -140,6 +140,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { } Memcpy(static_cast(mapped) + offset, data, static_cast(size)); + const VkResult flushResult = vmaFlushAllocation(m_allocator, m_allocation, offset, size); + if (flushResult != VK_SUCCESS) { + MGLOG_E("VkBufferObject::Upload failed: vmaFlushAllocation returned %d", flushResult); + if (!wasMapped) { + Unmap(); + } + return false; + } if (!wasMapped) { Unmap(); } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 29455b7c..3433f90b 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -1316,7 +1316,7 @@ void main() { .minUploadBytes = 4 * 1024 * 1024, .transientMemoryUsage = VMA_MEMORY_USAGE_AUTO, .transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, - .transientPersistentMapping = false, + .transientPersistentMapping = true, }); MOBILEGL_ASSERT(succeeded, "VkBufferManager initialization failed."); m_textureManager = MakeUnique(); @@ -1537,6 +1537,7 @@ void main() { auto sourceBufferShared = MG_State::pGLContext->GetBufferObject(sourceBuffer->GetExternalIndex()); MOBILEGL_ASSERT(sourceBufferShared != nullptr, "UploadAndBindVertexStreams failed to resolve shared source buffer"); + sourceBufferShared->MarkPersistentMappedRangeDirty(); BufferSlice slice{}; const Bool isDirty = (sourceBufferShared->GetChangeBits() & BufferChangeBits::DirtyBit); const Uint64 changeSerial = sourceBufferShared->GetChangeSerial(); @@ -1641,6 +1642,7 @@ void main() { BufferSlice slice{}; auto indexBufferShared = MG_State::pGLContext->GetBufferObject(indexBuffer->GetExternalIndex()); MOBILEGL_ASSERT(indexBufferShared != nullptr, "UploadAndBindIndexBuffer failed to resolve shared EBO"); + indexBufferShared->MarkPersistentMappedRangeDirty(); const Bool isDirty = (indexBufferShared->GetChangeBits() & BufferChangeBits::DirtyBit); const Uint64 changeSerial = indexBufferShared->GetChangeSerial(); const SizeT indexBufferSize = indexBufferShared->GetSize(); diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp index 7f4fd073..329b747f 100644 --- a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp @@ -16,68 +16,294 @@ namespace MobileGL::MG_Impl::GLImpl { namespace { + enum class BufferOp { + GetBufferParameteriv, + GetBufferParameteri64v, + GetBufferPointerv, + BufferStorage, + NamedBufferStorage, + NamedBufferData, + NamedBufferSubData, + MapBufferRange, + MapBuffer, + MapNamedBuffer, + MapNamedBufferRange, + UnmapNamedBuffer, + FlushMappedNamedBufferRange, + GetNamedBufferParameteriv, + GetNamedBufferParameteri64v, + GetNamedBufferPointerv, + }; + + const char* GetBufferOpName(BufferOp op) { + switch (op) { + case BufferOp::GetBufferParameteriv: + return "GetBufferParameteriv"; + case BufferOp::GetBufferParameteri64v: + return "GetBufferParameteri64v"; + case BufferOp::GetBufferPointerv: + return "GetBufferPointerv"; + case BufferOp::BufferStorage: + return "BufferStorage"; + case BufferOp::NamedBufferStorage: + return "NamedBufferStorage"; + case BufferOp::NamedBufferData: + return "NamedBufferData"; + case BufferOp::NamedBufferSubData: + return "NamedBufferSubData"; + case BufferOp::MapBufferRange: + return "MapBufferRange"; + case BufferOp::MapBuffer: + return "MapBuffer"; + case BufferOp::MapNamedBuffer: + return "MapNamedBuffer"; + case BufferOp::MapNamedBufferRange: + return "MapNamedBufferRange"; + case BufferOp::UnmapNamedBuffer: + return "UnmapNamedBuffer"; + case BufferOp::FlushMappedNamedBufferRange: + return "FlushMappedNamedBufferRange"; + case BufferOp::GetNamedBufferParameteriv: + return "GetNamedBufferParameteriv"; + case BufferOp::GetNamedBufferParameteri64v: + return "GetNamedBufferParameteri64v"; + case BufferOp::GetNamedBufferPointerv: + return "GetNamedBufferPointerv"; + default: + return "Buffer"; + } + } + auto& GetBufferBindingSlot(BufferTarget target) { if (target == BufferTarget::Index) { return MG_State::pGLContext->GetBoundVertexArray()->GetIndexBufferBindingSlot(); } return MG_State::pGLContext->GetBufferBindingSlot(target); } - } // namespace - void GetBufferParameteriv_State(GLenum target, GLenum pname, GLint* params) { - if (!params) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidValue, MakeUnique("MG_Impl/GLImpl", "GetBufferParameteriv_State", - "Params pointer cannot be null.")); - return; + SharedPtr GetBoundBufferObject(GLenum target, BufferOp op) { + BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); + if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return nullptr; + + auto& bindingSlot = GetBufferBindingSlot(bufferTarget); + auto& bufferObject = bindingSlot.GetBoundObject(); + if (!bufferObject) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "Buffer target is bound to no buffer object.")); + return nullptr; + } + return bufferObject; } - BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); - if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return; - - auto& bindingSlot = GetBufferBindingSlot(bufferTarget); - - auto& bufferObject = bindingSlot.GetBoundObject(); - if (!bufferObject) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidOperation, - MakeUnique("MG_Impl/GLImpl", "GetBufferParameteriv_State", - "Buffer target is bound to no buffer object.")); - return; + SharedPtr GetNamedBufferObject(GLuint buffer, BufferOp op) { + if (!BufferImpl::ValidateBufferName(buffer, false)) return nullptr; + if (!MG_State::pGLContext->ValidateBufferObject(buffer)) { + MG_State::pGLContext->CreateBufferObject(buffer); + } + auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer); + if (!bufferObject) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + std::format("Buffer object {} does not exist.", buffer))); + } + return bufferObject; } - switch (pname) { - case GL_BUFFER_SIZE: - *params = static_cast(bufferObject->GetSize()); - break; - case GL_BUFFER_USAGE: - *params = (GLint)MG_Util::ConvertBufferUsageToGLEnum(bufferObject->GetUsage()); - break; - case GL_BUFFER_ACCESS: - if (bufferObject->IsMapped()) { - auto access = bufferObject->GetMappingAccess(); - if (access & BufferMappingAccessBit::Read && access & BufferMappingAccessBit::Write) { - *params = GL_READ_WRITE; - } else if (access & BufferMappingAccessBit::Read) { - *params = GL_READ_ONLY; - } else if (access & BufferMappingAccessBit::Write) { - *params = GL_WRITE_ONLY; + Bool ValidateStorageFlags(GLbitfield flags, BufferOp op) { + constexpr GLbitfield validFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | + GL_MAP_COHERENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_CLIENT_STORAGE_BIT; + if ((flags & ~validFlags) != 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + std::format("Invalid buffer storage flags: 0x{:X}", flags))); + return false; + } + + if ((flags & GL_MAP_PERSISTENT_BIT) && !(flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "GL_MAP_PERSISTENT_BIT requires GL_MAP_READ_BIT or GL_MAP_WRITE_BIT.")); + return false; + } + + if ((flags & GL_MAP_COHERENT_BIT) && !(flags & GL_MAP_PERSISTENT_BIT)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "GL_MAP_COHERENT_BIT requires GL_MAP_PERSISTENT_BIT.")); + return false; + } + return true; + } + + Bool ValidateImmutableMapAccess(const SharedPtr& bufferObject, + Flags accessBits, BufferOp op) { + if (!bufferObject->IsImmutableStorage()) { + if (accessBits & (BufferMappingAccessBit::Persistent | BufferMappingAccessBit::Coherent)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique( + "MG_Impl/GLImpl", GetBufferOpName(op), + "Persistent or coherent mapping requires immutable buffer storage.")); + return false; + } + return true; + } + + const GLbitfield storageFlags = bufferObject->GetStorageFlags(); + if ((accessBits & BufferMappingAccessBit::Read) && !(storageFlags & GL_MAP_READ_BIT)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "GL_MAP_READ_BIT is not allowed by buffer storage flags.")); + return false; + } + if ((accessBits & BufferMappingAccessBit::Write) && !(storageFlags & GL_MAP_WRITE_BIT)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "GL_MAP_WRITE_BIT is not allowed by buffer storage flags.")); + return false; + } + if ((accessBits & BufferMappingAccessBit::Persistent) && !(storageFlags & GL_MAP_PERSISTENT_BIT)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "GL_MAP_PERSISTENT_BIT is not allowed by buffer storage flags.")); + return false; + } + if ((accessBits & BufferMappingAccessBit::Coherent) && !(storageFlags & GL_MAP_COHERENT_BIT)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "GL_MAP_COHERENT_BIT is not allowed by buffer storage flags.")); + return false; + } + return true; + } + + void GetBufferParameteriv_Object(const SharedPtr& bufferObject, GLenum pname, + GLint* params, BufferOp op) { + if (!params) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "Params pointer cannot be null.")); + return; + } + + switch (pname) { + case GL_BUFFER_SIZE: + *params = static_cast(bufferObject->GetSize()); + break; + case GL_BUFFER_USAGE: + *params = (GLint)MG_Util::ConvertBufferUsageToGLEnum(bufferObject->GetUsage()); + break; + case GL_BUFFER_ACCESS: + if (bufferObject->IsMapped()) { + auto access = bufferObject->GetMappingAccess(); + if (access & BufferMappingAccessBit::Read && access & BufferMappingAccessBit::Write) { + *params = GL_READ_WRITE; + } else if (access & BufferMappingAccessBit::Read) { + *params = GL_READ_ONLY; + } else if (access & BufferMappingAccessBit::Write) { + *params = GL_WRITE_ONLY; + } else { + *params = 0; + } } else { *params = 0; } - } else { - *params = 0; + break; + case GL_BUFFER_MAPPED: + *params = bufferObject->IsMapped() ? GL_TRUE : GL_FALSE; + break; + case GL_BUFFER_IMMUTABLE_STORAGE: + *params = bufferObject->IsImmutableStorage() ? GL_TRUE : GL_FALSE; + break; + case GL_BUFFER_STORAGE_FLAGS: + *params = static_cast(bufferObject->GetStorageFlags()); + break; + case GL_BUFFER_MAP_OFFSET: + *params = static_cast(bufferObject->GetMappedRange().start); + break; + case GL_BUFFER_MAP_LENGTH: + *params = static_cast(bufferObject->GetMappedRange().end - bufferObject->GetMappedRange().start); + break; + default: + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + std::format("Invalid pname enum: 0x{:X}", pname))); + break; } - break; - case GL_BUFFER_MAPPED: - *params = bufferObject->IsMapped() ? GL_TRUE : GL_FALSE; - break; - default: - MG_State::pGLContext->RecordError( - ErrorCode::InvalidEnum, MakeUnique("MG_Impl/GLImpl", "GetBufferParameteriv_State", - std::format("Invalid pname enum: 0x{:X}", pname))); - break; } + + void GetBufferParameteri64v_Object(const SharedPtr& bufferObject, GLenum pname, + GLint64* params, BufferOp op) { + if (!params) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "Params pointer cannot be null.")); + return; + } + + switch (pname) { + case GL_BUFFER_SIZE: + *params = static_cast(bufferObject->GetSize()); + break; + case GL_BUFFER_MAP_OFFSET: + *params = static_cast(bufferObject->GetMappedRange().start); + break; + case GL_BUFFER_MAP_LENGTH: + *params = static_cast(bufferObject->GetMappedRange().end - bufferObject->GetMappedRange().start); + break; + default: { + GLint value = 0; + GetBufferParameteriv_Object(bufferObject, pname, &value, op); + *params = static_cast(value); + break; + } + } + } + + void GetBufferPointerv_Object(const SharedPtr& bufferObject, GLenum pname, + void** params, BufferOp op) { + if (!params) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + "Params pointer cannot be null.")); + return; + } + if (pname != GL_BUFFER_MAP_POINTER) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, MakeUnique("MG_Impl/GLImpl", GetBufferOpName(op), + std::format("Invalid pname enum: 0x{:X}", pname))); + return; + } + *params = bufferObject->GetMappedPointer(); + } + } // namespace + + void GetBufferParameteriv_State(GLenum target, GLenum pname, GLint* params) { + auto bufferObject = GetBoundBufferObject(target, BufferOp::GetBufferParameteriv); + if (!bufferObject) return; + GetBufferParameteriv_Object(bufferObject, pname, params, BufferOp::GetBufferParameteriv); + } + + void GetBufferParameteri64v_State(GLenum target, GLenum pname, GLint64* params) { + auto bufferObject = GetBoundBufferObject(target, BufferOp::GetBufferParameteri64v); + if (!bufferObject) return; + GetBufferParameteri64v_Object(bufferObject, pname, params, BufferOp::GetBufferParameteri64v); + } + + void GetBufferPointerv_State(GLenum target, GLenum pname, void** params) { + auto bufferObject = GetBoundBufferObject(target, BufferOp::GetBufferPointerv); + if (!bufferObject) return; + GetBufferPointerv_Object(bufferObject, pname, params, BufferOp::GetBufferPointerv); } void DeleteBuffers_State(GLsizei n, const GLuint* buffers) { @@ -133,10 +359,11 @@ namespace MobileGL::MG_Impl::GLImpl { return; } - if (offset + length > bufferObject->GetSize()) { + const auto mappedRange = bufferObject->GetMappedRange(); + if (static_cast(offset) + static_cast(length) > mappedRange.end - mappedRange.start) { MG_State::pGLContext->RecordError( ErrorCode::InvalidValue, MakeUnique("MG_Impl/GLImpl", "FlushMappedBufferRange_State", - "Offset and length exceed buffer size.")); + "Offset and length exceed mapped range.")); return; } @@ -250,18 +477,24 @@ namespace MobileGL::MG_Impl::GLImpl { } } - const auto storageFlags = BufferMappingAccessBit::Persistent | BufferMappingAccessBit::Coherent; - auto requiredFlags = accessBits & storageFlags; - if (requiredFlags) { - // TODO: check if the buffer data is created by BufferStorage and its flags after its - // implementation + if ((accessBits & BufferMappingAccessBit::Persistent) && !(accessBits & (BufferMappingAccessBit::Read | BufferMappingAccessBit::Write))) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, MakeUnique("MG_Impl/GLImpl", "MapBufferRange_State", - "Access flags require matching storage flags in buffer.")); + "GL_MAP_PERSISTENT_BIT requires GL_MAP_READ_BIT or GL_MAP_WRITE_BIT.")); return nullptr; } + if ((accessBits & BufferMappingAccessBit::Coherent) && !(accessBits & BufferMappingAccessBit::Persistent)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "MapBufferRange_State", + "GL_MAP_COHERENT_BIT requires GL_MAP_PERSISTENT_BIT.")); + return nullptr; + } + + if (!ValidateImmutableMapAccess(bufferObject, accessBits, BufferOp::MapBufferRange)) return nullptr; + if (bufferObject->IsMapped()) { const auto invalidateFlags = BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer; @@ -319,6 +552,11 @@ namespace MobileGL::MG_Impl::GLImpl { return nullptr; } + Flags accessBits = BufferMappingAccessBit::Null; + if (readable) accessBits |= BufferMappingAccessBit::Read; + if (writable) accessBits |= BufferMappingAccessBit::Write; + if (!ValidateImmutableMapAccess(bufferObject, accessBits, BufferOp::MapBuffer)) return nullptr; + void* result = bufferObject->AcquireMemory(true, readable, writable); if (!result) { MG_State::pGLContext->RecordError( @@ -421,18 +659,35 @@ namespace MobileGL::MG_Impl::GLImpl { return; } - SizeT bufferSize = bufferObject->GetSize(); - Range1D mappedRange = bufferObject->GetMappedRange(); - if ((offset < mappedRange.end) && (offset + size > mappedRange.start)) { + if (bufferObject->IsImmutableStorage() && !(bufferObject->GetStorageFlags() & GL_DYNAMIC_STORAGE_BIT)) { MG_State::pGLContext->RecordError( - ErrorCode::InvalidValue, - MakeUnique( - "MG_Impl/GLImpl", "BufferSubData_State", - "Offset and size must not overlap with the mapped range of the buffer object.")); + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "BufferSubData_State", + "Immutable buffer storage was not created with GL_DYNAMIC_STORAGE_BIT.")); return; } + SizeT bufferSize = bufferObject->GetSize(); + if (static_cast(offset) + static_cast(size) > bufferSize) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "BufferSubData_State", + "Offset and size exceed buffer size.")); + return; + } + + Range1D mappedRange = bufferObject->GetMappedRange(); auto mappingAccess = bufferObject->GetMappingAccess(); + if (bufferObject->IsMapped() && !(mappingAccess & BufferMappingAccessBit::Persistent) && + (offset < mappedRange.end) && (offset + size > mappedRange.start)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique( + "MG_Impl/GLImpl", "BufferSubData_State", + "Cannot modify a non-persistently mapped buffer object.")); + return; + } + if (bufferObject->IsMapped() && !(mappingAccess & BufferMappingAccessBit::Persistent)) { Range1D mappedRange = bufferObject->GetMappedRange(); if (offset + size >= mappedRange.start) { @@ -474,6 +729,14 @@ namespace MobileGL::MG_Impl::GLImpl { return; } + if (bufferObject->IsImmutableStorage()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "BufferData_State", + "Cannot call glBufferData on immutable buffer storage.")); + return; + } + bufferObject->SetUsage(bufferUsage); bufferObject->Resize(size); if (data) { @@ -481,6 +744,305 @@ namespace MobileGL::MG_Impl::GLImpl { } } + void BufferStorage_State(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) { + if (size <= 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "BufferStorage_State", "Size must be positive.")); + return; + } + if (!ValidateStorageFlags(flags, BufferOp::BufferStorage)) return; + + auto bufferObject = GetBoundBufferObject(target, BufferOp::BufferStorage); + if (!bufferObject) return; + if (bufferObject->IsImmutableStorage()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "BufferStorage_State", + "Buffer already has immutable storage.")); + return; + } + bufferObject->AllocateImmutableStorage(static_cast(size), data, flags); + } + + void NamedBufferStorage_State(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) { + if (size <= 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "NamedBufferStorage_State", "Size must be positive.")); + return; + } + if (!ValidateStorageFlags(flags, BufferOp::NamedBufferStorage)) return; + + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::NamedBufferStorage); + if (!bufferObject) return; + if (bufferObject->IsImmutableStorage()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "NamedBufferStorage_State", + "Buffer already has immutable storage.")); + return; + } + bufferObject->AllocateImmutableStorage(static_cast(size), data, flags); + } + + void NamedBufferData_State(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) { + if (size < 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "NamedBufferData_State", "Size must be non-negative.")); + return; + } + + BufferUsage bufferUsage = MG_Util::ConvertGLEnumToBufferUsage(usage); + if (!BufferImpl::ValidateBufferUsage(bufferUsage)) return; + + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::NamedBufferData); + if (!bufferObject) return; + + if (bufferObject->IsImmutableStorage()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "NamedBufferData_State", + "Cannot call glNamedBufferData on immutable buffer storage.")); + return; + } + + bufferObject->SetUsage(bufferUsage); + bufferObject->Resize(size); + if (data) { + bufferObject->UploadData({(void*)data, (SizeT)size}, 0); + } + } + + void NamedBufferSubData_State(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) { + if (!data) { + MG_State::pGLContext->RecordError( + ErrorCode::NoError, + MakeUnique("MG_Impl/GLImpl", "NamedBufferSubData_State", + "Data pointer cannot be null.")); + return; + } + if (size < 0 || offset < 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "NamedBufferSubData_State", + "Offset and size must be non-negative.")); + return; + } + + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::NamedBufferSubData); + if (!bufferObject) return; + + if (bufferObject->IsImmutableStorage() && !(bufferObject->GetStorageFlags() & GL_DYNAMIC_STORAGE_BIT)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "NamedBufferSubData_State", + "Immutable buffer storage was not created with GL_DYNAMIC_STORAGE_BIT.")); + return; + } + if (static_cast(offset) + static_cast(size) > bufferObject->GetSize()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "NamedBufferSubData_State", + "Offset and size exceed buffer size.")); + return; + } + const auto mappingAccess = bufferObject->GetMappingAccess(); + const auto mappedRange = bufferObject->GetMappedRange(); + if (bufferObject->IsMapped() && !(mappingAccess & BufferMappingAccessBit::Persistent) && + (offset < mappedRange.end) && (offset + size > mappedRange.start)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "NamedBufferSubData_State", + "Cannot modify a non-persistently mapped buffer object.")); + return; + } + + bufferObject->UploadSubData({(void*)data, (SizeT)size}, offset); + } + + void* MapNamedBuffer_State(GLuint buffer, GLenum access) { + Bool readable = access == GL_READ_ONLY || access == GL_READ_WRITE; + Bool writable = access == GL_WRITE_ONLY || access == GL_READ_WRITE; + if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, + MakeUnique("MG_Impl/GLImpl", "MapNamedBuffer_State", + "Access must be one of GL_READ_ONLY, GL_WRITE_ONLY, or GL_READ_WRITE.")); + return nullptr; + } + + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::MapNamedBuffer); + if (!bufferObject) return nullptr; + if (bufferObject->IsMapped()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "MapNamedBuffer_State", + "Cannot map a buffer object that is already mapped.")); + return nullptr; + } + + Flags accessBits = BufferMappingAccessBit::Null; + if (readable) accessBits |= BufferMappingAccessBit::Read; + if (writable) accessBits |= BufferMappingAccessBit::Write; + if (!ValidateImmutableMapAccess(bufferObject, accessBits, BufferOp::MapNamedBuffer)) return nullptr; + + return bufferObject->AcquireMemory(true, readable, writable); + } + + void* MapNamedBufferRange_State(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) { + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::MapNamedBufferRange); + if (!bufferObject) return nullptr; + + if (length < 0 || offset < 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "MapNamedBufferRange_State", + "Offset and length must be non-negative.")); + return nullptr; + } + if (length == 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "MapNamedBufferRange_State", + "Length must be greater than zero.")); + return nullptr; + } + if (static_cast(offset) + static_cast(length) > bufferObject->GetSize()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "MapNamedBufferRange_State", + "Offset and length exceed buffer size.")); + return nullptr; + } + + auto accessBits = MG_Util::ConvertGLEnumToBufferMappingAccess(access); + if (!BufferImpl::ValidateBufferMappingAccess(accessBits)) return nullptr; + if (!(accessBits & (BufferMappingAccessBit::Read | BufferMappingAccessBit::Write))) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "MapNamedBufferRange_State", + "At least one of GL_MAP_READ_BIT or GL_MAP_WRITE_BIT must be set.")); + return nullptr; + } + if (accessBits & BufferMappingAccessBit::Read) { + const auto invalidFlags = BufferMappingAccessBit::InvalidateRange | + BufferMappingAccessBit::InvalidateBuffer | BufferMappingAccessBit::Unsynchronized; + if (accessBits & invalidFlags) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "MapNamedBufferRange_State", + "GL_MAP_READ_BIT cannot be combined with invalidation or unsynchronized flags.")); + return nullptr; + } + } + if ((accessBits & BufferMappingAccessBit::FlushExplicit) && !(accessBits & BufferMappingAccessBit::Write)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "MapNamedBufferRange_State", + "GL_MAP_FLUSH_EXPLICIT_BIT requires GL_MAP_WRITE_BIT.")); + return nullptr; + } + if ((accessBits & BufferMappingAccessBit::Persistent) && !(accessBits & (BufferMappingAccessBit::Read | BufferMappingAccessBit::Write))) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "MapNamedBufferRange_State", + "GL_MAP_PERSISTENT_BIT requires GL_MAP_READ_BIT or GL_MAP_WRITE_BIT.")); + return nullptr; + } + if ((accessBits & BufferMappingAccessBit::Coherent) && !(accessBits & BufferMappingAccessBit::Persistent)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "MapNamedBufferRange_State", + "GL_MAP_COHERENT_BIT requires GL_MAP_PERSISTENT_BIT.")); + return nullptr; + } + if (!ValidateImmutableMapAccess(bufferObject, accessBits, BufferOp::MapNamedBufferRange)) return nullptr; + + if (bufferObject->IsMapped()) { + const auto invalidateFlags = + BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer; + if (!(accessBits & invalidateFlags)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "MapNamedBufferRange_State", + "Cannot map a buffer object that is already mapped.")); + return nullptr; + } + } + + return bufferObject->AcquireMemoryRange({static_cast(offset), static_cast(offset + length)}, + accessBits); + } + + GLboolean UnmapNamedBuffer_State(GLuint buffer) { + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::UnmapNamedBuffer); + if (!bufferObject) return GL_FALSE; + if (!bufferObject->IsMapped()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "UnmapNamedBuffer_State", + "Cannot unmap a buffer object that is not mapped.")); + return GL_FALSE; + } + bufferObject->ReleaseMemory(); + return GL_TRUE; + } + + void FlushMappedNamedBufferRange_State(GLuint buffer, GLintptr offset, GLsizeiptr length) { + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::FlushMappedNamedBufferRange); + if (!bufferObject) return; + if (length < 0 || offset < 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "FlushMappedNamedBufferRange_State", + "Offset and length must be non-negative.")); + return; + } + if (!bufferObject->IsMapped()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "FlushMappedNamedBufferRange_State", + "Cannot flush a buffer object that is not mapped.")); + return; + } + const auto mappedRange = bufferObject->GetMappedRange(); + if (static_cast(offset) + static_cast(length) > mappedRange.end - mappedRange.start) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "FlushMappedNamedBufferRange_State", + "Offset and length exceed mapped range.")); + return; + } + if (!(bufferObject->GetMappingAccess() & BufferMappingAccessBit::FlushExplicit)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "FlushMappedNamedBufferRange_State", + "Cannot flush a buffer object that is not mapped with GL_MAP_FLUSH_EXPLICIT_BIT.")); + return; + } + bufferObject->FlushMemoryRange(static_cast(offset), static_cast(length)); + } + + void GetNamedBufferParameteriv_State(GLuint buffer, GLenum pname, GLint* params) { + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::GetNamedBufferParameteriv); + if (!bufferObject) return; + GetBufferParameteriv_Object(bufferObject, pname, params, BufferOp::GetNamedBufferParameteriv); + } + + void GetNamedBufferParameteri64v_State(GLuint buffer, GLenum pname, GLint64* params) { + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::GetNamedBufferParameteri64v); + if (!bufferObject) return; + GetBufferParameteri64v_Object(bufferObject, pname, params, BufferOp::GetNamedBufferParameteri64v); + } + + void GetNamedBufferPointerv_State(GLuint buffer, GLenum pname, void** params) { + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::GetNamedBufferPointerv); + if (!bufferObject) return; + GetBufferPointerv_Object(bufferObject, pname, params, BufferOp::GetNamedBufferPointerv); + } + void BindBuffer_State(GLenum target, GLuint buffer) { if (!BufferImpl::ValidateBufferName(buffer, true)) return; BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); @@ -558,6 +1120,14 @@ namespace MobileGL::MG_Impl::GLImpl { GetBufferParameteriv_State(target, pname, params); } + void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params) { + GetBufferParameteri64v_State(target, pname, params); + } + + void GetBufferPointerv(GLenum target, GLenum pname, void** params) { + GetBufferPointerv_State(target, pname, params); + } + GLboolean IsBuffer(GLuint buffer) { return IsBuffer_State(buffer); } @@ -582,6 +1152,50 @@ namespace MobileGL::MG_Impl::GLImpl { return MapBuffer_State(target, access); } + void BufferStorage(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) { + BufferStorage_State(target, size, data, flags); + } + + void NamedBufferStorage(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) { + NamedBufferStorage_State(buffer, size, data, flags); + } + + void NamedBufferData(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) { + NamedBufferData_State(buffer, size, data, usage); + } + + void NamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) { + NamedBufferSubData_State(buffer, offset, size, data); + } + + void* MapNamedBuffer(GLuint buffer, GLenum access) { + return MapNamedBuffer_State(buffer, access); + } + + void* MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) { + return MapNamedBufferRange_State(buffer, offset, length, access); + } + + GLboolean UnmapNamedBuffer(GLuint buffer) { + return UnmapNamedBuffer_State(buffer); + } + + void FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length) { + FlushMappedNamedBufferRange_State(buffer, offset, length); + } + + void GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint* params) { + GetNamedBufferParameteriv_State(buffer, pname, params); + } + + void GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, GLint64* params) { + GetNamedBufferParameteri64v_State(buffer, pname, params); + } + + void GetNamedBufferPointerv(GLuint buffer, GLenum pname, void** params) { + GetNamedBufferPointerv_State(buffer, pname, params); + } + // FIXME: this should be a "backend" function void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h index c24f9eea..48f48fbe 100644 --- a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h +++ b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h @@ -12,12 +12,25 @@ namespace MobileGL::MG_Impl::GLImpl { /* @INSERTION_POINT:FUNCTION_DECLARATION@ */ void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params); + void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params); + void GetBufferPointerv(GLenum target, GLenum pname, void** params); GLboolean IsBuffer(GLuint buffer); void DeleteBuffers(GLsizei n, const GLuint* buffers); void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); GLboolean UnmapBuffer(GLenum target); void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); void* MapBuffer(GLenum target, GLenum access); + void BufferStorage(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags); + void NamedBufferStorage(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags); + void NamedBufferData(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage); + void NamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data); + void* MapNamedBuffer(GLuint buffer, GLenum access); + void* MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); + GLboolean UnmapNamedBuffer(GLuint buffer); + void FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length); + void GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint* params); + void GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, GLint64* params); + void GetNamedBufferPointerv(GLuint buffer, GLenum pname, void** params); void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); diff --git a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp index 76a896a6..fd332bb6 100644 --- a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp +++ b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp @@ -10,6 +10,7 @@ #include "../Buffer/GL_Buffer.h" #include "../Getter/GL_Getter.h" #include "../Sampler/GL_Sampler.h" +#include "../Sync/GL_Sync.h" #include "../Texture/GL_Texture.h" #include "../Drawing/GL_Drawing.h" #include "../Program/GL_Program.h" @@ -214,7 +215,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, EndQuery, GLenum target) DECLARE_GL_FUNCTION DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryiv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryiv, target, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryObjectuiv, id, pname, params) DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLboolean, UnmapBuffer, target) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferPointerv, target, pname, params) +DECLARE_GL_FUNCTION_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBufferPointerv, target, pname, params) DECLARE_GL_FUNCTION_HEAD(void, DrawBuffers, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawBuffers, n, bufs) DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2x3fv, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix3x2fv, location, count, transpose, value) @@ -268,15 +269,15 @@ DECLARE_GL_FUNCTION_HEAD(void, GetActiveUniformBlockName, GLuint program, GLuint DECLARE_GL_FUNCTION_HEAD(void, UniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformBlockBinding, program, uniformBlockIndex, uniformBlockBinding) DECLARE_GL_FUNCTION_HEAD(void, DrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysInstanced, mode, first, count, instancecount) DECLARE_GL_FUNCTION_HEAD(void, DrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsInstanced, mode, count, type, indices, instancecount) -DECLARE_GL_FUNCTION_STUB_HEAD(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END(GLsync, FenceSync, condition, flags) -DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsSync, GLsync sync) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsSync, sync) -DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteSync, sync) -DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, ClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_STUB_END(GLenum, ClientWaitSync, sync, flags, timeout) -DECLARE_GL_FUNCTION_STUB_HEAD(void, WaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, WaitSync, sync, flags, timeout) +DECLARE_GL_FUNCTION_HEAD(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_END(GLsync, FenceSync, condition, flags) +DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSync, GLsync sync) DECLARE_GL_FUNCTION_END(GLboolean, IsSync, sync) +DECLARE_GL_FUNCTION_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSync, sync) +DECLARE_GL_FUNCTION_HEAD(GLenum, ClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END(GLenum, ClientWaitSync, sync, flags, timeout) +DECLARE_GL_FUNCTION_HEAD(void, WaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END_NO_RETURN(void, WaitSync, sync, flags, timeout) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInteger64v, GLenum pname, GLint64* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInteger64v, pname, data) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetSynciv, sync, pname, bufSize, length, values) +DECLARE_GL_FUNCTION_HEAD(void, GetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetSynciv, sync, pname, bufSize, length, values) DECLARE_GL_FUNCTION_HEAD(void, GetInteger64i_v, GLenum target, GLuint index, GLint64* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetInteger64i_v, target, index, data) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferParameteri64v, GLenum target, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferParameteri64v, target, pname, params) +DECLARE_GL_FUNCTION_HEAD(void, GetBufferParameteri64v, GLenum target, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBufferParameteri64v, target, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GenSamplers, GLsizei count, GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenSamplers, count, samplers) DECLARE_GL_FUNCTION_HEAD(void, DeleteSamplers, GLsizei count, const GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSamplers, count, samplers) DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSampler, GLuint sampler) DECLARE_GL_FUNCTION_END(GLboolean, IsSampler, sampler) @@ -979,7 +980,7 @@ DECLARE_GL_FUNCTION_HEAD(GLint, GetProgramResourceLocationIndex, GLuint program, DECLARE_GL_FUNCTION_HEAD(void, ShaderStorageBlockBinding, GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ShaderStorageBlockBinding, program, storageBlockIndex, storageBlockBinding) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureView, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureView, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribLFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribLFormat, attribindex, size, type, relativeoffset) -DECLARE_GL_FUNCTION_STUB_HEAD(void, BufferStorage, GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BufferStorage, target, size, data, flags) +DECLARE_GL_FUNCTION_HEAD(void, BufferStorage, GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferStorage, target, size, data, flags) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexImage, GLuint texture, GLint level, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexImage, texture, level, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffersBase, GLenum target, GLuint first, GLsizei count, const GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffersBase, target, first, count, buffers) @@ -996,17 +997,17 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbackiv, GLuint xfb, GLenum p DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki_v, GLuint xfb, GLenum pname, GLuint index, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki_v, xfb, pname, index, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki64_v, GLuint xfb, GLenum pname, GLuint index, GLint64* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki64_v, xfb, pname, index, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateBuffers, GLsizei n, GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateBuffers, n, buffers) -DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferStorage, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags) -DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferData, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage) -DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data) +DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorage, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags) +DECLARE_GL_FUNCTION_HEAD(void, NamedBufferData, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage) +DECLARE_GL_FUNCTION_HEAD(void, NamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyNamedBufferSubData, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyNamedBufferSubData, readBuffer, writeBuffer, readOffset, writeOffset, size) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferData, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferSubData, GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data) -DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapNamedBuffer, buffer) -DECLARE_GL_FUNCTION_STUB_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, *params) +DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer) +DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length) +DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params) +DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params) +DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer) @@ -1844,11 +1845,11 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposefEXT, GLenum mode, const DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixLoadTransposedEXT, mode, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposefEXT, GLenum mode, const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposefEXT, mode, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposedEXT, mode, m) -DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferDataEXT, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferDataEXT, buffer, size, data, usage) -DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferSubDataEXT, buffer, offset, size, data) -DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapNamedBufferEXT, buffer) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameterivEXT, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameterivEXT, buffer, pname, params) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferPointervEXT, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferPointervEXT, buffer, pname, *params) +DECLARE_GL_FUNCTION_HEAD(void, NamedBufferDataEXT, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage) +DECLARE_GL_FUNCTION_HEAD(void, NamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data) +DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer) +DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameterivEXT, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params) +DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointervEXT, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubDataEXT, buffer, offset, size, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferEXT, GLuint texture, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferEXT, texture, target, internalformat, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiTexBufferEXT, GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiTexBufferEXT, texunit, target, internalformat, buffer) @@ -1923,8 +1924,8 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegervEXT, GLuint vaobj, GLe DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointervEXT, GLuint vaobj, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointervEXT, vaobj, pname, *param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegeri_vEXT, vaobj, index, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointeri_vEXT, vaobj, index, pname, *param) -DECLARE_GL_FUNCTION_STUB_HEAD(void, FlushMappedNamedBufferRangeEXT, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FlushMappedNamedBufferRangeEXT, buffer, offset, length) -DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferStorageEXT, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferStorageEXT, buffer, size, data, flags) +DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRangeEXT, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length) +DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorageEXT, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferDataEXT, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferDataEXT, buffer, internalformat, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferSubDataEXT, GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferSubDataEXT, buffer, internalformat, offset, size, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteriEXT, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteriEXT, framebuffer, pname, param) @@ -2963,8 +2964,8 @@ MOBILEGL_GL_API void glGetObjectLabelEXT(GLenum identifier, GLuint name, GLsizei } MOBILEGL_GL_API void* glMapNamedBuffer(GLuint buffer, GLenum access) { - MGLOG_W("Stub function: %s(...)", __FUNCTION__); - return nullptr; + MGLOG_D("Implementing function: %s(...)", __FUNCTION__); + return MobileGL::MG_Impl::GLImpl::MapNamedBuffer(buffer, access); } MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) { @@ -2972,8 +2973,8 @@ MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) { } MOBILEGL_GL_API void* glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) { - MGLOG_W("Stub function: %s(...)", __FUNCTION__); - return nullptr; + MGLOG_D("Implementing function: %s(...)", __FUNCTION__); + return MobileGL::MG_Impl::GLImpl::MapNamedBufferRange(buffer, offset, length, access); } MOBILEGL_GL_API void* glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) { diff --git a/MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.cpp b/MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.cpp index 4bff1afc..39c091c9 100644 --- a/MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.cpp +++ b/MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.cpp @@ -8,36 +8,121 @@ #include "GL_Sync.h" -#include "MG_State/GLState/Core.h" +#include +#include namespace MobileGL::MG_Impl::GLImpl { - GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) { - return 0; - } + namespace { + struct SyncObject { + GLenum Condition = GL_SYNC_GPU_COMMANDS_COMPLETE; + GLbitfield Flags = 0; + }; - GLenum ClientWaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) { - return 0; - } + UnorderedMap> g_syncObjects; - void DeleteSync_Backend(GLsync sync) {} + void RecordSyncError(const char* funcName, ErrorCode code, String message) { + MG_State::pGLContext->RecordError(code, + MakeUnique("MG_Impl/GLImpl", funcName, Move(message))); + } - GLsync FenceSync_State(GLenum condition, GLbitfield flags) { - return 0; - } - - GLenum ClientWaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) { - return 0; - } - - void DeleteSync_State(GLsync sync) {} + SyncObject* GetSyncObject(GLsync sync, const char* funcName) { + auto it = g_syncObjects.find(sync); + if (sync == nullptr || it == g_syncObjects.end()) { + RecordSyncError(funcName, ErrorCode::InvalidValue, "Sync object is not valid."); + return nullptr; + } + return it->second.get(); + } + } // namespace GLsync FenceSync(GLenum condition, GLbitfield flags) { - return 0; + if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) { + RecordSyncError("FenceSync", ErrorCode::InvalidEnum, "Condition must be GL_SYNC_GPU_COMMANDS_COMPLETE."); + return nullptr; + } + if (flags != 0) { + RecordSyncError("FenceSync", ErrorCode::InvalidValue, "Flags must be zero."); + return nullptr; + } + + auto syncObject = MakeUnique(); + syncObject->Condition = condition; + syncObject->Flags = flags; + GLsync handle = reinterpret_cast(syncObject.get()); + g_syncObjects[handle] = Move(syncObject); + return handle; + } + + GLboolean IsSync(GLsync sync) { + return g_syncObjects.find(sync) != g_syncObjects.end() ? GL_TRUE : GL_FALSE; } GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { - return 0; + (void)timeout; + if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) { + RecordSyncError("ClientWaitSync", ErrorCode::InvalidValue, + "Flags can only contain GL_SYNC_FLUSH_COMMANDS_BIT."); + return GL_WAIT_FAILED; + } + if (!GetSyncObject(sync, "ClientWaitSync")) return GL_WAIT_FAILED; + return GL_ALREADY_SIGNALED; } - void DeleteSync(GLsync sync) {} + void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { + if (flags != 0) { + RecordSyncError("WaitSync", ErrorCode::InvalidValue, "Flags must be zero."); + return; + } + if (timeout != GL_TIMEOUT_IGNORED) { + RecordSyncError("WaitSync", ErrorCode::InvalidValue, "Timeout must be GL_TIMEOUT_IGNORED."); + return; + } + (void)GetSyncObject(sync, "WaitSync"); + } + + void DeleteSync(GLsync sync) { + if (sync == nullptr) return; + auto it = g_syncObjects.find(sync); + if (it == g_syncObjects.end()) { + RecordSyncError("DeleteSync", ErrorCode::InvalidValue, "Sync object is not valid."); + return; + } + g_syncObjects.erase(it); + } + + void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) { + if (bufSize < 0) { + RecordSyncError("GetSynciv", ErrorCode::InvalidValue, "bufSize must be non-negative."); + return; + } + + auto* syncObject = GetSyncObject(sync, "GetSynciv"); + if (!syncObject) return; + + GLint value = 0; + switch (pname) { + case GL_OBJECT_TYPE: + value = GL_SYNC_FENCE; + break; + case GL_SYNC_STATUS: + value = GL_SIGNALED; + break; + case GL_SYNC_CONDITION: + value = static_cast(syncObject->Condition); + break; + case GL_SYNC_FLAGS: + value = static_cast(syncObject->Flags); + break; + default: + RecordSyncError("GetSynciv", ErrorCode::InvalidEnum, std::format("Invalid pname enum: 0x{:X}", pname)); + return; + } + + if (length) { + *length = bufSize > 0 && values ? 1 : 0; + } + if (bufSize > 0 && values) { + values[0] = value; + } + } } // namespace MobileGL::MG_Impl::GLImpl diff --git a/MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.h b/MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.h index 356967da..d9a0dc87 100644 --- a/MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.h +++ b/MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.h @@ -11,6 +11,9 @@ namespace MobileGL::MG_Impl::GLImpl { GLsync FenceSync(GLenum condition, GLbitfield flags); + GLboolean IsSync(GLsync sync); GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); + void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); void DeleteSync(GLsync sync); + void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values); } // namespace MobileGL::MG_Impl::GLImpl diff --git a/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp b/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp index e625803b..9fc9b250 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp +++ b/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp @@ -18,19 +18,41 @@ namespace MobileGL::MG_State::GLState { } void BufferObject::Resize(SizeT size) { + ReleaseMemory(); m_size = size; m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve m_dataPtr->resize(size); + m_isImmutableStorage = false; + m_storageFlags = 0; m_change.Bits |= BufferChangeBits::DirtyBit; m_change.Bits |= BufferChangeBits::PreferReallocationBit; ++m_changeSerial; } + void BufferObject::AllocateImmutableStorage(SizeT size, const void* data, GLbitfield storageFlags) { + ReleaseMemory(); + m_size = size; + m_dataPtr->reserve(std::bit_ceil(size)); + m_dataPtr->resize(size); + if (data) { + Memcpy(m_dataPtr->data(), data, size); + } else if (size > 0) { + Memset(m_dataPtr->data(), 0, size); + } + m_isImmutableStorage = true; + m_storageFlags = storageFlags; + m_change.DirtyRanges.clear(); + m_change.DirtyRanges.Add({0, size}); + m_change.Bits = BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit; + ++m_changeSerial; + } + void BufferObject::UploadData(DataPtr data, SizeT atOffset) { MOBILEGL_ASSERT(atOffset + data.size <= m_size, "UploadData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset, data.size, m_size); - MOBILEGL_ASSERT(!m_isMapped, "Cannot upload data while buffer is mapped."); + MOBILEGL_ASSERT(!m_isMapped || (m_mappingAccess & BufferMappingAccessBit::Persistent), + "Cannot upload data while buffer is non-persistently mapped."); Memcpy(m_dataPtr->data() + atOffset, data.data, data.size); m_change.DirtyRanges.Add({atOffset, atOffset + data.size}); m_change.Bits |= BufferChangeBits::DirtyBit; @@ -52,8 +74,10 @@ namespace MobileGL::MG_State::GLState { if (m_mappingAccess & BufferMappingAccessBit::Write) { // if we wrote to the buffer if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly - Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(), - m_mappedRange.end - m_mappedRange.start); + if (!(m_mappingAccess & BufferMappingAccessBit::Persistent)) { + Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(), + m_mappedRange.end - m_mappedRange.start); + } m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end}); m_change.Bits |= BufferChangeBits::DirtyBit; ++m_changeSerial; @@ -80,14 +104,29 @@ namespace MobileGL::MG_State::GLState { MOBILEGL_ASSERT(end <= m_mappedRange.end, "Flush range out of bounds: mappedRange.end (%zu) < end (%zu)", m_mappedRange.end, end); - Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length); + if (!(m_mappingAccess & BufferMappingAccessBit::Persistent)) { + Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length); + } m_change.DirtyRanges.Add({start, end}); m_change.Bits |= BufferChangeBits::DirtyBit; ++m_changeSerial; } + void BufferObject::MarkPersistentMappedRangeDirty() { + if (!m_isMapped) return; + if (!(m_mappingAccess & BufferMappingAccessBit::Persistent)) return; + if (!(m_mappingAccess & BufferMappingAccessBit::Write)) return; + if (m_mappingAccess & BufferMappingAccessBit::FlushExplicit) return; + if (m_mappedRange.start >= m_mappedRange.end) return; + + m_change.DirtyRanges.Add(m_mappedRange); + m_change.Bits |= BufferChangeBits::DirtyBit; + ++m_changeSerial; + } + void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) { - MOBILEGL_ASSERT(!m_isMapped, "Cannot upload sub data while buffer is mapped."); + MOBILEGL_ASSERT(!m_isMapped || (m_mappingAccess & BufferMappingAccessBit::Persistent), + "Cannot upload sub data while buffer is non-persistently mapped."); MOBILEGL_ASSERT(atOffset + data.size <= m_size, "UploadSubData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset, data.size, m_size); @@ -101,8 +140,10 @@ namespace MobileGL::MG_State::GLState { } void BufferObject::CopyDataFrom(const SharedPtr& src, SizeT srcOffset, SizeT dstOffset, SizeT size) { - MOBILEGL_ASSERT(!m_isMapped, "Cannot copy data while buffer is mapped."); - MOBILEGL_ASSERT(!src->IsMapped(), "Cannot copy data from a buffer that is mapped."); + MOBILEGL_ASSERT(!m_isMapped || (m_mappingAccess & BufferMappingAccessBit::Persistent), + "Cannot copy data while destination buffer is non-persistently mapped."); + MOBILEGL_ASSERT(!src->IsMapped() || (src->GetMappingAccess() & BufferMappingAccessBit::Persistent), + "Cannot copy data from a buffer that is non-persistently mapped."); MOBILEGL_ASSERT(srcOffset + size <= src->GetSize(), "Source buffer copy out of bounds: srcOffset (%zu) + size (%zu) > src->GetSize() (%zu)", srcOffset, size, src->GetSize()); @@ -149,6 +190,19 @@ namespace MobileGL::MG_State::GLState { m_mappingAccess = access; m_mappedRange = range; + m_change.Bits |= + !(access & BufferMappingAccessBit::InvalidateBuffer || access & BufferMappingAccessBit::InvalidateRange) + ? BufferChangeBits::ForbidInvalidationBit + : BufferChangeBits::None; + m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized) + ? BufferChangeBits::ForbidUnsynchronizationBit + : BufferChangeBits::None; + + if (access & BufferMappingAccessBit::Persistent) { + m_ownsStagingData = false; + return m_dataPtr->data() + range.start; + } + if (access & BufferMappingAccessBit::Write) { m_stagingData.resize(range.end - range.start); m_ownsStagingData = true; @@ -162,14 +216,6 @@ namespace MobileGL::MG_State::GLState { m_ownsStagingData = false; return m_dataPtr->data() + range.start; } - - m_change.Bits |= - !(access & BufferMappingAccessBit::InvalidateBuffer || access & BufferMappingAccessBit::InvalidateRange) - ? BufferChangeBits::ForbidInvalidationBit - : BufferChangeBits::None; - m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized) - ? BufferChangeBits::ForbidUnsynchronizationBit - : BufferChangeBits::None; } const SharedPtr& BufferObject::GetDataReadOnly() const { @@ -185,6 +231,10 @@ namespace MobileGL::MG_State::GLState { return m_size; } + Bool BufferObject::IsImmutableStorage() const { + return m_isImmutableStorage; + } + BufferUsage BufferObject::GetUsage() const { return m_usage; } @@ -209,10 +259,25 @@ namespace MobileGL::MG_State::GLState { return m_isMapped ? m_mappedRange : Range1D{0, 0}; } + void* BufferObject::GetMappedPointer() const { + if (!m_isMapped) return nullptr; + if (m_mappingAccess & BufferMappingAccessBit::Persistent) { + return const_cast(m_dataPtr->data()) + m_mappedRange.start; + } + if (m_ownsStagingData) { + return const_cast(m_stagingData.data()); + } + return const_cast(m_dataPtr->data()) + m_mappedRange.start; + } + Flags BufferObject::GetMappingAccess() const { return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null; } + GLbitfield BufferObject::GetStorageFlags() const { + return m_storageFlags; + } + Uint BufferObject::GetExternalIndex() const { return m_externalIndex; } diff --git a/MobileGL/MG_State/GLState/BufferState/BufferObject.h b/MobileGL/MG_State/GLState/BufferState/BufferObject.h index e6a01383..f13ed348 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferObject.h +++ b/MobileGL/MG_State/GLState/BufferState/BufferObject.h @@ -80,22 +80,27 @@ namespace MobileGL { BufferObject(Uint externalIndex); void Resize(SizeT size); + void AllocateImmutableStorage(SizeT size, const void* data, GLbitfield storageFlags); void UploadData(DataPtr data, SizeT atOffset); void SetUsage(BufferUsage usage); void* AcquireMemory(Bool markMapped, Bool read, Bool write); void* AcquireMemoryRange(Range1D range, Flags access); void ReleaseMemory(); void FlushMemoryRange(SizeT offset, SizeT length); + void MarkPersistentMappedRangeDirty(); void UploadSubData(DataPtr data, SizeT atOffset); void CopyDataFrom(const SharedPtr& src, SizeT srcOffset, SizeT dstOffset, SizeT size); void ClearDirty(); Bool IsMapped() const; + Bool IsImmutableStorage() const; SizeT GetSize() const; BufferUsage GetUsage() const; Range1D GetMappedRange() const; + void* GetMappedPointer() const; const SharedPtr& GetDataReadOnly() const; Flags GetMappingAccess() const; + GLbitfield GetStorageFlags() const; Uint GetExternalIndex() const; const VecRange1D& GetDirtyRanges() const; Flags GetChangeBits() const; @@ -108,6 +113,8 @@ namespace MobileGL { SharedPtr m_dataPtr; Bool m_isMapped; Flags m_mappingAccess; + Bool m_isImmutableStorage = false; + GLbitfield m_storageFlags = 0; BufferChange m_change; Uint64 m_changeSerial = 0; Range1D m_mappedRange; diff --git a/MobileGL/MG_Test/Buffer/BufferTest.cpp b/MobileGL/MG_Test/Buffer/BufferTest.cpp index 9d724fcd..1f589e68 100644 --- a/MobileGL/MG_Test/Buffer/BufferTest.cpp +++ b/MobileGL/MG_Test/Buffer/BufferTest.cpp @@ -477,6 +477,157 @@ TEST_F(GeneralBufferTest, General_MapFlags) { EXPECT_EQ(GetError(), GL_NO_ERROR); } +TEST_F(GeneralBufferTest, General_BufferStorageQueriesImmutable) { + GLuint buffer = 0; + GenBuffers(1, &buffer); + BindBuffer(GL_ARRAY_BUFFER, buffer); + + const GLint initial[] = {1, 2, 3, 4}; + constexpr GLbitfield storageFlags = GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT; + BufferStorage(GL_ARRAY_BUFFER, sizeof(initial), initial, storageFlags); + EXPECT_EQ(GetError(), GL_NO_ERROR); + + GLint immutable = GL_FALSE; + GLint reportedFlags = 0; + GetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_IMMUTABLE_STORAGE, &immutable); + GetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_STORAGE_FLAGS, &reportedFlags); + EXPECT_EQ(immutable, GL_TRUE); + EXPECT_EQ(reportedFlags, static_cast(storageFlags)); + + const GLint update = 42; + BufferSubData(GL_ARRAY_BUFFER, sizeof(GLint), sizeof(update), &update); + EXPECT_EQ(GetError(), GL_NO_ERROR); + + BufferData(GL_ARRAY_BUFFER, sizeof(initial), initial, GL_DYNAMIC_DRAW); + EXPECT_EQ(GetError(), GL_INVALID_OPERATION); +} + +TEST_F(GeneralBufferTest, General_PersistentMapRequiresStorageFlags) { + GLuint mutableBuffer = CreateBoundBuffer(GL_ARRAY_BUFFER, 64, GL_DYNAMIC_DRAW); + (void)mutableBuffer; + void* mapped = MapBufferRange(GL_ARRAY_BUFFER, 0, 16, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + EXPECT_EQ(mapped, nullptr); + EXPECT_EQ(GetError(), GL_INVALID_OPERATION); + + GLuint storageBuffer = 0; + GenBuffers(1, &storageBuffer); + BindBuffer(GL_ARRAY_BUFFER, storageBuffer); + BufferStorage(GL_ARRAY_BUFFER, 64, nullptr, GL_MAP_WRITE_BIT); + EXPECT_EQ(GetError(), GL_NO_ERROR); + mapped = MapBufferRange(GL_ARRAY_BUFFER, 0, 16, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + EXPECT_EQ(mapped, nullptr); + EXPECT_EQ(GetError(), GL_INVALID_OPERATION); + + GLuint persistentBuffer = 0; + GenBuffers(1, &persistentBuffer); + BindBuffer(GL_ARRAY_BUFFER, persistentBuffer); + BufferStorage(GL_ARRAY_BUFFER, 64, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_CLIENT_STORAGE_BIT); + EXPECT_EQ(GetError(), GL_NO_ERROR); + mapped = MapBufferRange(GL_ARRAY_BUFFER, 0, 16, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + ASSERT_NE(mapped, nullptr); + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + +TEST_F(GeneralBufferTest, General_PersistentCoherentWriteDirtyWithoutUnmap) { + GLuint buffer = 0; + GenBuffers(1, &buffer); + BindBuffer(GL_ARRAY_BUFFER, buffer); + + GLint initial[] = {10, 20, 30, 40}; + BufferStorage(GL_ARRAY_BUFFER, sizeof(initial), initial, + GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + EXPECT_EQ(GetError(), GL_NO_ERROR); + + auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer); + ASSERT_NE(bufferObject, nullptr); + bufferObject->ClearDirty(); + + auto* mapped = static_cast( + MapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(initial), + GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT)); + ASSERT_NE(mapped, nullptr); + mapped[2] = 1234; + + bufferObject->MarkPersistentMappedRangeDirty(); + ASSERT_FALSE(bufferObject->GetDirtyRanges().empty()); + EXPECT_EQ(bufferObject->GetDirtyRanges()[0].start, 0); + EXPECT_EQ(bufferObject->GetDirtyRanges()[0].end, sizeof(initial)); + + const auto data = bufferObject->GetDataReadOnly(); + EXPECT_EQ(reinterpret_cast(data->data())[2], 1234); + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + +TEST_F(GeneralBufferTest, General_PersistentExplicitFlushOnlyDirtiesFlushedRange) { + GLuint buffer = 0; + GenBuffers(1, &buffer); + BindBuffer(GL_ARRAY_BUFFER, buffer); + + GLint initial[] = {10, 20, 30, 40}; + BufferStorage(GL_ARRAY_BUFFER, sizeof(initial), initial, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + EXPECT_EQ(GetError(), GL_NO_ERROR); + + auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer); + ASSERT_NE(bufferObject, nullptr); + bufferObject->ClearDirty(); + + auto* mapped = static_cast( + MapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(initial), + GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)); + ASSERT_NE(mapped, nullptr); + mapped[1] = 200; + mapped[3] = 400; + + bufferObject->MarkPersistentMappedRangeDirty(); + EXPECT_TRUE(bufferObject->GetDirtyRanges().empty()); + + FlushMappedBufferRange(GL_ARRAY_BUFFER, sizeof(GLint), sizeof(GLint)); + ASSERT_FALSE(bufferObject->GetDirtyRanges().empty()); + EXPECT_EQ(bufferObject->GetDirtyRanges()[0].start, sizeof(GLint)); + EXPECT_EQ(bufferObject->GetDirtyRanges()[0].end, sizeof(GLint) * 2); + + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + +TEST_F(GeneralBufferTest, General_NamedBufferStorageMappingWrappers) { + GLuint buffer = 0; + GenBuffers(1, &buffer); + + GLint initial[] = {1, 2, 3, 4}; + NamedBufferStorage(buffer, sizeof(initial), initial, + GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + EXPECT_EQ(GetError(), GL_NO_ERROR); + + GLint immutable = GL_FALSE; + GetNamedBufferParameteriv(buffer, GL_BUFFER_IMMUTABLE_STORAGE, &immutable); + EXPECT_EQ(immutable, GL_TRUE); + + auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer); + ASSERT_NE(bufferObject, nullptr); + bufferObject->ClearDirty(); + + auto* mapped = static_cast( + MapNamedBufferRange(buffer, 0, sizeof(initial), + GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)); + ASSERT_NE(mapped, nullptr); + mapped[0] = 99; + + void* mapPointer = nullptr; + GetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &mapPointer); + EXPECT_EQ(mapPointer, mapped); + + FlushMappedNamedBufferRange(buffer, 0, sizeof(GLint)); + ASSERT_FALSE(bufferObject->GetDirtyRanges().empty()); + EXPECT_EQ(bufferObject->GetDirtyRanges()[0].start, 0); + EXPECT_EQ(bufferObject->GetDirtyRanges()[0].end, sizeof(GLint)); + + EXPECT_TRUE(UnmapNamedBuffer(buffer)); + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + TEST_F(GeneralBufferTest, General_GeneralTest_1) { GLuint buffers[3]; GenBuffers(3, buffers); diff --git a/MobileGL/MG_Test/Buffer/CMakeLists.txt b/MobileGL/MG_Test/Buffer/CMakeLists.txt index c8f5787a..cf72e015 100644 --- a/MobileGL/MG_Test/Buffer/CMakeLists.txt +++ b/MobileGL/MG_Test/Buffer/CMakeLists.txt @@ -8,6 +8,9 @@ add_executable( target_include_directories(BufferTest PRIVATE ${MGL_ROOT}/include ${MGL_ROOT}/MobileGL + ${MGL_ROOT}/3rdparty/xxHash + ${MGL_ROOT}/3rdparty/Vulkan-Headers/include + ${MGL_ROOT}/3rdparty/SPIRV-Reflect ) target_link_libraries( @@ -16,5 +19,9 @@ target_link_libraries( ${LINK_LIBRARIES} ) +if (MSVC) + target_compile_options(BufferTest PRIVATE /Zc:preprocessor) +endif() + include(GoogleTest) gtest_discover_tests(BufferTest)