mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Perf|Improvement] (All): Improve performance & optimize code.
This commit is contained in:
@@ -7,210 +7,203 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "BufferObject.h"
|
||||
#include "MG_Util/Types.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
BufferObject::BufferObject(Uint externalIndex)
|
||||
: m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false),
|
||||
m_mappingAccess(BufferMappingAccessBit::Null),
|
||||
m_change(BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit), m_mappedRange({0, 0}),
|
||||
m_dataPtr(MakeShared<Data>()) {
|
||||
m_change.DirtyRanges.reserve(BufferChange::DEFAULT_RESERVED_DIRTY_RANGES_COUNT);
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
BufferObject::BufferObject(Uint externalIndex)
|
||||
: m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false),
|
||||
m_mappingAccess(BufferMappingAccessBit::Null),
|
||||
m_change(BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit), m_mappedRange({0, 0}),
|
||||
m_dataPtr(MakeShared<Data>()), m_ownsStagingData{} {
|
||||
m_change.DirtyRanges.reserve(BufferChange::DEFAULT_RESERVED_DIRTY_RANGES_COUNT);
|
||||
}
|
||||
|
||||
void BufferObject::Resize(SizeT size) {
|
||||
m_size = size;
|
||||
m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve
|
||||
m_dataPtr->resize(size);
|
||||
void BufferObject::Resize(SizeT size) {
|
||||
m_size = size;
|
||||
m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve
|
||||
m_dataPtr->resize(size);
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::PreferReallocationBit;
|
||||
}
|
||||
|
||||
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.");
|
||||
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
|
||||
m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
// This function may be called by `glBufferData`, but we still set the forbid bits above,
|
||||
// because when `PreferReallocationBit` is set, those bits are ignored anyway.
|
||||
// The bits can fit the `glBufferSubData` semantics
|
||||
// (though `glBufferSubData` calls `UploadSubData` instead).
|
||||
}
|
||||
|
||||
void BufferObject::SetUsage(BufferUsage usage) {
|
||||
m_usage = usage;
|
||||
}
|
||||
|
||||
void BufferObject::ReleaseMemory() {
|
||||
if (!m_isMapped) return;
|
||||
|
||||
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);
|
||||
m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::PreferReallocationBit;
|
||||
}
|
||||
|
||||
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.");
|
||||
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
|
||||
m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
// This function may be called by `glBufferData`, but we still set the forbid bits above,
|
||||
// because when `PreferReallocationBit` is set, those bits are ignored anyway.
|
||||
// The bits can fit the `glBufferSubData` semantics
|
||||
// (though `glBufferSubData` calls `UploadSubData` instead).
|
||||
}
|
||||
m_stagingData.clear();
|
||||
}
|
||||
|
||||
void BufferObject::SetUsage(BufferUsage usage) {
|
||||
m_usage = usage;
|
||||
}
|
||||
m_isMapped = false;
|
||||
m_mappingAccess = BufferMappingAccessBit::Null;
|
||||
m_mappedRange = {0, 0};
|
||||
m_ownsStagingData = false;
|
||||
}
|
||||
|
||||
void BufferObject::ReleaseMemory() {
|
||||
if (!m_isMapped) return;
|
||||
void BufferObject::FlushMemoryRange(SizeT offset, SizeT length) {
|
||||
MOBILEGL_ASSERT(m_isMapped, "Buffer must be mapped to flush memory range.");
|
||||
MOBILEGL_ASSERT((m_mappingAccess & BufferMappingAccessBit::FlushExplicit),
|
||||
"Buffer must be mapped with FlushExplicit access to flush memory range.");
|
||||
MOBILEGL_ASSERT((m_mappingAccess & BufferMappingAccessBit::Write),
|
||||
"Buffer must be mapped with Write access to flush memory range.");
|
||||
|
||||
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);
|
||||
m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
SizeT start = m_mappedRange.start + offset;
|
||||
SizeT end = start + length;
|
||||
MOBILEGL_ASSERT(end <= m_mappedRange.end, "Flush range out of bounds: mappedRange.end (%zu) < end (%zu)",
|
||||
m_mappedRange.end, end);
|
||||
|
||||
m_stagingData.clear();
|
||||
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
|
||||
m_change.DirtyRanges.Add({start, end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
|
||||
void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) {
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload sub data while buffer is 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);
|
||||
|
||||
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
|
||||
m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
}
|
||||
|
||||
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(srcOffset + size <= src->GetSize(),
|
||||
"Source buffer copy out of bounds: srcOffset (%zu) + size (%zu) > src->GetSize() (%zu)",
|
||||
srcOffset, size, src->GetSize());
|
||||
MOBILEGL_ASSERT(dstOffset + size <= m_size,
|
||||
"Destination buffer copy out of bounds: dstOffset (%zu) + size (%zu) > m_size (%zu)", dstOffset,
|
||||
size, m_size);
|
||||
|
||||
const Uint8* srcData = src->m_dataPtr->data() + srcOffset;
|
||||
Memcpy(m_dataPtr->data() + dstOffset, srcData, size);
|
||||
m_change.DirtyRanges.Add({dstOffset, dstOffset + size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
|
||||
void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) {
|
||||
if (markMapped) {
|
||||
m_isMapped = true;
|
||||
auto a = BufferMappingAccessBit::Coherent | BufferMappingAccessBit::Read;
|
||||
m_mappingAccess = (read ? BufferMappingAccessBit::Read : BufferMappingAccessBit::Null) |
|
||||
(write ? BufferMappingAccessBit::Write : BufferMappingAccessBit::Null);
|
||||
m_mappedRange = {0, m_size};
|
||||
|
||||
if (m_mappingAccess & BufferMappingAccessBit::Write) {
|
||||
m_stagingData.resize(m_size);
|
||||
m_ownsStagingData = true;
|
||||
|
||||
if (!(m_mappingAccess &
|
||||
(BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
|
||||
Memcpy(m_stagingData.data(), m_dataPtr->data(), m_size);
|
||||
}
|
||||
|
||||
m_isMapped = false;
|
||||
m_mappingAccess = BufferMappingAccessBit::Null;
|
||||
m_mappedRange = {0, 0};
|
||||
m_ownsStagingData = false;
|
||||
return m_stagingData.data();
|
||||
}
|
||||
}
|
||||
|
||||
return m_dataPtr->data();
|
||||
}
|
||||
|
||||
void* BufferObject::AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access) {
|
||||
MOBILEGL_ASSERT(range.end <= m_size && range.start <= range.end,
|
||||
"AcquireMemoryRange out of bounds: range (%zu, %zu) exceeds m_size (%zu)", range.start,
|
||||
range.end, m_size);
|
||||
m_isMapped = true;
|
||||
m_mappingAccess = access;
|
||||
m_mappedRange = range;
|
||||
|
||||
if (access & BufferMappingAccessBit::Write) {
|
||||
m_stagingData.resize(range.end - range.start);
|
||||
m_ownsStagingData = true;
|
||||
|
||||
if (!(access & (BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
|
||||
Memcpy(m_stagingData.data(), m_dataPtr->data() + range.start, m_stagingData.size());
|
||||
}
|
||||
|
||||
void BufferObject::FlushMemoryRange(SizeT offset, SizeT length) {
|
||||
MOBILEGL_ASSERT(m_isMapped, "Buffer must be mapped to flush memory range.");
|
||||
MOBILEGL_ASSERT((m_mappingAccess & BufferMappingAccessBit::FlushExplicit),
|
||||
"Buffer must be mapped with FlushExplicit access to flush memory range.");
|
||||
MOBILEGL_ASSERT((m_mappingAccess & BufferMappingAccessBit::Write),
|
||||
"Buffer must be mapped with Write access to flush memory range.");
|
||||
return m_stagingData.data();
|
||||
} else {
|
||||
m_ownsStagingData = false;
|
||||
return m_dataPtr->data() + range.start;
|
||||
}
|
||||
|
||||
SizeT start = m_mappedRange.start + offset;
|
||||
SizeT end = start + length;
|
||||
MOBILEGL_ASSERT(end <= m_mappedRange.end,
|
||||
"Flush range out of bounds: mappedRange.end (%zu) < end (%zu)", m_mappedRange.end, end);
|
||||
m_change.Bits |=
|
||||
!(access & BufferMappingAccessBit::InvalidateBuffer || access & BufferMappingAccessBit::InvalidateRange)
|
||||
? BufferChangeBits::ForbidInvalidationBit
|
||||
: BufferChangeBits::None;
|
||||
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
|
||||
? BufferChangeBits::ForbidUnsynchronizationBit
|
||||
: BufferChangeBits::None;
|
||||
}
|
||||
|
||||
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
|
||||
m_change.DirtyRanges.Add({start, end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
const SharedPtr<Data>& BufferObject::GetDataReadOnly() const {
|
||||
return m_dataPtr;
|
||||
}
|
||||
|
||||
void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) {
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload sub data while buffer is 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);
|
||||
void BufferObject::ClearDirty() {
|
||||
m_change.DirtyRanges.clear();
|
||||
m_change.Bits = BufferChangeBits::None;
|
||||
}
|
||||
|
||||
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
|
||||
m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
}
|
||||
SizeT BufferObject::GetSize() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
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(srcOffset + size <= src->GetSize(),
|
||||
"Source buffer copy out of bounds: srcOffset (%zu) + size (%zu) > src->GetSize() (%zu)",
|
||||
srcOffset, size, src->GetSize());
|
||||
MOBILEGL_ASSERT(dstOffset + size <= m_size,
|
||||
"Destination buffer copy out of bounds: dstOffset (%zu) + size (%zu) > m_size (%zu)",
|
||||
dstOffset, size, m_size);
|
||||
BufferUsage BufferObject::GetUsage() const {
|
||||
return m_usage;
|
||||
}
|
||||
|
||||
const Uint8* srcData = src->m_dataPtr->data() + srcOffset;
|
||||
Memcpy(m_dataPtr->data() + dstOffset, srcData, size);
|
||||
m_change.DirtyRanges.Add({dstOffset, dstOffset + size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
const VecRange1D& BufferObject::GetDirtyRanges() const {
|
||||
return m_change.DirtyRanges;
|
||||
}
|
||||
|
||||
void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) {
|
||||
if (markMapped) {
|
||||
m_isMapped = true;
|
||||
auto a = BufferMappingAccessBit::Coherent | BufferMappingAccessBit::Read;
|
||||
m_mappingAccess = (read ? BufferMappingAccessBit::Read : BufferMappingAccessBit::Null) |
|
||||
(write ? BufferMappingAccessBit::Write : BufferMappingAccessBit::Null);
|
||||
m_mappedRange = {0, m_size};
|
||||
Flags<BufferChangeBits> BufferObject::GetChangeBits() const {
|
||||
return m_change.Bits;
|
||||
}
|
||||
|
||||
if (m_mappingAccess & BufferMappingAccessBit::Write) {
|
||||
m_stagingData.resize(m_size);
|
||||
m_ownsStagingData = true;
|
||||
Bool BufferObject::IsMapped() const {
|
||||
return m_isMapped;
|
||||
}
|
||||
|
||||
if (!(m_mappingAccess &
|
||||
(BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
|
||||
Memcpy(m_stagingData.data(), m_dataPtr->data(), m_size);
|
||||
}
|
||||
Range1D BufferObject::GetMappedRange() const {
|
||||
return m_isMapped ? m_mappedRange : Range1D{0, 0};
|
||||
}
|
||||
|
||||
return m_stagingData.data();
|
||||
}
|
||||
}
|
||||
Flags<BufferMappingAccessBit> BufferObject::GetMappingAccess() const {
|
||||
return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null;
|
||||
}
|
||||
|
||||
return m_dataPtr->data();
|
||||
}
|
||||
|
||||
void* BufferObject::AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access) {
|
||||
MOBILEGL_ASSERT(range.end <= m_size && range.start <= range.end,
|
||||
"AcquireMemoryRange out of bounds: range (%zu, %zu) exceeds m_size (%zu)", range.start,
|
||||
range.end, m_size);
|
||||
m_isMapped = true;
|
||||
m_mappingAccess = access;
|
||||
m_mappedRange = range;
|
||||
|
||||
if (access & BufferMappingAccessBit::Write) {
|
||||
m_stagingData.resize(range.end - range.start);
|
||||
m_ownsStagingData = true;
|
||||
|
||||
if (!(access &
|
||||
(BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
|
||||
Memcpy(m_stagingData.data(), m_dataPtr->data() + range.start, m_stagingData.size());
|
||||
}
|
||||
|
||||
return m_stagingData.data();
|
||||
} else {
|
||||
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 {
|
||||
return m_dataPtr;
|
||||
}
|
||||
|
||||
void BufferObject::ClearDirty() {
|
||||
m_change.DirtyRanges.clear();
|
||||
m_change.Bits = BufferChangeBits::None;
|
||||
}
|
||||
|
||||
SizeT BufferObject::GetSize() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
BufferUsage BufferObject::GetUsage() const {
|
||||
return m_usage;
|
||||
}
|
||||
|
||||
const VecRange1D& BufferObject::GetDirtyRanges() const {
|
||||
return m_change.DirtyRanges;
|
||||
}
|
||||
|
||||
Flags<BufferChangeBits> BufferObject::GetChangeBits() const {
|
||||
return m_change.Bits;
|
||||
}
|
||||
|
||||
Bool BufferObject::IsMapped() const {
|
||||
return m_isMapped;
|
||||
}
|
||||
|
||||
Range1D BufferObject::GetMappedRange() const {
|
||||
return m_isMapped ? m_mappedRange : Range1D{0, 0};
|
||||
}
|
||||
|
||||
Flags<BufferMappingAccessBit> BufferObject::GetMappingAccess() const {
|
||||
return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null;
|
||||
}
|
||||
|
||||
Uint BufferObject::GetExternalIndex() const {
|
||||
return m_externalIndex;
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
Uint BufferObject::GetExternalIndex() const {
|
||||
return m_externalIndex;
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include "MG_Util/Types.h"
|
||||
#include <Includes.h>
|
||||
#include <MG_Util/Math/VectorTypes.h>
|
||||
|
||||
@@ -73,47 +72,45 @@ namespace MobileGL {
|
||||
VecRange1D DirtyRanges;
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class BufferObject {
|
||||
public:
|
||||
using TargetEnum = BufferTarget;
|
||||
namespace MG_State::GLState {
|
||||
class BufferObject {
|
||||
public:
|
||||
using TargetEnum = BufferTarget;
|
||||
|
||||
BufferObject(Uint externalIndex);
|
||||
BufferObject(Uint externalIndex);
|
||||
|
||||
void Resize(SizeT size);
|
||||
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 UploadSubData(DataPtr data, SizeT atOffset);
|
||||
void CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size);
|
||||
void ClearDirty();
|
||||
void Resize(SizeT size);
|
||||
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 UploadSubData(DataPtr data, SizeT atOffset);
|
||||
void CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size);
|
||||
void ClearDirty();
|
||||
|
||||
Bool IsMapped() const;
|
||||
SizeT GetSize() const;
|
||||
BufferUsage GetUsage() const;
|
||||
Range1D GetMappedRange() const;
|
||||
const SharedPtr<Data> GetDataReadOnly() const;
|
||||
Flags<BufferMappingAccessBit> GetMappingAccess() const;
|
||||
Uint GetExternalIndex() const;
|
||||
const VecRange1D& GetDirtyRanges() const;
|
||||
Flags<BufferChangeBits> GetChangeBits() const;
|
||||
Bool IsMapped() const;
|
||||
SizeT GetSize() const;
|
||||
BufferUsage GetUsage() const;
|
||||
Range1D GetMappedRange() const;
|
||||
const SharedPtr<Data>& GetDataReadOnly() const;
|
||||
Flags<BufferMappingAccessBit> GetMappingAccess() const;
|
||||
Uint GetExternalIndex() const;
|
||||
const VecRange1D& GetDirtyRanges() const;
|
||||
Flags<BufferChangeBits> GetChangeBits() const;
|
||||
|
||||
private:
|
||||
const Uint m_externalIndex = 0;
|
||||
SizeT m_size = 0;
|
||||
BufferUsage m_usage = BufferUsage::StaticDraw;
|
||||
SharedPtr<Data> m_dataPtr;
|
||||
Bool m_isMapped;
|
||||
Flags<BufferMappingAccessBit> m_mappingAccess;
|
||||
BufferChange m_change;
|
||||
Range1D m_mappedRange;
|
||||
Vector<Uint8> m_stagingData;
|
||||
Bool m_ownsStagingData;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
private:
|
||||
const Uint m_externalIndex = 0;
|
||||
SizeT m_size = 0;
|
||||
BufferUsage m_usage = BufferUsage::StaticDraw;
|
||||
SharedPtr<Data> m_dataPtr;
|
||||
Bool m_isMapped;
|
||||
Flags<BufferMappingAccessBit> m_mappingAccess;
|
||||
BufferChange m_change;
|
||||
Range1D m_mappedRange;
|
||||
Vector<Uint8> m_stagingData;
|
||||
Bool m_ownsStagingData;
|
||||
};
|
||||
} // namespace MG_State::GLState
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -8,78 +8,75 @@
|
||||
|
||||
#include "BufferState.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
BufferState::BufferState() : m_indexGenerator(1024, 1) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
m_bindingSlots[i] = BindingSlot<BufferObject>(GlobalBufferTargets[i]);
|
||||
}
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
BufferState::BufferState() : m_indexGenerator(1024, 1) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
m_bindingSlots[i] = BindingSlot<BufferObject>(GlobalBufferTargets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr<BufferObject> BufferState::GetBufferObject(Uint index) {
|
||||
auto it = m_bufferObjects.find(index);
|
||||
if (it != m_bufferObjects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const SharedPtr<BufferObject>& BufferState::GetBufferObject(Uint index) {
|
||||
auto it = m_bufferObjects.find(index);
|
||||
if (it != m_bufferObjects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
static SharedPtr<BufferObject> nullBufferObject = nullptr;
|
||||
return nullBufferObject;
|
||||
}
|
||||
|
||||
Vector<Uint> BufferState::GenerateNames(Uint number) {
|
||||
Vector<Uint> buffers(number);
|
||||
m_indexGenerator.Generate(number, buffers.data());
|
||||
return buffers;
|
||||
}
|
||||
void BufferState::GenerateNames(Uint number, Vector<Uint>& buffers) {
|
||||
buffers.resize(number);
|
||||
m_indexGenerator.Generate(number, buffers.data());
|
||||
}
|
||||
|
||||
SharedPtr<BufferObject> BufferState::CreateBufferObject(Uint index) {
|
||||
auto bufferObject = MakeShared<BufferObject>(index);
|
||||
m_bufferObjects[index] = bufferObject;
|
||||
return bufferObject;
|
||||
}
|
||||
const SharedPtr<BufferObject>& BufferState::CreateBufferObject(Uint index) {
|
||||
auto& bufferObj = m_bufferObjects[index];
|
||||
if (!bufferObj) {
|
||||
bufferObj = MakeShared<BufferObject>(index);
|
||||
}
|
||||
return bufferObj;
|
||||
}
|
||||
|
||||
BindingSlot<BufferObject>& BufferState::GetBindingSlot(BufferTarget target) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
if (m_bindingSlots[i].GetTarget() == target) {
|
||||
return m_bindingSlots[i];
|
||||
BindingSlot<BufferObject>& BufferState::GetBindingSlot(BufferTarget target) {
|
||||
for (auto& bindingSlot : m_bindingSlots) {
|
||||
if (bindingSlot.GetTarget() == target) {
|
||||
return bindingSlot;
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value: %d", static_cast<int>(target));
|
||||
return m_bindingSlots[0];
|
||||
}
|
||||
|
||||
void BufferState::MarkBufferObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
auto it = m_bufferObjects.find(index);
|
||||
if (it != m_bufferObjects.end()) {
|
||||
for (auto& bindingSlot : m_bindingSlots) {
|
||||
if (bindingSlot.GetBoundObject() == it->second) {
|
||||
bindingSlot.Bind(nullptr);
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value: %d", static_cast<int>(target));
|
||||
return m_bindingSlots[0];
|
||||
m_bufferObjects.erase(it);
|
||||
}
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
|
||||
void BufferState::MarkBufferObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
auto it = m_bufferObjects.find(index);
|
||||
if (it != m_bufferObjects.end()) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
if (m_bindingSlots[i].GetBoundObject() == it->second) {
|
||||
m_bindingSlots[i].Bind(nullptr);
|
||||
}
|
||||
}
|
||||
m_bufferObjects.erase(it);
|
||||
}
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
Bool BufferState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
|
||||
Bool BufferState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
Bool BufferState::ValidateBufferObject(Uint index) const {
|
||||
return m_bufferObjects.find(index) != m_bufferObjects.end();
|
||||
}
|
||||
|
||||
Bool BufferState::ValidateBufferObject(Uint index) const {
|
||||
return m_bufferObjects.find(index) != m_bufferObjects.end();
|
||||
BindingSlotRange1D<BufferObject>& BufferState::GetBindingPoint(BufferTarget target, Uint index) {
|
||||
for (SizeT i = 0; i < BufferBindPointTargets.size(); ++i) {
|
||||
if (BufferBindPointTargets[i] == target) {
|
||||
return m_bufferBindPointTargets[i][index];
|
||||
}
|
||||
|
||||
BindingSlotRange1D<BufferObject>& BufferState::GetBindingPoint(BufferTarget target, Uint index) {
|
||||
for (SizeT i = 0; i < BufferBindPointTargets.size(); ++i) {
|
||||
if (BufferBindPointTargets[i] == target) {
|
||||
return m_bufferBindPointTargets[i][index];
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value for binding point: %d",
|
||||
static_cast<int>(target));
|
||||
return m_bufferBindPointTargets[0][index];
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value for binding point: %d", static_cast<int>(target));
|
||||
return m_bufferBindPointTargets[0][index];
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -11,46 +11,40 @@
|
||||
#include <MG_Util/Miscellany/IndexGenerator.h>
|
||||
#include "BufferObject.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
constexpr const auto GlobalBufferTargets =
|
||||
ToArray(BufferTarget::Vertex, BufferTarget::Uniform, BufferTarget::CopyRead, BufferTarget::CopyWrite,
|
||||
BufferTarget::PixelPack, BufferTarget::PixelUnpack, BufferTarget::Query, BufferTarget::Texture,
|
||||
BufferTarget::TransformFeedback, BufferTarget::AtomicCounter, BufferTarget::DispatchIndirect,
|
||||
BufferTarget::DrawIndirect, BufferTarget::ShaderStorage);
|
||||
constexpr const auto BufferBindPointTargets =
|
||||
ToArray(BufferTarget::Uniform, BufferTarget::TransformFeedback, BufferTarget::AtomicCounter,
|
||||
BufferTarget::ShaderStorage);
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
constexpr const auto GlobalBufferTargets =
|
||||
ToArray(BufferTarget::Vertex, BufferTarget::Uniform, BufferTarget::CopyRead, BufferTarget::CopyWrite,
|
||||
BufferTarget::PixelPack, BufferTarget::PixelUnpack, BufferTarget::Query, BufferTarget::Texture,
|
||||
BufferTarget::TransformFeedback, BufferTarget::AtomicCounter, BufferTarget::DispatchIndirect,
|
||||
BufferTarget::DrawIndirect, BufferTarget::ShaderStorage);
|
||||
constexpr const auto BufferBindPointTargets = ToArray(BufferTarget::Uniform, BufferTarget::TransformFeedback,
|
||||
BufferTarget::AtomicCounter, BufferTarget::ShaderStorage);
|
||||
|
||||
class BufferState {
|
||||
public:
|
||||
BufferState();
|
||||
class BufferState {
|
||||
public:
|
||||
BufferState();
|
||||
|
||||
SharedPtr<BufferObject> GetBufferObject(Uint index);
|
||||
Vector<Uint> GenerateNames(Uint number);
|
||||
SharedPtr<BufferObject> CreateBufferObject(Uint index);
|
||||
BindingSlot<BufferObject>& GetBindingSlot(BufferTarget target);
|
||||
// For glBindBufferBase / glBindBufferRange
|
||||
BindingSlotRange1D<BufferObject>& GetBindingPoint(BufferTarget target, Uint index);
|
||||
constexpr SizeT GetBindingPointCount(const BufferTarget target) const {
|
||||
auto it = std::find(BufferBindPointTargets.begin(), BufferBindPointTargets.end(), target);
|
||||
auto index = std::distance(BufferBindPointTargets.begin(), it);
|
||||
return m_bufferBindPointTargets[index].size();
|
||||
}
|
||||
void MarkBufferObjectForDeletion(Uint index);
|
||||
Bool ValidateName(Uint index) const;
|
||||
Bool ValidateBufferObject(Uint index) const;
|
||||
const SharedPtr<BufferObject>& GetBufferObject(Uint index);
|
||||
void GenerateNames(Uint number, Vector<Uint>& buffers);
|
||||
const SharedPtr<BufferObject>& CreateBufferObject(Uint index);
|
||||
BindingSlot<BufferObject>& GetBindingSlot(BufferTarget target);
|
||||
// For glBindBufferBase / glBindBufferRange
|
||||
BindingSlotRange1D<BufferObject>& GetBindingPoint(BufferTarget target, Uint index);
|
||||
constexpr SizeT GetBindingPointCount(const BufferTarget target) const {
|
||||
auto it = std::find(BufferBindPointTargets.begin(), BufferBindPointTargets.end(), target);
|
||||
auto index = std::distance(BufferBindPointTargets.begin(), it);
|
||||
return m_bufferBindPointTargets[index].size();
|
||||
}
|
||||
void MarkBufferObjectForDeletion(Uint index);
|
||||
Bool ValidateName(Uint index) const;
|
||||
Bool ValidateBufferObject(Uint index) const;
|
||||
|
||||
private:
|
||||
UnorderedMap<Uint, SharedPtr<BufferObject>> m_bufferObjects;
|
||||
IndexGenerator<Uint> m_indexGenerator;
|
||||
Array<BindingSlot<BufferObject>, GlobalBufferTargets.size()> m_bindingSlots;
|
||||
// TODO: query the count somewhere globally?
|
||||
// For glBindBufferBase / glBindBufferRange
|
||||
Array<Array<BindingSlotRange1D<BufferObject>, 16>, BufferBindPointTargets.size()>
|
||||
m_bufferBindPointTargets;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
private:
|
||||
UnorderedMap<Uint, SharedPtr<BufferObject>> m_bufferObjects;
|
||||
IndexGenerator<Uint> m_indexGenerator;
|
||||
Array<BindingSlot<BufferObject>, GlobalBufferTargets.size()> m_bindingSlots;
|
||||
// TODO: query the count somewhere globally?
|
||||
// For glBindBufferBase / glBindBufferRange
|
||||
Array<Array<BindingSlotRange1D<BufferObject>, 16>, BufferBindPointTargets.size()> m_bufferBindPointTargets;
|
||||
};
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
Reference in New Issue
Block a user