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.bindFlags = bindFlags;
147 buffer.vertexFormat = nullptr; // clear union
148 buffer.keepMapBacking = 0;
149 buffer.writeBackMap = 0;
150 buffer.isMapped = 0;
151 buffer.isIndexBuffer = 0;
152
153 if (bindFlags & BindFlags::VertexBuffer) {
154 buffer.target = OpenGLES30::BufferTarget::ArrayBuffer;
155
156 if (bindFlags & BindFlags::IndexBuffer) {
157#ifdef __EMSCRIPTEN__
158 LOG_ERROR_ONCE(logger, "loadBuffer: Buffer with mixed vertex and index data is explicitly not supported by WebGL");
160#else
161 LOG_WARNING_ONCE(logger, "loadBuffer: Buffer with mixed vertex and index data is explicitly not supported by WebGL");
162#endif
163 }
164
165 }
166 else if (bindFlags & BindFlags::IndexBuffer) {
167 buffer.target = OpenGLES30::BufferTarget::ElementArrayBuffer;
168 buffer.isIndexBuffer = 1;
169
170 switch (stride) {
171 case 2:
172 buffer.indexType = GL_UNSIGNED_SHORT;
173 break;
174 case 4:
175 buffer.indexType = GL_UNSIGNED_INT;
176 break;
177 default:
178 LOG_ERROR_ONCE(logger, "loadBuffer: IndexBuffer with unsupported stride %u", stride);
180 }
181
182 }
183 else if (bindFlags & BindFlags::ConstantBuffer) {
184 buffer.target = OpenGLES30::BufferTarget::UniformBuffer;
185
186 // Round up to nearest multiple of 16 since some implementations are picky about this
187 buffer.size = (buffer.size + 15) & ~15;
188
189 }
190 else if (bindFlags & BindFlags::StreamOutBuffer) {
191 buffer.target = OpenGLES30::BufferTarget::TransformFeedbackBuffer;
192 }
193 else {
194 buffer.target = OpenGLES30::BufferTarget::CopyReadBuffer;
195 }
196
197 GLenum usage = GL_STATIC_DRAW;
198 switch (usageMode) {
199 case Usage::Default: [[fallthrough]];
200 case Usage::Static:
201 usage = GL_STATIC_DRAW;
202 break;
203 case Usage::Dynamic:
204 usage = GL_DYNAMIC_DRAW;
205 buffer.keepMapBacking = 1;
206 break;
207 case Usage::Staging:
208 usage = GL_STREAM_READ;
209 buffer.keepMapBacking = 1;
210 break;
211 default:
212 assert(false && "Illegal usage mode");
213 }
214
215 glGenBuffers(1, &buffer.bufferId);
216 GLenum glTarget = context->bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, buffer);
217 glBufferData(glTarget, static_cast<GLsizeiptr>(buffer.size), data, usage);
218 if(context->uploadStatisticsEnabled) context->uploadStatisticsBufferUpload(buffer.size);
219
220 if (bindFlags & BindFlags::VertexBuffer) {
221 RegisterGPUResource(glBufferFakeAddress(buffer.bufferId), buffer.size, MemBlockType::GPUVertexBuffer);
222 }
223 else if (bindFlags & BindFlags::IndexBuffer) {
224 RegisterGPUResource(glBufferFakeAddress(buffer.bufferId), buffer.size, MemBlockType::GPUIndexBuffer);
225 }
226 else if (bindFlags & BindFlags::ConstantBuffer) {
227 RegisterGPUResource(glBufferFakeAddress(buffer.bufferId), buffer.size, MemBlockType::GPUConstantBuffer);
228 }
229 else {
230 RegisterGPUResource(glBufferFakeAddress(buffer.bufferId), buffer.size, MemBlockType::GPUBuffer);
231 }
232
233 const size_t roundedSize = buffer.size;
234 BufferHandle handle = buffers.addResource(std::move(buffer));
235 recordBufferCreate(handle, static_cast<BindFlags::EBindFlags>(bindFlags), roundedSize);
236 return handle;
237}
238
240{
241 if (!bufferHandle) return;
242
243 BufferGLES30& buffer = buffers[bufferHandle];
244 GLuint bufferId = buffer.bufferId;
245
246 context->unbindBuffer(bufferId);
247
248 recordBufferRelease(bufferHandle, static_cast<BindFlags::EBindFlags>(buffer.bindFlags), buffer.size);
249
250 UnregisterGPUResource(glBufferFakeAddress(bufferId));
251
252 glDeleteBuffers(1, &bufferId);
253
254 buffers.removeResource(bufferHandle);
255}
256
258{
259 {
260 std::vector<BufferHandle> handles;
261 for (auto& resource : buffers) {
262 handles.push_back(buffers.getHandle(resource));
263 }
264 for (auto& handle : handles) {
265 releaseBuffer(handle);
266 }
267 }
268 {
269 std::vector<InputLayoutHandle> handles;
270 for (auto& resource : inputLayouts) {
271 handles.push_back(inputLayouts.getHandle(resource));
272 }
273 for (auto& handle : handles) {
274 releaseInputLayout(handle);
275 }
276 }
277 {
278 std::vector<VertexArrayObjectHandle> handles;
279 for (auto& resource : vertexArrayObjects) {
280 handles.push_back(vertexArrayObjects.getHandle(resource));
281 }
282 for (auto& handle : handles) {
283 releaseVertexArrayObject(handle);
284 }
285 }
286}
287
288void Cogs::BuffersGLES30::retrieveSubBuffer(void* /*data*/, BufferHandle /*source*/, const size_t /*offset*/, const size_t /*size*/)
289{
290 LOG_ERROR_ONCE(logger, "retrieveSubBuffer: not implemented");
291 return;
292}
293
295 const VertexBufferHandle* vertexBufferHandles, const size_t vertexBufferCount,
296 const VertexFormat* const* vertexFormats, const uint32_t* vertexStrides, const uint32_t* vertexOffsets,
297 const IndexBufferHandle indexBufferHandle, uint32_t indexStride)
298{
299 if (!HandleIsValid(effectHandle)) {
300 LOG_ERROR_ONCE(logger, "loadVertexArrayObject: needs valid effect");
302 }
303 const EffectGLES30& effect = effects->effects[effectHandle];
304
305 for (size_t i = 0; i < vertexBufferCount; i++) {
306 if (!HandleIsValid(vertexBufferHandles[i])) {
307 LOG_ERROR_ONCE(logger, "loadVertexArrayObject: vertex buffer handle %zu (of %zu) is invalid", i, vertexBufferCount);
309 }
310 }
311
312 // Resolve index buffer before we create a vertex array object
313 GLenum indexType = GL_INVALID_ENUM;
314 if (HandleIsValid(indexBufferHandle)) {
315 const BufferGLES30* buffer = &buffers[IndexBufferHandle(indexBufferHandle)];
316 if (buffer->isIndexBuffer == 0) {
317 LOG_ERROR_ONCE(logger, "loadVertexArrayObject: Cannot bind non-index buffer as index buffer");
319 }
320
321 switch (indexStride) {
322 case 0:
323 indexType = buffer->indexType;
324 assert((indexType == GL_UNSIGNED_SHORT) || (indexType == GL_UNSIGNED_INT));
325 break;
326 case 2:
327 indexType = GL_UNSIGNED_SHORT;
328 break;
329 case 4:
330 indexType = GL_UNSIGNED_INT;
331 break;
332 default:
333 LOG_ERROR_ONCE(logger, "loadVertexArrayObject: invalid index stride %u", indexStride);
335 }
336 }
337
338
340 glGenVertexArrays(1, &vao.glName);
341 glBindVertexArray(vao.glName);
342
343 for (size_t b = 0; b < vertexBufferCount; b++) {
344
345 const BufferGLES30& buffer = buffers[VertexBufferHandle(vertexBufferHandles[b])];
346 const VertexFormat* vertexFormat = buffer.vertexFormat;
347 if (vertexFormats && vertexFormats[b]) {
348 vertexFormat = vertexFormats[b];
349 }
350 const GLsizei stride = vertexStrides && vertexStrides[b] ? vertexStrides[b] : static_cast<GLsizei>(getSize(*vertexFormat));
351 const GLsizei bufferOffset = vertexOffsets ? vertexOffsets[b] : 0;
352
353 // Don't let context track this because it is part of VAO state.
354 glBindBuffer(GL_ARRAY_BUFFER, buffer.bufferId);
355
356 for (const VertexElement& element : vertexFormat->elements) {
357
358 // Search for effect attribute location for this semantic/slot pair
359 GLint attributeLocation = -1;
360 for (size_t i = 0; i < effect.activeAttributes; i++) {
361 if (effect.attributeSemantic[i].semantic == uint32_t(element.semantic) &&
362 effect.attributeSemantic[i].slot == element.semanticIndex)
363 {
364 attributeLocation = effect.attributeLocation[i];
365 break;
366 }
367 }
368 if (attributeLocation == -1) { continue; } // Attribute not active
369
370 const OpenGLES30::DataFormatInfo format = OpenGLES30::DataFormats[size_t(element.format)];
371 if (format.isVertexFormat == 0) {
372 LOG_WARNING_ONCE(logger, "Encountered unsupported vertex format");
373 continue;
374 }
375
376 const GLvoid* attribOffset = reinterpret_cast<const GLvoid*>((size_t)element.offset + bufferOffset);
378 if (format.type == GL_FLOAT && format.components == 4 && format.columns == 4) {
379 for (GLuint a = 0; a < 4; a++) {
380 GLuint ix = attributeLocation + a;
381 glVertexAttribPointer(ix, 4, format.type, GL_TRUE, stride, reinterpret_cast<const GLvoid*>(sizeof(GLfloat) * a * 4));
382 glEnableVertexAttribArray(ix);
383 glVertexAttribDivisor(ix, element.instanceStep);
384 }
385 }
386 }
387 else {
388 if (format.columns == 1) {
389 if (format.isInteger) {
390 glVertexAttribIPointer(attributeLocation, format.components, format.type, stride, attribOffset);
391 }
392 else {
393 glVertexAttribPointer(attributeLocation, format.components, format.type, format.isNormalized ? GL_TRUE : GL_FALSE, stride, attribOffset);
394 }
395 glEnableVertexAttribArray(attributeLocation);
396 glVertexAttribDivisor(attributeLocation, element.instanceStep);
397 }
398 }
399 }
400 }
401
402 if (HandleIsValid(indexBufferHandle)) {
403 const BufferGLES30& buffer = buffers[IndexBufferHandle(indexBufferHandle)];
404
405 // Don't let context track this because it is part of VAO state.
406 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.bufferId);
407
408 vao.indexType = indexType;
409 switch (vao.indexType) {
410 case GL_UNSIGNED_SHORT:
411 vao.indexCount = GLsizei(buffer.size / 2);
412 vao.indexStride = indexStride;
413 break;
414 case GL_UNSIGNED_INT:
415 vao.indexCount = GLsizei(buffer.size / 4);
416 vao.indexStride = indexStride;
417 break;
418 default:
419 assert(false && "Illegal index type");
420 break;
421 }
422 }
423
424 glBindVertexArray(0);
425 context->vertexArrayObject.prevHandle = VertexArrayObjectHandle::NoHandle;
426 context->vertexArrayObject.currHandle = VertexArrayObjectHandle::NoHandle;
427 context->vertexArrayObject.indexType = GL_INVALID_ENUM;
428 context->vertexArrayObject.indexCount = 0;
429 context->vertexArrayObject.indexStride = 0;
430 return vertexArrayObjects.addResource(std::move(vao));
431}
432
434{
435 VertexArrayObjectGLES30& vao = vertexArrayObjects[vertexArrayObjectHandle];
436 glDeleteVertexArrays(1, &vao.glName);
437 vertexArrayObjects.removeResource(vertexArrayObjectHandle);
438}
439
Log implementation class.
Definition: LogManager.h:140
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:181
@ 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
EBindFlags
Bind flags enumeration.
Definition: Flags.h:64
@ 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:75
OpenGLES30::BufferTarget target
OpenGL bind target.
Definition: CommonGLES30.h:70
uint32_t bindFlags
Original Cogs::BindFlags bitmask used to create the buffer.
Definition: CommonGLES30.h:71
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:76
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:73
unsigned short writeBackMap
Set by map, if one, write back results to GL after unmap (i.e. map with write flags).
Definition: CommonGLES30.h:74
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:78
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:81
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