Cogs.Core
BuffersGLES30.cpp
1#include "../Base/ContextCommon.h"
2
3#include "ContextGLES30.h"
4#include "BuffersGLES30.h"
5#include "CapabilitiesGLES30.h"
6#include "EffectsGLES30.h"
7#include "FormatsGLES30.h"
8
9
10namespace
11{
12 Cogs::Logging::Log logger = Cogs::Logging::getLogger("BuffersGLES30");
13}
14
15#if defined(COGS_WGL) && (defined(COGSRENDERING_GFX_ANNOTATE) || defined(OSOMP_EnableProfiler))
16
17void Cogs::BuffersGLES30::annotate(BufferHandle handle, const StringView& name)
18{
19 if (HandleIsValid(handle) && !name.empty()) {
20 BufferGLES30& buffer = buffers[handle];
21
22#if defined( OSOMP_EnableProfiler )
23 OsoMPAttribute attribute = { COGSMEM_NameAttribute, ATTRIBUTETYPE_String };
24
25 std::string name_(name);
26 attribute.mData.mText = name_.c_str();
27 RegisterGPUResourceAttributes(glBufferFakeAddress(buffer.bufferId), &attribute, 1);
28#endif
29
30#if defined(COGSRENDERING_GFX_ANNOTATE)
31 if (glObjectLabelKHR && handle && name) {
32 glObjectLabelKHR(GL_BUFFER_KHR, buffer.bufferId, static_cast<GLsizei>(name.length()), name.data());
33 }
34#endif
35
36 }
37}
38void Cogs::BuffersGLES30::annotate(VertexBufferHandle handle, const StringView& name)
39{
40 if (HandleIsValid(handle) && !name.empty()) {
41 BufferGLES30& buffer = buffers[handle];
42
43#if defined( OSOMP_EnableProfiler )
44 OsoMPAttribute attribute = { COGSMEM_NameAttribute, ATTRIBUTETYPE_String };
45
46 std::string name_(name);
47 attribute.mData.mText = name_.c_str();
48 RegisterGPUResourceAttributes(glBufferFakeAddress(buffer.bufferId), &attribute, 1);
49#endif
50
51#if defined(COGSRENDERING_GFX_ANNOTATE)
52 if (glObjectLabelKHR && name) {
53 glObjectLabelKHR(GL_BUFFER_KHR, buffer.bufferId, static_cast<GLsizei>(name.length()), name.data());
54 }
55#endif
56
57 }
58}
59#endif
60
61
62Cogs::VertexBufferHandle Cogs::BuffersGLES30::loadVertexBuffer(const void * vertexData, const size_t count, const VertexFormat & vertexFormat)
63{
64 const uint32_t stride = getSize(vertexFormat);
65 const size_t size = count * stride;
66
67 auto handle = loadBuffer(vertexData, size, Usage::Default, AccessMode::None, BindFlags::VertexBuffer);
68
69 auto& buffer = buffers[handle];
70
71 auto formatHandle = createVertexFormat(vertexFormat.elements.data(), vertexFormat.elements.size());
72
73 buffer.vertexFormat = getVertexFormat(formatHandle);
74 buffer.target = OpenGLES30::BufferTarget::ArrayBuffer;
75
76 assert(buffer.vertexFormat);
77
78 return handle;
79}
80
81Cogs::VertexBufferHandle Cogs::BuffersGLES30::loadVertexBuffer(const void* vertexData, const size_t count, VertexFormatHandle vertexFormatHandle)
82{
83 return loadVertexBuffer(vertexData, count, *VertexFormats::getVertexFormat(vertexFormatHandle));
84}
85
87{
88 releaseBuffer(vertexBufferHandle);
89}
90
91Cogs::IndexBufferHandle Cogs::BuffersGLES30::loadIndexBuffer(const void * indexData, const size_t count, const size_t indexSize)
92{
93 return loadBuffer(indexData,
94 static_cast<uint32_t>(count * indexSize),
96 static_cast<uint32_t>(indexSize));
97}
98
100{
101 releaseBuffer(indexBufferHandle);
102}
103
104Cogs::InputLayoutHandle Cogs::BuffersGLES30::loadInputLayout(const VertexFormatHandle* vertexFormats, const size_t count, EffectHandle /*effectHandle*/)
105{
106 InputLayoutGLES30 inputLayout = {};
107 inputLayout.numFormats = count;
108
109 const uint32_t maxInputs = (uint32_t)capabilities->getDeviceCapabilities().MaxVertexInputElements;
110
111 for (size_t i = 0; i < count; ++i) {
112 const VertexFormat* vertexFormat = VertexFormats::getVertexFormat(vertexFormats[i]);
113
114 inputLayout.formats[i] = getVertexFormat(vertexFormats[i]);
115
116 if (maxInputs <= vertexFormat->elements.size()) {
117 LOG_ERROR(logger, "Input element count exceeds limit set by GL_MAX_VERTEX_ATTRIBS.");
119 }
120 }
121 return inputLayouts.addResource(inputLayout);
122}
123
125{
126 inputLayouts.removeResource(vertexFormatHandle);
127}
128
129Cogs::BufferHandle Cogs::BuffersGLES30::loadBuffer(const void* data, const size_t size, Usage::EUsage usageMode, uint32_t /*accessMode*/, uint32_t bindFlags, uint32_t stride)
130{
131 if constexpr (sizeof(uint32_t) < sizeof(size_t)) {
132 if (std::numeric_limits<uint32_t>::max() < size) {
133 LOG_ERROR(logger, "Buffer size %zu larger than 32-bits is unsupported.", size);
135 }
136 }
137
138 // FIXME: Verify these
139 if (bindFlags & BindFlags::ShaderResource) { LOG_WARNING(logger, "loadBuffer: OpenGLES30 loadBuffer does not support ShaderResource flag."); }
140 if (bindFlags & BindFlags::RawBuffer) { LOG_WARNING(logger, "loadBuffer: OpenGLES30 loadBuffer does not support RawBuffer flag."); }
141 if (bindFlags & BindFlags::StructuredBuffer) { LOG_WARNING(logger, "loadBuffer: OpenGLES30 loadBuffer does not support StructuredBuffer flag."); }
142 if (bindFlags & BindFlags::StructuredBufferWithCounter) { LOG_WARNING(logger, "loadBuffer: OpenGLES30 loadBuffer does not support StructuredBufferWithCounter flag."); }
143
144 BufferGLES30 buffer = {};
145 buffer.size = uint32_t(size);
146 buffer.vertexFormat = nullptr; // clear union
147 buffer.keepMapBacking = 0;
148 buffer.writeBackMap = 0;
149 buffer.isMapped = 0;
150 buffer.isIndexBuffer = 0;
151
152 if (bindFlags & BindFlags::VertexBuffer) {
153 buffer.target = OpenGLES30::BufferTarget::ArrayBuffer;
154
155 if (bindFlags & BindFlags::IndexBuffer) {
156#ifdef EMSCRIPTEN
157 LOG_ERROR_ONCE(logger, "loadBuffer: Buffer with mixed vertex and index data is explicitly not supported by WebGL");
159#else
160 LOG_WARNING_ONCE(logger, "loadBuffer: Buffer with mixed vertex and index data is explicitly not supported by WebGL");
161#endif
162 }
163
164 }
165 else if (bindFlags & BindFlags::IndexBuffer) {
166 buffer.target = OpenGLES30::BufferTarget::ElementArrayBuffer;
167 buffer.isIndexBuffer = 1;
168
169 switch (stride) {
170 case 2:
171 buffer.indexType = GL_UNSIGNED_SHORT;
172 break;
173 case 4:
174 buffer.indexType = GL_UNSIGNED_INT;
175 break;
176 default:
177 LOG_ERROR_ONCE(logger, "loadBuffer: IndexBuffer with unsupported stride %u", stride);
179 }
180
181 }
182 else if (bindFlags & BindFlags::ConstantBuffer) {
183 buffer.target = OpenGLES30::BufferTarget::UniformBuffer;
184
185 // Round up to nearest multiple of 16 since some implementations are picky about this
186 buffer.size = (buffer.size + 15) & ~15;
187
188 }
189 else if (bindFlags & BindFlags::StreamOutBuffer) {
190 buffer.target = OpenGLES30::BufferTarget::TransformFeedbackBuffer;
191 }
192 else {
193 buffer.target = OpenGLES30::BufferTarget::CopyReadBuffer;
194 }
195
196 GLenum usage = GL_STATIC_DRAW;
197 switch (usageMode) {
198 case Usage::Default: [[fallthrough]];
199 case Usage::Static:
200 usage = GL_STATIC_DRAW;
201 break;
202 case Usage::Dynamic:
203 usage = GL_DYNAMIC_DRAW;
204 buffer.keepMapBacking = 1;
205 break;
206 case Usage::Staging:
207 usage = GL_STREAM_READ;
208 buffer.keepMapBacking = 1;
209 break;
210 default:
211 assert(false && "Illegal usage mode");
212 }
213
214 glGenBuffers(1, &buffer.bufferId);
215 GLenum glTarget = context->bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, buffer);
216 glBufferData(glTarget, static_cast<GLsizeiptr>(buffer.size), data, usage);
217 if(context->uploadStatisticsEnabled) context->uploadStatisticsBufferUpload(buffer.size);
218
219 bufferMemoryConsumption += buffer.size;
220
221 if (bindFlags & BindFlags::VertexBuffer) {
222 RegisterGPUResource(glBufferFakeAddress(buffer.bufferId), buffer.size, MemBlockType::GPUVertexBuffer);
223 }
224 else if (bindFlags & BindFlags::IndexBuffer) {
225 RegisterGPUResource(glBufferFakeAddress(buffer.bufferId), buffer.size, MemBlockType::GPUIndexBuffer);
226 }
227 else if (bindFlags & BindFlags::ConstantBuffer) {
228 RegisterGPUResource(glBufferFakeAddress(buffer.bufferId), buffer.size, MemBlockType::GPUConstantBuffer);
229 }
230 else {
231 RegisterGPUResource(glBufferFakeAddress(buffer.bufferId), buffer.size, MemBlockType::GPUBuffer);
232 }
233
234 return buffers.addResource(std::move(buffer));
235}
236
238{
239 if (!bufferHandle) return;
240
241 BufferGLES30& buffer = buffers[bufferHandle];
242 GLuint bufferId = buffer.bufferId;
243
244 context->unbindBuffer(bufferId);
245
246 bufferMemoryConsumption -= buffer.size;
247
248 UnregisterGPUResource(glBufferFakeAddress(bufferId));
249
250 glDeleteBuffers(1, &bufferId);
251
252 buffers.removeResource(bufferHandle);
253}
254
256{
257 {
258 std::vector<BufferHandle> handles;
259 for (auto& resource : buffers) {
260 handles.push_back(buffers.getHandle(resource));
261 }
262 for (auto& handle : handles) {
263 releaseBuffer(handle);
264 }
265 }
266 {
267 std::vector<InputLayoutHandle> handles;
268 for (auto& resource : inputLayouts) {
269 handles.push_back(inputLayouts.getHandle(resource));
270 }
271 for (auto& handle : handles) {
272 releaseInputLayout(handle);
273 }
274 }
275 {
276 std::vector<VertexArrayObjectHandle> handles;
277 for (auto& resource : vertexArrayObjects) {
278 handles.push_back(vertexArrayObjects.getHandle(resource));
279 }
280 for (auto& handle : handles) {
281 releaseVertexArrayObject(handle);
282 }
283 }
284}
285
286void Cogs::BuffersGLES30::retrieveSubBuffer(void* /*data*/, BufferHandle /*source*/, const size_t /*offset*/, const size_t /*size*/)
287{
288 LOG_ERROR_ONCE(logger, "retrieveSubBuffer: not implemented");
289 return;
290}
291
293 const VertexBufferHandle* vertexBufferHandles, const size_t vertexBufferCount,
294 const VertexFormat* const* vertexFormats, const uint32_t* vertexStrides, const uint32_t* vertexOffsets,
295 const IndexBufferHandle indexBufferHandle, uint32_t indexStride)
296{
297 if (!HandleIsValid(effectHandle)) {
298 LOG_ERROR_ONCE(logger, "loadVertexArrayObject: needs valid effect");
300 }
301 const EffectGLES30& effect = effects->effects[effectHandle];
302
303 for (size_t i = 0; i < vertexBufferCount; i++) {
304 if (!HandleIsValid(vertexBufferHandles[i])) {
305 LOG_ERROR_ONCE(logger, "loadVertexArrayObject: vertex buffer handle %zu (of %zu) is invalid", i, vertexBufferCount);
307 }
308 }
309
310 // Resolve index buffer before we create a vertex array object
311 GLenum indexType = GL_INVALID_ENUM;
312 if (HandleIsValid(indexBufferHandle)) {
313 const BufferGLES30* buffer = &buffers[IndexBufferHandle(indexBufferHandle)];
314 if (buffer->isIndexBuffer == 0) {
315 LOG_ERROR_ONCE(logger, "loadVertexArrayObject: Cannot bind non-index buffer as index buffer");
317 }
318
319 switch (indexStride) {
320 case 0:
321 indexType = buffer->indexType;
322 assert((indexType == GL_UNSIGNED_SHORT) || (indexType == GL_UNSIGNED_INT));
323 break;
324 case 2:
325 indexType = GL_UNSIGNED_SHORT;
326 break;
327 case 4:
328 indexType = GL_UNSIGNED_INT;
329 break;
330 default:
331 LOG_ERROR_ONCE(logger, "loadVertexArrayObject: invalid index stride %u", indexStride);
333 }
334 }
335
336
338 glGenVertexArrays(1, &vao.glName);
339 glBindVertexArray(vao.glName);
340
341 for (size_t b = 0; b < vertexBufferCount; b++) {
342
343 const BufferGLES30& buffer = buffers[VertexBufferHandle(vertexBufferHandles[b])];
344 const VertexFormat* vertexFormat = buffer.vertexFormat;
345 if (vertexFormats && vertexFormats[b]) {
346 vertexFormat = vertexFormats[b];
347 }
348 const GLsizei stride = vertexStrides && vertexStrides[b] ? vertexStrides[b] : static_cast<GLsizei>(getSize(*vertexFormat));
349 const GLsizei bufferOffset = vertexOffsets ? vertexOffsets[b] : 0;
350
351 // Don't let context track this because it is part of VAO state.
352 glBindBuffer(GL_ARRAY_BUFFER, buffer.bufferId);
353
354 for (const VertexElement& element : vertexFormat->elements) {
355
356 // Search for effect attribute location for this semantic/slot pair
357 GLint attributeLocation = -1;
358 for (size_t i = 0; i < effect.activeAttributes; i++) {
359 if (effect.attributeSemantic[i].semantic == uint32_t(element.semantic) &&
360 effect.attributeSemantic[i].slot == element.semanticIndex)
361 {
362 attributeLocation = effect.attributeLocation[i];
363 break;
364 }
365 }
366 if (attributeLocation == -1) { continue; } // Attribute not active
367
368 const OpenGLES30::DataFormatInfo format = OpenGLES30::DataFormats[size_t(element.format)];
369 if (format.isVertexFormat == 0) {
370 LOG_WARNING_ONCE(logger, "Encountered unsupported vertex format");
371 continue;
372 }
373
374 const GLvoid* attribOffset = reinterpret_cast<const GLvoid*>((size_t)element.offset + bufferOffset);
376 if (format.type == GL_FLOAT && format.components == 4 && format.columns == 4) {
377 for (GLuint a = 0; a < 4; a++) {
378 GLuint ix = attributeLocation + a;
379 glVertexAttribPointer(ix, 4, format.type, GL_TRUE, stride, reinterpret_cast<const GLvoid*>(sizeof(GLfloat) * a * 4));
380 glEnableVertexAttribArray(ix);
381 glVertexAttribDivisor(ix, element.instanceStep);
382 }
383 }
384 }
385 else {
386 if (format.columns == 1) {
387 if (format.isInteger) {
388 glVertexAttribIPointer(attributeLocation, format.components, format.type, stride, attribOffset);
389 }
390 else {
391 glVertexAttribPointer(attributeLocation, format.components, format.type, format.isNormalized ? GL_TRUE : GL_FALSE, stride, attribOffset);
392 }
393 glEnableVertexAttribArray(attributeLocation);
394 glVertexAttribDivisor(attributeLocation, element.instanceStep);
395 }
396 }
397 }
398 }
399
400 if (HandleIsValid(indexBufferHandle)) {
401 const BufferGLES30& buffer = buffers[IndexBufferHandle(indexBufferHandle)];
402
403 // Don't let context track this because it is part of VAO state.
404 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.bufferId);
405
406 vao.indexType = indexType;
407 switch (vao.indexType) {
408 case GL_UNSIGNED_SHORT:
409 vao.indexCount = GLsizei(buffer.size / 2);
410 vao.indexStride = indexStride;
411 break;
412 case GL_UNSIGNED_INT:
413 vao.indexCount = GLsizei(buffer.size / 4);
414 vao.indexStride = indexStride;
415 break;
416 default:
417 assert(false && "Illegal index type");
418 break;
419 }
420 }
421
422 glBindVertexArray(0);
423 context->vertexArrayObject.prevHandle = VertexArrayObjectHandle::NoHandle;
424 context->vertexArrayObject.currHandle = VertexArrayObjectHandle::NoHandle;
425 context->vertexArrayObject.indexType = GL_INVALID_ENUM;
426 context->vertexArrayObject.indexCount = 0;
427 context->vertexArrayObject.indexStride = 0;
428 return vertexArrayObjects.addResource(std::move(vao));
429}
430
432{
433 VertexArrayObjectGLES30& vao = vertexArrayObjects[vertexArrayObjectHandle];
434 glDeleteVertexArrays(1, &vao.glName);
435 vertexArrayObjects.removeResource(vertexArrayObjectHandle);
436}
437
Log implementation class.
Definition: LogManager.h:139
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
@ InstanceMatrix
Instance matrix semantic.
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ None
The buffer can not be either read from or written to by the CPU after creation.
Definition: Flags.h:46
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
@ StructuredBufferWithCounter
The buffer can be bound as a structured buffer and read or written from shaders, with an additional a...
Definition: Flags.h:82
@ StreamOutBuffer
The buffer can be bound as stream output to receive transform feedback results.
Definition: Flags.h:74
@ VertexBuffer
The buffer can be bound as input to the vertex shader stage as a vertex buffer.
Definition: Flags.h:68
@ RawBuffer
The buffer can be bound as a byte address buffer and read or written from shaders.
Definition: Flags.h:78
@ IndexBuffer
The buffer can be bound as input to the vertex shader stage as an index buffer.
Definition: Flags.h:70
@ ShaderResource
The buffer can be bound as a shader resource and read from shaders.
Definition: Flags.h:76
@ StructuredBuffer
The buffer can be bound as a structured buffer and read or written from shaders.
Definition: Flags.h:80
GLuint bufferId
OpenGL buffer name.
Definition: CommonGLES30.h:69
unsigned short isMapped
Buffer is currently mapped.
Definition: CommonGLES30.h:74
OpenGLES30::BufferTarget target
OpenGL bind target.
Definition: CommonGLES30.h:70
uint32_t size
Buffer size..
Definition: CommonGLES30.h:68
GLenum indexType
OpenGL index type if buffer is an index buffer.
Definition: CommonGLES30.h:65
unsigned short isIndexBuffer
Buffer is an index buffer.
Definition: CommonGLES30.h:75
const VertexFormat * vertexFormat
Vertex format if buffer is a vertex buffer.
Definition: CommonGLES30.h:66
unsigned short keepMapBacking
Do not release memory mapping backing store after unmap, set to 1 for repeatedly mapped buffers.
Definition: CommonGLES30.h:72
unsigned short writeBackMap
Set by map, if one, write back results to GL after unmap (i.e. map with write flags).
Definition: CommonGLES30.h:73
VertexBufferHandle loadVertexBuffer(const void *vertexData, const size_t count, const VertexFormat &vertexFormat) override
Loads a new vertex buffer and populates it with the given data.
void releaseVertexBuffer(VertexBufferHandle vertexBufferHandle) override
Release the vertex buffer with the given handle.
InputLayoutHandle loadInputLayout(const VertexFormatHandle *vertexFormats, const size_t count, EffectHandle effectHandle) override
Loads a new input layout to map vertex flow between vertex buffers with the given vertexFormats to ef...
IndexBufferHandle loadIndexBuffer(const void *indexData, const size_t count, const size_t indexSize)
Loads a new index buffer and populates it with the given indexData.
void releaseResources()
Releases all allocated buffer resources.
VertexArrayObjectHandle loadVertexArrayObject(const EffectHandle effectHandle, const VertexBufferHandle *vertexBufferHandles, const size_t count, const VertexFormat *const *vertexFormats=nullptr, const uint32_t *strides=nullptr, const uint32_t *offsets=nullptr, const IndexBufferHandle indexBufferHandle=IndexBufferHandle::NoHandle, uint32_t stride=4) override
BufferHandle loadBuffer(const void *data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride=0) override
Loads a new buffer using the given data to populate the buffer.
void releaseBuffer(BufferHandle bufferHandle)
Releases the buffer with the given bufferHandle.
void releaseInputLayout(InputLayoutHandle vertexFormatHandle)
Releases the input layout with the given inputLayoutHandle.
void releaseIndexBuffer(IndexBufferHandle indexBufferHandle)
Releases the index buffer with the given handle.
virtual void retrieveSubBuffer(void *data, BufferHandle source, const size_t offset, const size_t size) override
Retrieves the contents of a buffer.
void releaseVertexArrayObject(VertexArrayObjectHandle vertexArrayObjectHandle)
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
virtual void annotate(BufferHandle handle, const StringView &name)
Associate a name with an object for use in graphics debugging.
Definition: IBuffers.h:17
EUsage
Usage enumeration.
Definition: Flags.h:24
@ Static
Buffer will be loaded once and used to render many subsequent frames without any updates.
Definition: Flags.h:28
@ Default
Default usage.
Definition: Flags.h:26
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30
@ Staging
Definition: Flags.h:33
Vertex element structure used to describe a single data element in a vertex for the input assembler.
Definition: VertexFormat.h:38
DataFormat format
Format of the element.
Definition: VertexFormat.h:40
uint16_t offset
Offset in bytes from the vertex position in memory.
Definition: VertexFormat.h:39
uint16_t semanticIndex
Index for the semantic mapping.
Definition: VertexFormat.h:42
ElementSemantic semantic
Semantic mapping of the element (position, normal, etc...).
Definition: VertexFormat.h:41
uint16_t instanceStep
Instance step factor.
Definition: VertexFormat.h:44
Vertex format structure used to describe a single vertex for the input assembler.
Definition: VertexFormat.h:60
std::vector< VertexElement > elements
Vector containing all vertex elements of this format.
Definition: VertexFormat.h:62