Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
vkGenericVertexData.cpp
Go to the documentation of this file.
1
2
5
9
12
13namespace Divide {
14 vkGenericVertexData::vkGenericVertexData(GFXDevice& context, const U16 ringBufferLength, const std::string_view name)
15 : GenericVertexData(context, ringBufferLength, name)
16 {
17 }
18
20 {
21 _bufferObjects.clear();
22
24 _idxBuffers.clear();
25 }
26
27 void vkGenericVertexData::draw(const GenericDrawCommand& command, VDIUserData* userData) noexcept
28 {
29 vkUserData* vkData = static_cast<vkUserData*>(userData);
30
32
33 for (const auto& buffer : _bufferObjects)
34 {
35 bindBufferInternal(buffer._bindConfig, *vkData->_cmdBuffer);
36 }
37
38 SharedLock<SharedMutex> w_lock( _idxBufferLock );
39 if ( !_idxBuffers.empty() )
40 {
41 DIVIDE_ASSERT( command._bufferFlag < _idxBuffers.size() );
42
43 const auto& idxBuffer = _idxBuffers[command._bufferFlag];
44 if (idxBuffer._buffer != nullptr)
45 {
46 VkDeviceSize offsetInBytes = 0u;
47
48 if ( idxBuffer._ringSizeFactor > 1 )
49 {
50 offsetInBytes += idxBuffer._buffer->_params._elementCount * idxBuffer._buffer->_params._elementSize * queueIndex();
51 }
52 VK_PROFILE(vkCmdBindIndexBuffer, *vkData->_cmdBuffer, idxBuffer._buffer->_buffer, offsetInBytes, idxBuffer._data.smallIndices ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
53 }
54
55 // Submit the draw command
56 VK_PROFILE(VKUtil::SubmitRenderCommand, command, *vkData->_cmdBuffer, idxBuffer._buffer != nullptr );
57 }
58 else
59 {
60 DIVIDE_ASSERT( command._bufferFlag == 0u );
61 PROFILE_VK_EVENT( "Submit non-indexed" );
62 VKUtil::SubmitRenderCommand( command, *vkData->_cmdBuffer, false );
63 }
64
65 }
66
67 void vkGenericVertexData::bindBufferInternal(const SetBufferParams::BufferBindConfig& bindConfig, VkCommandBuffer& cmdBuffer)
68 {
70
71 GenericBufferImpl* impl = nullptr;
72 for (auto& bufferImpl : _bufferObjects)
73 {
74 if (bufferImpl._bindConfig._bufferIdx == bindConfig._bufferIdx)
75 {
76 impl = &bufferImpl;
77 break;
78 }
79 }
80
81 if (impl == nullptr) {
82 return;
83 }
84
85 const BufferParams& bufferParams = impl->_buffer->_params;
86 VkDeviceSize offsetInBytes = 0u;
87
88 if (impl->_ringSizeFactor > 1) {
89 offsetInBytes += bufferParams._elementCount * bufferParams._elementSize * queueIndex();
90 }
91
92 VK_PROFILE(vkCmdBindVertexBuffers, cmdBuffer, bindConfig._bindIdx, 1, &impl->_buffer->_buffer, &offsetInBytes);
93 }
94
96 {
98
99 DIVIDE_ASSERT( params._bufferParams._flags._usageType != BufferUsageType::COUNT );
100
101 // Make sure we specify buffers in order.
102 GenericBufferImpl* impl = nullptr;
103 for (auto& buffer : _bufferObjects)
104 {
105 if (buffer._bindConfig._bufferIdx == params._bindConfig._bufferIdx)
106 {
107 impl = &buffer;
108 break;
109 }
110 }
111
112 if (impl == nullptr)
113 {
114 impl = &_bufferObjects.emplace_back();
115 }
116
117 const size_t ringSizeFactor = params._useRingBuffer ? queueLength() : 1;
118 const size_t bufferSizeInBytes = params._bufferParams._elementCount * params._bufferParams._elementSize;
119 const size_t dataSize = bufferSizeInBytes * ringSizeFactor;
120
121 const size_t elementStride = params._elementStride == SetBufferParams::INVALID_ELEMENT_STRIDE
122 ? params._bufferParams._elementSize
123 : params._elementStride;
124 impl->_ringSizeFactor = ringSizeFactor;
125 impl->_bindConfig = params._bindConfig;
126 impl->_elementStride = elementStride;
127
128 if ( impl->_buffer != nullptr && impl->_buffer->_params == params._bufferParams )
129
130 {
131 return updateBuffer( params._bindConfig._bufferIdx, 0, params._bufferParams._elementCount, params._initialData.first);
132 }
133
134 const string bufferName = _name.empty() ? Util::StringFormat("DVD_GENERAL_VTX_BUFFER_{}", handle()._id) : string(_name.c_str()) + "_VTX_BUFFER";
135 impl->_buffer = std::make_unique<vkBufferImpl>(params._bufferParams,
136 bufferSizeInBytes,
137 ringSizeFactor,
138 params._initialData,
139 bufferName.c_str());
140 return BufferLock
141 {
142 ._range = {0u, dataSize},
144 ._buffer = impl->_buffer.get()
145 };
146 }
147
149 {
151
152 IndexBufferEntry* impl = nullptr;
153
155 bool found = false;
156 for (auto& idxBuffer : _idxBuffers) {
157 if (idxBuffer._data.id == indices.id)
158 {
159 impl = &idxBuffer;
160 found = true;
161 break;
162 }
163 }
164
165 if (!found)
166 {
167 impl = &_idxBuffers.emplace_back();
168 }
169 else if ( impl->_buffer != nullptr )
170 {
171 DIVIDE_ASSERT(impl->_buffer->_buffer != VK_NULL_HANDLE);
172
173 if ( indices.count == 0u || // We don't need indices anymore
174 impl->_data.dynamic != indices.dynamic || // Buffer usage mode changed
175 impl->_data.count < indices.count ) // Buffer not big enough
176 {
177 if ( !impl->_buffer->waitForLockedRange( {0, U32_MAX} ) )
178 {
180 }
181 impl->_buffer.reset();
182 }
183 }
184
185 if ( indices.count == 0u )
186 {
187 // That's it. We have a buffer entry but no VK buffer associated with it, so it won't be used
188 return {};
189 }
190
191 SCOPE_EXIT {
192 impl->_data._smallIndicesTemp.clear();
193 };
194
195 bufferPtr data = indices.data;
196 if ( indices.indicesNeedCast )
197 {
198 impl->_data._smallIndicesTemp.resize( indices.count );
199 const U32* const dataIn = reinterpret_cast<U32*>(data);
200 for ( size_t i = 0u; i < indices.count; ++i )
201 {
202 impl->_data._smallIndicesTemp[i] = to_U16( dataIn[i] );
203 }
204 data = impl->_data._smallIndicesTemp.data();
205 }
206
207 const size_t elementSize = indices.smallIndices ? sizeof( U16 ) : sizeof( U32 );
208 const size_t range = indices.count * elementSize;
209
210 if ( impl->_buffer != nullptr )
211 {
212 size_t offsetInBytes = 0u;
213 if ( impl->_ringSizeFactor > 1u )
214 {
215 offsetInBytes += impl->_data.count * elementSize * queueIndex();
216 }
217
218 DIVIDE_ASSERT( range <= impl->_bufferSize );
219 return impl->_buffer->writeBytes( { offsetInBytes, range }, VK_ACCESS_INDEX_READ_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, data );
220 }
221
222 impl->_bufferSize = range;
223 impl->_data = indices;
225
226 BufferParams params{};
228 params._flags._updateUsage = BufferUpdateUsage::CPU_TO_GPU;
229 params._flags._usageType = BufferUsageType::INDEX_BUFFER;
230 params._elementSize = elementSize;
231 params._elementCount = to_U32(indices.count);
232
233 const std::pair<bufferPtr, size_t> initialData = { data, range };
234
235 const string bufferName = _name.empty() ? Util::StringFormat( "DVD_GENERAL_IDX_BUFFER_{}", handle()._id ) : string(_name.c_str()) + "_IDX_BUFFER";
236 impl->_buffer = std::make_unique<vkBufferImpl>( params,
237 impl->_bufferSize,
238 impl->_ringSizeFactor,
239 initialData,
240 bufferName.c_str() );
241 return BufferLock
242 {
243 ._range = {0u, indices.count},
245 ._buffer = impl->_buffer.get()
246 };
247 }
248
250 U32 elementCountOffset,
251 U32 elementCountRange,
252 bufferPtr data) noexcept
253 {
254 GenericBufferImpl* impl = nullptr;
255 for (auto& bufferImpl : _bufferObjects) {
256 if (bufferImpl._bindConfig._bufferIdx == buffer) {
257 impl = &bufferImpl;
258 break;
259 }
260 }
261
262 const BufferParams& bufferParams = impl->_buffer->_params;
264
265 DIVIDE_ASSERT(impl != nullptr, "vkGenericVertexData error: set buffer called for invalid buffer index!");
266
267 // Calculate the size of the data that needs updating
268 const size_t dataCurrentSizeInBytes = elementCountRange * bufferParams._elementSize;
269 // Calculate the offset in the buffer in bytes from which to start writing
270 size_t offsetInBytes = elementCountOffset * bufferParams._elementSize;
271 const size_t bufferSizeInBytes = bufferParams._elementCount * bufferParams._elementSize;
272 DIVIDE_ASSERT(offsetInBytes + dataCurrentSizeInBytes <= bufferSizeInBytes);
273
274 if (impl->_ringSizeFactor > 1u)
275 {
276 offsetInBytes += bufferParams._elementCount * bufferParams._elementSize * queueIndex();
277 }
278
279 if (!impl->_buffer->waitForLockedRange({offsetInBytes, dataCurrentSizeInBytes}))
280 {
282 }
283
284 const BufferRange range = { offsetInBytes , dataCurrentSizeInBytes};
285 return impl->_buffer->writeBytes(range, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, data);
286 }
287}; //namespace Divide
#define SCOPE_EXIT
#define DIVIDE_ASSERT(...)
#define DIVIDE_UNEXPECTED_CALL()
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
#define PROFILE_VK_EVENT(NAME)
Definition: Profiler.h:98
#define PROFILE_VK_EVENT_AUTO_AND_CONTEX(BUFFER)
Definition: Profiler.h:101
Rough around the edges Adapter pattern abstracting the actual rendering API and access to the GPU.
Definition: GFXDevice.h:215
U16 queueLength() const noexcept
Definition: RingBuffer.h:108
I32 queueIndex() const noexcept
Definition: RingBuffer.h:113
vector< IndexBufferEntry > _idxBuffers
BufferLock updateBuffer(U32 buffer, U32 elementCountOffset, U32 elementCountRange, bufferPtr data) noexcept override
BufferLock setIndexBuffer(const IndexBuffer &indices) override
vkGenericVertexData(GFXDevice &context, const U16 ringBufferLength, const std::string_view name)
BufferLock setBuffer(const SetBufferParams &params) noexcept override
vector< GenericBufferImpl > _bufferObjects
void bindBufferInternal(const SetBufferParams::BufferBindConfig &bindConfig, VkCommandBuffer &cmdBuffer)
void draw(const GenericDrawCommand &command, VDIUserData *data) noexcept override
void reset() override
Also clears GPU memory.
constexpr Optick::Category::Type Graphics
Definition: Profiler.h:60
Str StringFormat(const char *fmt, Args &&...args)
void SubmitRenderCommand(const GenericDrawCommand &drawCommand, const VkCommandBuffer commandBuffer, bool indexed)
Note: If internal format is not GL_NONE, an indexed draw is issued!
Definition: vkResources.cpp:67
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
std::lock_guard< mutex > LockGuard
Definition: SharedMutex.h:55
constexpr U32 to_U32(const T value)
constexpr U16 to_U16(const T value)
std::shared_lock< mutex > SharedLock
Definition: SharedMutex.h:49
uint16_t U16
std::basic_string< char, std::char_traits< char >, dvd_allocator< char > > string
Definition: STLString.h:41
uint32_t U32
void * bufferPtr
BufferUpdateFrequency _updateFrequency
Definition: BufferParams.h:39
BufferRange _range
Definition: BufferLocks.h:57
size_t _elementSize
Buffer primitive size in bytes.
Definition: BufferParams.h:50
BufferFlags _flags
Definition: BufferParams.h:48
SetBufferParams::BufferBindConfig _bindConfig
vkBufferImpl_uptr _buffer
size_t _ringSizeFactor
size_t _bufferSize
IndexBuffer _data
VkCommandBuffer * _cmdBuffer
Definition: VKWrapper.h:55
#define VK_PROFILE(FUNCTION,...)
Definition: vkResources.h:340