Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
glGenericVertexData.cpp
Go to the documentation of this file.
1
2
4
9
12
13namespace Divide
14{
15
16 glGenericVertexData::glGenericVertexData( GFXDevice& context, const U16 ringBufferLength, const std::string_view name )
17 : GenericVertexData( context, ringBufferLength, name )
18 {
19 }
20
22 {
24
25 _bufferObjects.clear();
26
28 for ( auto& idx : _idxBuffers )
29 {
30 if ( idx._handle != GL_NULL_HANDLE )
31 {
32 GLUtil::freeBuffer( idx._handle );
33 }
34 }
35 _idxBuffers.clear();
36 }
37
39 void glGenericVertexData::draw( const GenericDrawCommand& command, [[maybe_unused]] VDIUserData* userData )
40 {
42
43 // Update buffer bindings
44 for ( const auto& buffer : _bufferObjects )
45 {
46 bindBufferInternal( buffer._bindConfig );
47 }
48
49 {
51
52 gl46core::GLenum indexFormat = gl46core::GL_NONE;
53 if ( !_idxBuffers.empty())
54 {
55 DIVIDE_ASSERT(command._bufferFlag < _idxBuffers.size());
56
57 auto& idxBuffer = _idxBuffers[command._bufferFlag];
58 if ( idxBuffer._idxBufferSync != nullptr )
59 {
60 gl46core::glWaitSync( idxBuffer._idxBufferSync, gl46core::UnusedMask::GL_UNUSED_BIT, gl46core::GL_TIMEOUT_IGNORED );
61 GL_API::DestroyFenceSync( idxBuffer._idxBufferSync );
62 }
63 if ( GL_API::GetStateTracker().setActiveBuffer( gl46core::GL_ELEMENT_ARRAY_BUFFER, idxBuffer._handle ) == GLStateTracker::BindResult::FAILED ) [[unlikely]]
64 {
66 }
67
68 indexFormat = idxBuffer._data.count > 0u ? (idxBuffer._data.smallIndices ? gl46core::GL_UNSIGNED_SHORT : gl46core::GL_UNSIGNED_INT) : gl46core::GL_NONE;
69 }
70 else
71 {
72 DIVIDE_ASSERT(command._bufferFlag == 0u);
73 }
74
75 // Submit the draw command
76 GLUtil::SubmitRenderCommand( command, indexFormat );
77 }
78 }
79
81 {
83
84 IndexBufferEntry* impl = nullptr;
85
87 bool found = false;
88 for ( auto& idxBuffer : _idxBuffers )
89 {
90 if ( idxBuffer._data.id == indices.id )
91 {
92 impl = &idxBuffer;
93 found = true;
94 break;
95 }
96 }
97
98 if ( !found )
99 {
100 impl = &_idxBuffers.emplace_back();
101 }
102 else if ( impl->_handle != GL_NULL_HANDLE )
103 {
104 if ( indices.count == 0u || // We don't need indices anymore
105 impl->_data.dynamic != indices.dynamic || // Buffer usage mode changed
106 impl->_data.count < indices.count) // Buffer not big enough
107 {
109 impl->_bufferSize = 0u;
110 }
111 }
112
113 if ( indices.count == 0u )
114 {
115 // That's it. We have a buffer entry but no GL buffer associated with it, so it won't be used
116 return {};
117 }
118
119 const size_t elementSize = indices.smallIndices ? sizeof( gl46core::GLushort ) : sizeof( gl46core::GLuint );
120 const gl46core::GLenum usage = indices.dynamic ? gl46core::GL_STREAM_DRAW : gl46core::GL_STATIC_DRAW;
121 if ( impl->_handle == GL_NULL_HANDLE )
122 {
123 impl->_data = indices;
124 // At this point, we need an actual index buffer
125 impl->_bufferSize = indices.count * elementSize;
127 _name.empty() ? nullptr : Util::StringFormat( "{}_index_{}", _name.c_str(), indices.id ).c_str() );
128 }
129
130 const size_t range = indices.count * elementSize;
131 DIVIDE_ASSERT( range <= impl->_bufferSize );
132
133 bufferPtr data = indices.data;
134 if ( indices.indicesNeedCast )
135 {
136 impl->_data._smallIndicesTemp.resize( indices.count );
137 const U32* const dataIn = reinterpret_cast<U32*>(data);
138 for ( size_t i = 0u; i < indices.count; ++i )
139 {
140 impl->_data._smallIndicesTemp[i] = to_U16( dataIn[i] );
141 }
142 data = impl->_data._smallIndicesTemp.data();
143 }
144
145 if ( range == impl->_bufferSize )
146 {
147 gl46core::glNamedBufferData( impl->_handle, range, data, usage);
148 }
149 else
150 {
151 gl46core::glInvalidateBufferSubData( impl->_handle, 0u, range );
152 gl46core::glNamedBufferSubData( impl->_handle, 0u, range, data );
153 }
154
155 if ( !Runtime::isMainThread() )
156 {
157 if ( impl->_idxBufferSync != nullptr )
158 {
160 }
161
163 gl46core::glFlush();
164 }
165
166 impl->_data._smallIndicesTemp.clear();
167
168 return {};
169 }
170
173 {
175
177 // Make sure we specify buffers in order.
178 GenericBufferImpl* impl = nullptr;
179 for ( auto& buffer : _bufferObjects )
180 {
181 if ( buffer._bindConfig._bufferIdx == params._bindConfig._bufferIdx )
182 {
183 impl = &buffer;
184 break;
185 }
186 }
187 if ( impl == nullptr )
188 {
189 impl = &_bufferObjects.emplace_back();
190 }
191
192 const size_t ringSizeFactor = params._useRingBuffer ? queueLength() : 1;
193 const size_t bufferSizeInBytes = params._bufferParams._elementCount * params._bufferParams._elementSize;
194
195 BufferImplParams implParams;
196 implParams._bufferParams = params._bufferParams;
197 implParams._dataSize = bufferSizeInBytes * ringSizeFactor;
198 implParams._target = gl46core::GL_ARRAY_BUFFER;
199 implParams._useChunkAllocation = true;
200
201 const size_t elementStride = params._elementStride == SetBufferParams::INVALID_ELEMENT_STRIDE
203 : params._elementStride;
204 impl->_ringSizeFactor = ringSizeFactor;
205 impl->_bindConfig = params._bindConfig;
206 impl->_elementStride = elementStride;
207
208 if ( impl->_buffer != nullptr && impl->_buffer->params() == implParams )
209 {
210 return updateBuffer( params._bindConfig._bufferIdx, 0, params._bufferParams._elementCount, params._initialData.first );
211 }
212
213 impl->_buffer = std::make_unique<glBufferImpl>( _context, implParams, params._initialData, _name.empty() ? nullptr : _name.c_str() );
214
215 BufferLock ret = {};
216 for ( U32 i = 1u; i < ringSizeFactor; ++i )
217 {
218 ret = impl->_buffer->writeOrClearBytes(i * bufferSizeInBytes,
219 params._initialData.second > 0 ? params._initialData.second : bufferSizeInBytes,
220 params._initialData.first,
221 true );
222 }
223
224 ret._range = {0u, implParams._dataSize};
225 return ret;
226 }
227
230 const U32 elementCountOffset,
231 const U32 elementCountRange,
232 const bufferPtr data )
233 {
235
236 GenericBufferImpl* impl = nullptr;
237 for ( auto& bufferImpl : _bufferObjects )
238 {
239 if ( bufferImpl._bindConfig._bufferIdx == buffer )
240 {
241 impl = &bufferImpl;
242 break;
243 }
244 }
245
246 DIVIDE_ASSERT( impl != nullptr && "glGenericVertexData error: set buffer called for invalid buffer index!" );
247
248 const BufferParams& bufferParams = impl->_buffer->params()._bufferParams;
249
250 // Calculate the size of the data that needs updating
251 const size_t dataCurrentSizeInBytes = elementCountRange * bufferParams._elementSize;
252 // Calculate the offset in the buffer in bytes from which to start writing
253 size_t offsetInBytes = elementCountOffset * bufferParams._elementSize;
254
255 DIVIDE_ASSERT( offsetInBytes + dataCurrentSizeInBytes <= bufferParams._elementCount * bufferParams._elementSize );
256
257 if ( impl->_ringSizeFactor > 1u )
258 {
259 offsetInBytes += bufferParams._elementCount * bufferParams._elementSize * queueIndex();
260 }
261
262 impl->_buffer->writeOrClearBytes( offsetInBytes, dataCurrentSizeInBytes, data );
263
264 return BufferLock
265 {
266 ._range = { offsetInBytes, dataCurrentSizeInBytes },
268 ._buffer = impl->_buffer.get()
269 };
270 }
271
272 void glGenericVertexData::bindBufferInternal( const SetBufferParams::BufferBindConfig& bindConfig )
273 {
275
276 GenericBufferImpl* impl = nullptr;
277 for ( auto& bufferImpl : _bufferObjects )
278 {
279 if ( bufferImpl._bindConfig._bufferIdx == bindConfig._bufferIdx )
280 {
281 impl = &bufferImpl;
282 break;
283 }
284 }
285
286 if ( impl == nullptr ) [[unlikely]]
287 {
288 return;
289 }
290
291 const BufferParams& bufferParams = impl->_buffer->params()._bufferParams;
292 size_t offsetInBytes = impl->_buffer->memoryBlock()._offset;
293
294 if ( impl->_ringSizeFactor > 1 ) [[likely]]
295 {
296 offsetInBytes += bufferParams._elementCount * bufferParams._elementSize * queueIndex();
297 }
298
300 GL_API::GetStateTracker().bindActiveBuffer( bindConfig._bindIdx,
301 impl->_buffer->memoryBlock()._bufferHandle,
302 offsetInBytes,
303 impl->_elementStride );
304
306 }
307
308};
#define DIVIDE_ASSERT(...)
#define DIVIDE_UNEXPECTED_CALL()
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
Rough around the edges Adapter pattern abstracting the actual rendering API and access to the GPU.
Definition: GFXDevice.h:215
static void DestroyFenceSync(gl46core::GLsync &sync)
Definition: GLWrapper.cpp:1998
static gl46core::GLsync CreateFenceSync()
Definition: GLWrapper.cpp:1988
static GLStateTracker & GetStateTracker() noexcept
Definition: GLWrapper.cpp:1749
U16 queueLength() const noexcept
Definition: RingBuffer.h:108
I32 queueIndex() const noexcept
Definition: RingBuffer.h:113
void draw(const GenericDrawCommand &command, VDIUserData *data) override
Submit a draw command to the GPU using this object and the specified command.
BufferLock updateBuffer(U32 buffer, U32 elementCountOffset, U32 elementCountRange, bufferPtr data) override
Update the elementCount worth of data contained in the buffer starting from elementCountOffset size o...
eastl::fixed_vector< IndexBufferEntry, 1, true > _idxBuffers
glGenericVertexData(GFXDevice &context, U16 ringBufferLength, const std::string_view name)
BufferLock setBuffer(const SetBufferParams &params) override
Specify the structure and data of the given buffer.
void bindBufferInternal(const SetBufferParams::BufferBindConfig &bindConfig)
eastl::fixed_vector< GenericBufferImpl, 1, true > _bufferObjects
void reset() override
Also clears GPU memory.
BufferLock setIndexBuffer(const IndexBuffer &indices) override
void SubmitRenderCommand(const GenericDrawCommand &drawCommand, const gl46core::GLenum internalFormat)
Note: If internal format is not GL_NONE, an indexed draw is issued!
void createBuffer(gl46core::GLuint &bufferIdOut, const char *name)
void freeBuffer(gl46core::GLuint &bufferId, bufferPtr mappedPtr)
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
constexpr U16 to_U16(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
std::shared_lock< mutex > SharedLock
Definition: SharedMutex.h:49
uint16_t U16
uint32_t U32
void * bufferPtr
BufferUsageType _usageType
Definition: BufferParams.h:41
BufferParams _bufferParams
Definition: glBufferImpl.h:45
gl46core::GLenum _target
Definition: glBufferImpl.h:46
BufferRange _range
Definition: BufferLocks.h:57
size_t _elementSize
Buffer primitive size in bytes.
Definition: BufferParams.h:50
BufferFlags _flags
Definition: BufferParams.h:48
BindResult bindActiveBuffer(gl46core::GLuint location, gl46core::GLuint bufferID, size_t offset, size_t stride)
Modify buffer bindings for the active vao.
std::pair< bufferPtr, size_t > _initialData
SetBufferParams::BufferBindConfig _bindConfig
size_t _bufferSize
IndexBuffer _data
gl46core::GLuint _handle
gl46core::GLsync _idxBufferSync