[Feat] (MG_Impl/GL_Buffer, MG_State/BufferState, MG_Backend): implement persistent mapping

This commit is contained in:
2026-06-08 14:08:35 +08:00
parent be3c3eb9bb
commit d553e363a7
18 changed files with 1098 additions and 128 deletions
@@ -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
@@ -106,6 +106,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl {
void CreateAndSyncBufferObject(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
bufferObject->MarkPersistentMappedRangeDirty();
if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return;
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject.get());
+8 -1
View File
@@ -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);
@@ -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;
@@ -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
@@ -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<Uint32>(blockIndex)).c_str());
bufferObject->MarkPersistentMappedRangeDirty();
const auto bufferData = bufferObject->GetDataReadOnly();
MOBILEGL_ASSERT(bufferData != nullptr && !bufferData->empty(),
@@ -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<VkDeviceSize>(bufferObject->GetSize());
if (bufferSize == 0) {
@@ -140,6 +140,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
Memcpy(static_cast<Uint8*>(mapped) + offset, data, static_cast<SizeT>(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();
}
@@ -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<VkTextureManager>();
@@ -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();
+675 -61
View File
@@ -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<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteriv_State",
"Params pointer cannot be null."));
return;
SharedPtr<MG_State::GLState::BufferObject> 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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteriv_State",
"Buffer target is bound to no buffer object."));
return;
SharedPtr<MG_State::GLState::BufferObject> 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<GenericErrorInfo>("MG_Impl/GLImpl", GetBufferOpName(op),
std::format("Buffer object {} does not exist.", buffer)));
}
return bufferObject;
}
switch (pname) {
case GL_BUFFER_SIZE:
*params = static_cast<GLint>(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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", GetBufferOpName(op),
"GL_MAP_COHERENT_BIT requires GL_MAP_PERSISTENT_BIT."));
return false;
}
return true;
}
Bool ValidateImmutableMapAccess(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject,
Flags<BufferMappingAccessBit> accessBits, BufferOp op) {
if (!bufferObject->IsImmutableStorage()) {
if (accessBits & (BufferMappingAccessBit::Persistent | BufferMappingAccessBit::Coherent)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>(
"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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<MG_State::GLState::BufferObject>& bufferObject, GLenum pname,
GLint* params, BufferOp op) {
if (!params) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", GetBufferOpName(op),
"Params pointer cannot be null."));
return;
}
switch (pname) {
case GL_BUFFER_SIZE:
*params = static_cast<GLint>(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<GLint>(bufferObject->GetStorageFlags());
break;
case GL_BUFFER_MAP_OFFSET:
*params = static_cast<GLint>(bufferObject->GetMappedRange().start);
break;
case GL_BUFFER_MAP_LENGTH:
*params = static_cast<GLint>(bufferObject->GetMappedRange().end - bufferObject->GetMappedRange().start);
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteriv_State",
std::format("Invalid pname enum: 0x{:X}", pname)));
break;
}
void GetBufferParameteri64v_Object(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject, GLenum pname,
GLint64* params, BufferOp op) {
if (!params) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", GetBufferOpName(op),
"Params pointer cannot be null."));
return;
}
switch (pname) {
case GL_BUFFER_SIZE:
*params = static_cast<GLint64>(bufferObject->GetSize());
break;
case GL_BUFFER_MAP_OFFSET:
*params = static_cast<GLint64>(bufferObject->GetMappedRange().start);
break;
case GL_BUFFER_MAP_LENGTH:
*params = static_cast<GLint64>(bufferObject->GetMappedRange().end - bufferObject->GetMappedRange().start);
break;
default: {
GLint value = 0;
GetBufferParameteriv_Object(bufferObject, pname, &value, op);
*params = static_cast<GLint64>(value);
break;
}
}
}
void GetBufferPointerv_Object(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject, GLenum pname,
void** params, BufferOp op) {
if (!params) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", GetBufferOpName(op),
"Params pointer cannot be null."));
return;
}
if (pname != GL_BUFFER_MAP_POINTER) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("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<SizeT>(offset) + static_cast<SizeT>(length) > mappedRange.end - mappedRange.start) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<BufferMappingAccessBit> 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<GenericErrorInfo>(
"MG_Impl/GLImpl", "BufferSubData_State",
"Offset and size must not overlap with the mapped range of the buffer object."));
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State",
"Immutable buffer storage was not created with GL_DYNAMIC_STORAGE_BIT."));
return;
}
SizeT bufferSize = bufferObject->GetSize();
if (static_cast<SizeT>(offset) + static_cast<SizeT>(size) > bufferSize) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("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<GenericErrorInfo>(
"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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "BufferStorage_State",
"Buffer already has immutable storage."));
return;
}
bufferObject->AllocateImmutableStorage(static_cast<SizeT>(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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "NamedBufferStorage_State",
"Buffer already has immutable storage."));
return;
}
bufferObject->AllocateImmutableStorage(static_cast<SizeT>(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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "NamedBufferSubData_State",
"Data pointer cannot be null."));
return;
}
if (size < 0 || offset < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "NamedBufferSubData_State",
"Immutable buffer storage was not created with GL_DYNAMIC_STORAGE_BIT."));
return;
}
if (static_cast<SizeT>(offset) + static_cast<SizeT>(size) > bufferObject->GetSize()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "MapNamedBuffer_State",
"Cannot map a buffer object that is already mapped."));
return nullptr;
}
Flags<BufferMappingAccessBit> 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<GenericErrorInfo>("MG_Impl/GLImpl", "MapNamedBufferRange_State",
"Offset and length must be non-negative."));
return nullptr;
}
if (length == 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapNamedBufferRange_State",
"Length must be greater than zero."));
return nullptr;
}
if (static_cast<SizeT>(offset) + static_cast<SizeT>(length) > bufferObject->GetSize()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "MapNamedBufferRange_State",
"Cannot map a buffer object that is already mapped."));
return nullptr;
}
}
return bufferObject->AcquireMemoryRange({static_cast<SizeT>(offset), static_cast<SizeT>(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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedNamedBufferRange_State",
"Offset and length must be non-negative."));
return;
}
if (!bufferObject->IsMapped()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedNamedBufferRange_State",
"Cannot flush a buffer object that is not mapped."));
return;
}
const auto mappedRange = bufferObject->GetMappedRange();
if (static_cast<SizeT>(offset) + static_cast<SizeT>(length) > mappedRange.end - mappedRange.start) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedNamedBufferRange_State",
"Offset and length exceed mapped range."));
return;
}
if (!(bufferObject->GetMappingAccess() & BufferMappingAccessBit::FlushExplicit)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("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<SizeT>(offset), static_cast<SizeT>(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) {
@@ -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);
@@ -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) {
+105 -20
View File
@@ -8,36 +8,121 @@
#include "GL_Sync.h"
#include "MG_State/GLState/Core.h"
#include <MG_State/GLState/Core.h>
#include <MG_State/GLState/ErrorState/Error.h>
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<GLsync, UniquePtr<SyncObject>> g_syncObjects;
void DeleteSync_Backend(GLsync sync) {}
void RecordSyncError(const char* funcName, ErrorCode code, String message) {
MG_State::pGLContext->RecordError(code,
MakeUnique<GenericErrorInfo>("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>();
syncObject->Condition = condition;
syncObject->Flags = flags;
GLsync handle = reinterpret_cast<GLsync>(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<GLint>(syncObject->Condition);
break;
case GL_SYNC_FLAGS:
value = static_cast<GLint>(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
+3
View File
@@ -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
@@ -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<BufferObject>& 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<Data>& 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<Uint8*>(m_dataPtr->data()) + m_mappedRange.start;
}
if (m_ownsStagingData) {
return const_cast<Uint8*>(m_stagingData.data());
}
return const_cast<Uint8*>(m_dataPtr->data()) + m_mappedRange.start;
}
Flags<BufferMappingAccessBit> BufferObject::GetMappingAccess() const {
return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null;
}
GLbitfield BufferObject::GetStorageFlags() const {
return m_storageFlags;
}
Uint BufferObject::GetExternalIndex() const {
return m_externalIndex;
}
@@ -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<BufferMappingAccessBit> access);
void ReleaseMemory();
void FlushMemoryRange(SizeT offset, SizeT length);
void MarkPersistentMappedRangeDirty();
void UploadSubData(DataPtr data, SizeT atOffset);
void CopyDataFrom(const SharedPtr<BufferObject>& 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<Data>& GetDataReadOnly() const;
Flags<BufferMappingAccessBit> GetMappingAccess() const;
GLbitfield GetStorageFlags() const;
Uint GetExternalIndex() const;
const VecRange1D& GetDirtyRanges() const;
Flags<BufferChangeBits> GetChangeBits() const;
@@ -108,6 +113,8 @@ namespace MobileGL {
SharedPtr<Data> m_dataPtr;
Bool m_isMapped;
Flags<BufferMappingAccessBit> m_mappingAccess;
Bool m_isImmutableStorage = false;
GLbitfield m_storageFlags = 0;
BufferChange m_change;
Uint64 m_changeSerial = 0;
Range1D m_mappedRange;
+151
View File
@@ -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<GLint>(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<GLint*>(
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<const GLint*>(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<GLint*>(
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<GLint*>(
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);
+7
View File
@@ -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)