mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Feat] (BufferState): Implement MapBufferRange, FlushMappedBufferRange and CopyBufferSubData.
This commit is contained in:
@@ -56,31 +56,10 @@ GLenum BufferState::Create(GLuint buffer) {
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
//GLenum BufferState::CreateN(GLsizei n, GLuint* buffers) {
|
||||
// MG_Util::Debug::LogD("MG_State: Buffer: CreateN called with n=%d", n);
|
||||
// if (n < 0) return GL_INVALID_VALUE;
|
||||
//
|
||||
// for (GLsizei i = 0; i < n; ++i) {
|
||||
// GLenum result = Create(&buffers[i]);
|
||||
// if (result != GL_NO_ERROR) {
|
||||
// MG_Util::Debug::LogE("MG_State: Buffer: CreateN create buffer failed with error 0x%x", result);
|
||||
// return result;
|
||||
// }
|
||||
// }
|
||||
// MG_Util::Debug::LogD("MG_State: Buffer: CreateN created buffers successfully");
|
||||
// return GL_NO_ERROR;
|
||||
//}
|
||||
|
||||
GLenum BufferState::Bind(GLenum target, GLuint buffer) {
|
||||
// We don't handle unallocated buffer names here, just plain bind
|
||||
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Bind called with target=%s, buffer=%u", MG_Util::Debug::GLEnumToString(target), buffer);
|
||||
|
||||
// if (buffer != 0 && !ValidateAllocatedHandle(buffer)) {
|
||||
// MG_Util::Debug::LogE("MG_State: Buffer: Binding invalid buffer %d to %s", buffer, MG_Util::Debug::GLEnumToString(target));
|
||||
// return GL_INVALID_OPERATION;
|
||||
// }
|
||||
|
||||
currentBindings_[target] = buffer;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Bind succeed bind buffer %u to target 0x%x", buffer, target);
|
||||
return GL_NO_ERROR;
|
||||
@@ -106,44 +85,121 @@ GLenum BufferState::CommitStorage(GLenum target, GLsizeiptr size, const void* da
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer) {
|
||||
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
|
||||
if (MG_Constants::Buffer::VALID_ACCESS.find(access) == MG_Constants::Buffer::VALID_ACCESS.end()) {
|
||||
GLenum BufferState::AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange called with target=0x%x, offset=%ld, length=%ld, access=0x%x", target, offset, length, access);
|
||||
if (!IsValidTarget_(target)) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid target 0x%x", target);
|
||||
return GL_INVALID_ENUM;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemory buffer at target 0x%x acquired mapped memory, access mode = 0x%x", target, access);
|
||||
}
|
||||
|
||||
if (offset < 0 || length <= 0) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid offset %ld or length %ld", offset, length);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
if (it == currentBindings_.end() || it->second == 0) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: no buffer bound to target 0x%x", target);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
if (obj.isMapped) return GL_INVALID_OPERATION;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange operating on buffer %u", it->second);
|
||||
if (obj.isMapped) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: buffer %u is already mapped", it->second);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
const GLbitfield validFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ;
|
||||
if ((access & ~validFlags) != 0) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid access flags 0x%x", access);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(offset + length) > obj.data.size()) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: requested range [%ld, %ld) exceeds buffer size %zu", offset, offset + length, obj.data.size());
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
obj.isMapped = true;
|
||||
*mappedPointer = obj.data.data();
|
||||
obj.accessMode = access;
|
||||
obj.mapOffset = offset;
|
||||
obj.mapLength = length;
|
||||
obj.mapAccessFlags = access;
|
||||
obj.dirty = true;
|
||||
|
||||
*mappedPointer = obj.data.data() + offset;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange succeeded for buffer %u. Mapped pointer: %p", it->second, *mappedPointer);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::ReleaseBufferMemory(GLenum target) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: ReleaseBufferMemory called on target 0x%x",target);
|
||||
GLenum BufferState::SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length) {
|
||||
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
|
||||
if (offset < 0 || length <= 0) return GL_INVALID_VALUE;
|
||||
|
||||
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
if (!obj.isMapped) return GL_INVALID_OPERATION;
|
||||
if (!obj.isMapped || !(obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT))
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
if (offset < obj.mapOffset || offset + length > obj.mapOffset + obj.mapLength)
|
||||
return GL_INVALID_VALUE;
|
||||
|
||||
// TODO: Add support for flush range.
|
||||
// Now only mark it as dirty.
|
||||
obj.dirty = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
|
||||
if (!IsValidTarget_(readTarget) || !IsValidTarget_(writeTarget))
|
||||
return GL_INVALID_ENUM;
|
||||
if (readOffset < 0 || writeOffset < 0 || size < 0)
|
||||
return GL_INVALID_VALUE;
|
||||
|
||||
GLuint readBuffer = currentBindings_[readTarget];
|
||||
GLuint writeBuffer = currentBindings_[writeTarget];
|
||||
if (readBuffer == 0 || writeBuffer == 0 || readBuffer == writeBuffer)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& src = buffers_[readBuffer];
|
||||
BufferObject& dst = buffers_[writeBuffer];
|
||||
|
||||
if (static_cast<size_t>(readOffset + size) > src.data.size() ||
|
||||
static_cast<size_t>(writeOffset + size) > dst.data.size())
|
||||
return GL_INVALID_VALUE;
|
||||
|
||||
memcpy(dst.data.data() + writeOffset, src.data.data() + readOffset, size);
|
||||
dst.dirty = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer) {
|
||||
return AcquireBufferMemoryRange(target, 0, buffers_[currentBindings_[target]].data.size(), access, mappedPointer);
|
||||
}
|
||||
|
||||
GLenum BufferState::ReleaseBufferMemory(GLenum target) {
|
||||
if (!IsValidTarget_(target))
|
||||
return GL_INVALID_ENUM;
|
||||
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
if (!obj.isMapped)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
if ((obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
|
||||
obj.dirty = true;
|
||||
}
|
||||
|
||||
obj.isMapped = false;
|
||||
obj.mapOffset = 0;
|
||||
obj.mapLength = 0;
|
||||
obj.mapAccessFlags = 0;
|
||||
obj.accessMode = GL_READ_WRITE;
|
||||
obj.dirty = true;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: ReleaseBufferMemory buffer at target 0x%x released mapped memory", target);
|
||||
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,23 +21,28 @@ public:
|
||||
bool isMapped = false;
|
||||
bool generated = false;
|
||||
GLenum accessMode = GL_READ_WRITE;
|
||||
GLintptr mapOffset = 0;
|
||||
GLsizeiptr mapLength = 0;
|
||||
GLbitfield mapAccessFlags = 0;
|
||||
};
|
||||
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
GLenum GenName(GLuint* buffer);
|
||||
GLenum GenNameN(GLsizei n, GLuint* buffers);
|
||||
GLenum Create(GLuint buffer);
|
||||
// GLenum CreateN(GLsizei n, GLuint* buffers);
|
||||
GLenum Bind(GLenum target, GLuint buffer);
|
||||
GLenum CommitStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||
GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer);
|
||||
GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length);
|
||||
GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
||||
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer);
|
||||
GLenum ReleaseBufferMemory(GLenum target);
|
||||
GLenum QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const;
|
||||
GLenum DeleteN(GLsizei n, const GLuint* buffers);
|
||||
|
||||
bool ValidateAllocatedHandle(GLuint buffer);
|
||||
bool ValidateGeneratedName(GLuint buffer);
|
||||
void Delete(GLuint buffer);
|
||||
GLenum DeleteN(GLsizei n, const GLuint* buffers);
|
||||
GLuint GetCurrentBinding(GLenum target) const;
|
||||
|
||||
unordered_map<GLenum, GLuint> currentBindings_;
|
||||
|
||||
Reference in New Issue
Block a user