Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
glBufferImpl.cpp
Go to the documentation of this file.
1
2
5
10
13
14namespace Divide
15{
16 glBufferImpl::glBufferImpl( GFXDevice& context, const BufferImplParams& params, const std::pair<const bufferPtr, size_t>& initialData, const char* name )
17 : _params( params )
18 , _context( context )
19 {
21
22 _lockManager = std::make_unique<glLockManager>();
23
24 // Create all buffers with zero mem and then write the actual data that we have (If we want to initialise all memory)
26 {
27 gl46core::GLenum usage = gl46core::GL_NONE;
28 switch ( params._bufferParams._flags._updateFrequency )
29 {
31 switch ( params._bufferParams._flags._updateUsage )
32 {
33 case BufferUpdateUsage::CPU_TO_GPU: usage = gl46core::GL_STATIC_DRAW; break;
34 case BufferUpdateUsage::GPU_TO_CPU: usage = gl46core::GL_STATIC_READ; break;
35 case BufferUpdateUsage::GPU_TO_GPU: usage = gl46core::GL_STATIC_COPY; break;
36 default: break;
37 }
38 break;
40 switch ( params._bufferParams._flags._updateUsage )
41 {
42 case BufferUpdateUsage::CPU_TO_GPU: usage = gl46core::GL_DYNAMIC_DRAW; break;
43 case BufferUpdateUsage::GPU_TO_CPU: usage = gl46core::GL_DYNAMIC_READ; break;
44 case BufferUpdateUsage::GPU_TO_GPU: usage = gl46core::GL_DYNAMIC_COPY; break;
45 default: break;
46 }
47 break;
49 switch ( params._bufferParams._flags._updateUsage )
50 {
51 case BufferUpdateUsage::CPU_TO_GPU: usage = gl46core::GL_STREAM_DRAW; break;
52 case BufferUpdateUsage::GPU_TO_CPU: usage = gl46core::GL_STREAM_READ; break;
53 case BufferUpdateUsage::GPU_TO_GPU: usage = gl46core::GL_STREAM_COPY; break;
54 default: break;
55 }
56 break;
57 default: break;
58 }
59
60 DIVIDE_ASSERT( usage != gl46core::GL_NONE );
61
62 GLUtil::createAndAllocBuffer( _params._dataSize,
63 usage,
64 _memoryBlock._bufferHandle,
65 initialData,
66 name );
67
68 _memoryBlock._offset = 0u;
69 _memoryBlock._size = _params._dataSize;
70 _memoryBlock._free = false;
71 }
72 else
73 {
74 const gl46core::BufferStorageMask storageMask = gl46core::GL_MAP_PERSISTENT_BIT | gl46core::GL_MAP_WRITE_BIT | gl46core::GL_MAP_COHERENT_BIT;
75 const gl46core::BufferAccessMask accessMask = gl46core::GL_MAP_PERSISTENT_BIT | gl46core::GL_MAP_WRITE_BIT | gl46core::GL_MAP_COHERENT_BIT;
76
77 const size_t alignment = params._target == gl46core::GL_UNIFORM_BUFFER
79 : _params._target == gl46core::GL_SHADER_STORAGE_BUFFER
82
84 _memoryBlock = allocator.allocate( _params._useChunkAllocation,
85 _params._dataSize,
86 alignment,
87 storageMask,
88 accessMask,
89 params._target,
90 name,
91 initialData );
92 assert( _memoryBlock._ptr != nullptr && _memoryBlock._size >= _params._dataSize && "PersistentBuffer::Create error: Can't mapped persistent buffer!" );
93 }
94
95 _isLockable = _memoryBlock._ptr != nullptr;
96
97 if ( !Runtime::isMainThread() )
98 {
100 if ( !lockRange( { 0u, _params._dataSize }, sync ) )
101 {
103 }
104 }
105
107 }
108
110 {
111 if (!waitForLockedRange({0u, _memoryBlock._size}))
112 {
114 }
115
116 if ( _memoryBlock._bufferHandle != GL_NULL_HANDLE )
117 {
118 if ( _memoryBlock._ptr != nullptr )
119 {
121 allocator.deallocate( _memoryBlock );
122 }
123 else
124 {
125 GLUtil::freeBuffer( _memoryBlock._bufferHandle );
127 }
128
129 _context.getPerformanceMetrics()._bufferVRAMUsage -= _params._dataSize;
131 }
132 }
133
134 BufferLock glBufferImpl::writeOrClearBytes( const size_t offsetInBytes, const size_t rangeInBytes, const bufferPtr data, const bool firstWrite )
135 {
136 assert( rangeInBytes > 0u && offsetInBytes + rangeInBytes <= _memoryBlock._size );
137
139 PROFILE_TAG( "Mapped", static_cast<bool>(_memoryBlock._ptr != nullptr) );
140 PROFILE_TAG( "Offset", to_U32( offsetInBytes ) );
141 PROFILE_TAG( "Range", to_U32( rangeInBytes ) );
142
143 if ( !waitForLockedRange({offsetInBytes, rangeInBytes} ) ) [[unlikely]]
144 {
145 Console::errorfn( LOCALE_STR( "ERROR_BUFFER_LOCK_MANAGER_WAIT" ) );
146 }
147
148 BufferLock ret =
149 {
151 ._buffer = this
152 };
153
154 LockGuard<Mutex> w_lock( _mapLock );
155 if ( _memoryBlock._ptr != nullptr ) [[likely]]
156 {
157 if ( data == nullptr )
158 {
159 memset( &_memoryBlock._ptr[offsetInBytes], 0, rangeInBytes );
160 }
161 else
162 {
163 memcpy( &_memoryBlock._ptr[offsetInBytes], data, rangeInBytes );
164 }
165
166 ret._range = {offsetInBytes, rangeInBytes};
167 }
168 else
169 {
170 DIVIDE_ASSERT( data == nullptr || firstWrite, "glBufferImpl: trying to write to a buffer create with BufferUpdateFrequency::ONCE" );
171
172 Byte* ptr = (Byte*)gl46core::glMapNamedBufferRange( _memoryBlock._bufferHandle, _memoryBlock._offset + offsetInBytes, rangeInBytes, gl46core::GL_MAP_WRITE_BIT | gl46core::GL_MAP_INVALIDATE_RANGE_BIT | gl46core::GL_MAP_UNSYNCHRONIZED_BIT );
173 if ( data == nullptr )
174 {
175 memset( ptr, 0, rangeInBytes );
176 }
177 else
178 {
179 memcpy( ptr, data, rangeInBytes );
180 }
181 gl46core::glUnmapNamedBuffer( _memoryBlock._bufferHandle );
182 }
183
184 return ret;
185 }
186
187 void glBufferImpl::readBytes( const size_t offsetInBytes, const size_t rangeInBytes, std::pair<bufferPtr, size_t> outData )
188 {
190
191 if ( !waitForLockedRange( {offsetInBytes, rangeInBytes} ) ) [[unlikely]]
192 {
194 }
195
196 LockGuard<Mutex> w_lock( _mapLock );
197 if ( _memoryBlock._ptr != nullptr ) [[likely]]
198 {
199 DIVIDE_ASSERT(rangeInBytes + offsetInBytes <= _memoryBlock._size );
200 memcpy( outData.first, _memoryBlock._ptr + offsetInBytes, rangeInBytes);
201 }
202 else
203 {
204 if ( _copyBufferTarget == GL_NULL_HANDLE || _copyBufferSize < rangeInBytes )
205 {
207 _copyBufferSize = rangeInBytes;
209 gl46core::GL_STREAM_READ,
211 { nullptr, 0u },
212 Util::StringFormat( "COPY_BUFFER_{}", _memoryBlock._bufferHandle ).c_str() );
213
215 }
216 gl46core::glCopyNamedBufferSubData( _memoryBlock._bufferHandle, _copyBufferTarget, _memoryBlock._offset + offsetInBytes, 0u, rangeInBytes );
217
218 const Byte* bufferData = (Byte*)gl46core::glMapNamedBufferRange( _copyBufferTarget, 0u, rangeInBytes, gl46core::BufferAccessMask::GL_MAP_READ_BIT );
219 assert( bufferData != nullptr );
220 memcpy( outData.first, bufferData, rangeInBytes );
221 gl46core::glUnmapNamedBuffer( _copyBufferTarget );
222 }
223 }
224
225}; //namespace Divide
#define LOCALE_STR(X)
Definition: Localization.h:91
#define DIVIDE_ASSERT(...)
#define DIVIDE_UNEXPECTED_CALL()
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
#define PROFILE_TAG(NAME,...)
Definition: Profiler.h:88
Rough around the edges Adapter pattern abstracting the actual rendering API and access to the GPU.
Definition: GFXDevice.h:215
static const DeviceInformation & GetDeviceInformation() noexcept
Definition: GFXDevice.inl:158
PerformanceMetrics & getPerformanceMetrics() noexcept
Definition: GFXDevice.inl:194
static GLUtil::GLMemory::DeviceAllocator & GetMemoryAllocator(GLUtil::GLMemory::GLMemoryType memoryType) noexcept
Definition: GLWrapper.cpp:1778
static GLUtil::GLMemory::GLMemoryType GetMemoryTypeForUsage(gl46core::GLenum usage) noexcept
Definition: GLWrapper.cpp:1754
void deallocate(const Block &block) const
Block allocate(bool poolAllocations, size_t size, size_t alignment, gl46core::BufferStorageMask storageMask, gl46core::BufferAccessMask accessMask, gl46core::GLenum usage, const char *blockName, std::pair< bufferPtr, size_t > initialData)
static constexpr U8 DEFAULT_SYNC_FLAG_SSBO
Definition: LockManager.h:79
static SyncObjectHandle CreateSyncObject(RenderAPI api, U8 flag=DEFAULT_SYNC_FLAG_INTERNAL)
GFXDevice & _context
Definition: glBufferImpl.h:68
BufferLock writeOrClearBytes(size_t offsetInBytes, size_t rangeInBytes, const bufferPtr data, bool firstWrite=false)
virtual ~glBufferImpl() override
gl46core::GLuint _copyBufferTarget
Definition: glBufferImpl.h:70
void readBytes(size_t offsetInBytes, size_t rangeInBytes, std::pair< bufferPtr, size_t > outData)
glBufferImpl(GFXDevice &context, const BufferImplParams &params, const std::pair< const bufferPtr, size_t > &initialData, const char *name)
void freeBuffer(gl46core::GLuint &bufferId, bufferPtr mappedPtr)
void createAndAllocBuffer(const size_t bufferSize, const gl46core::GLenum usageMask, gl46core::GLuint &bufferIdOut, const std::pair< bufferPtr, size_t > initialData, const char *name)
constexpr Optick::Category::Type Graphics
Definition: Profiler.h:60
bool isMainThread() noexcept
Str StringFormat(const char *fmt, Args &&...args)
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
std::lock_guard< mutex > LockGuard
Definition: SharedMutex.h:55
std::byte Byte
constexpr U32 to_U32(const T value)
constexpr gl46core::GLuint GL_NULL_HANDLE
Invalid object value. Used to compare handles and determine if they were properly created.
Definition: glResources.h:105
void * bufferPtr
BufferUpdateUsage _updateUsage
Definition: BufferParams.h:40
BufferUpdateFrequency _updateFrequency
Definition: BufferParams.h:39
BufferParams _bufferParams
Definition: glBufferImpl.h:45
gl46core::GLenum _target
Definition: glBufferImpl.h:46
BufferRange _range
Definition: BufferLocks.h:57
BufferSyncUsage _type
Definition: BufferLocks.h:58
BufferFlags _flags
Definition: BufferParams.h:48
static NO_INLINE void errorfn(const char *format, T &&... args)
bool waitForLockedRange(BufferRange range) const
Definition: BufferLocks.cpp:38
bool lockRange(BufferRange range, SyncObjectHandle &sync) const
Definition: BufferLocks.cpp:26
LockManager_uptr _lockManager
Definition: BufferLocks.h:46
size_t _bufferVRAMUsage
Total VRAM usage for all shader buffers.