Cogs.Core
ContextGLES30.cpp
1#include "ContextGLES30.h"
2
3#include "BuffersGLES30.h"
4#include "TexturesGLES30.h"
5#include "EffectsGLES30.h"
6#include "RenderTargetsGLES30.h"
7#include "FormatsGLES30.h"
8#include "CapabilitiesGLES30.h"
9
10#ifdef EMSCRIPTEN
11#include <webgl/webgl2.h>
12#endif
13
14namespace
15{
16 Cogs::Logging::Log logger = Cogs::Logging::getLogger("ContextGLES30");
17
18 GLenum Blends[] = {
19 GL_ZERO,
20 GL_ONE,
21 GL_SRC_COLOR,
22 GL_ONE_MINUS_SRC_COLOR,
23 GL_SRC_ALPHA,
24 GL_ONE_MINUS_SRC_ALPHA,
25 GL_DST_ALPHA,
26 GL_ONE_MINUS_DST_ALPHA,
27 GL_DST_COLOR,
28 GL_ONE_MINUS_DST_COLOR,
29 GL_SRC_ALPHA_SATURATE,
30 GL_CONSTANT_COLOR,
31 GL_ONE_MINUS_CONSTANT_COLOR
32 };
33 static_assert(sizeof(Blends) == sizeof(Blends[0]) * size_t(Cogs::BlendState::Blend::Count));
34
35 GLenum BlendOperations[] = {
36 GL_FUNC_ADD,
37 GL_FUNC_SUBTRACT,
38 GL_FUNC_REVERSE_SUBTRACT,
39 GL_MIN,
40 GL_MAX
41 };
42 static_assert(sizeof(BlendOperations) == sizeof(BlendOperations[0]) * size_t(Cogs::BlendState::BlendOperation::Count));
43
44 GLenum DepthFunctions[] = {
45 GL_NEVER,
46 GL_LESS,
47 GL_LEQUAL,
48 GL_EQUAL,
49 GL_GEQUAL,
50 GL_GREATER,
51 GL_NOTEQUAL,
52 GL_ALWAYS,
53 };
54
55 GLenum glBufferTargets[] = {
56 GL_ARRAY_BUFFER,
57 GL_ELEMENT_ARRAY_BUFFER,
58 GL_UNIFORM_BUFFER,
59 GL_PIXEL_PACK_BUFFER,
60 GL_COPY_READ_BUFFER,
61 GL_COPY_WRITE_BUFFER,
62 GL_TRANSFORM_FEEDBACK_BUFFER
63 };
64 static_assert(sizeof(glBufferTargets) == sizeof(glBufferTargets[0]) * size_t(Cogs::OpenGLES30::BufferTarget::Count));
65
66 bool setupFramebuffer(Cogs::TextureGLES30& texture, GLenum framebufferTarget)
67 {
68 switch (texture.target) {
69 case GL_TEXTURE_2D:
70 if (texture.textureId == 0) {
71 LOG_ERROR_ONCE(logger, "Cannot resolve to/from null texture");
72 return false;
73 }
74 break;
75 case GL_RENDERBUFFER:
76 if (texture.renderBuffer == 0) {
77 LOG_ERROR_ONCE(logger, "Cannot resolve to/from null renderbuffer");
78 return false;
79 }
80 break;
81 default:
82 LOG_ERROR_ONCE(logger, "Cannot resolve to/from this kind of texture target");
83 return false;
84 }
85
86 glGenFramebuffers(1, &texture.fbo);
87 glBindFramebuffer(framebufferTarget, texture.fbo);
88
89 GLenum framebufferAttachment = (texture.flags & Cogs::TextureFlags::DepthBuffer) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0;
90
91 switch (texture.target) {
92 case GL_TEXTURE_2D:
93 glFramebufferTexture2D(framebufferTarget, framebufferAttachment, GL_TEXTURE_2D, texture.textureId, 0);
94 break;
95 case GL_RENDERBUFFER:
96 glFramebufferRenderbuffer(framebufferTarget, framebufferAttachment, GL_RENDERBUFFER, texture.renderBuffer);
97 break;
98 default:
99 assert(false);
100 break;
101 }
102
103 GLenum status = glCheckFramebufferStatus(framebufferTarget);
104 if (status != GL_FRAMEBUFFER_COMPLETE) {
105 LOG_ERROR_ONCE(logger, "Failed to set up framebuffer: %s", Cogs::OpenGLES30::framebuffersStatusString(status));
106 glBindFramebuffer(GL_FRAMEBUFFER, 0);
107 return false;
108 }
109
110 return true;
111 }
112
113
114}
115
116Cogs::IEffects* Cogs::ContextGLES30::getEffects() { return effects; }
117
119{
120 syncObjects->signal(fenceHandle);
121}
122
123void Cogs::ContextGLES30::setupVertexAttributes(size_t baseVertex)
124{
125 if (inputLayout.currHandle && currentEffect.ptr) {
126 const EffectGLES30* effect = currentEffect.ptr;
127
128 const InputLayoutGLES30& layout = buffers->inputLayouts[inputLayout.currHandle];
129
130 uint32_t attributeMask = 0;
131 if (vertexBuffers.count < layout.numFormats) {
132 LOG_ERROR_ONCE(logger, "vertexBufferCount=%u < inputLayout.numFormats=%zu", vertexBuffers.count, layout.numFormats);
133 }
134 else {
135
136 for (size_t b = 0; b < layout.numFormats; ++b) {
137 auto& vertexBuffer = vertexBuffers.currItems[b];
138
139 BufferGLES30& buffer = buffers->buffers[vertexBuffer.handle];
140 const VertexFormat* vertexFormat = layout.formats[b];// buffer.vertexFormat;
141 const GLsizei stride = vertexBuffer.stride ? vertexBuffer.stride : getSize(*vertexFormat);
142 const GLsizei bufferOffset = static_cast<GLsizei>(baseVertex) * stride + vertexBuffer.offset;
143 bindBuffer(OpenGLES30::BufferTarget::ArrayBuffer, buffer.bufferId);
144 for (const VertexElement& element : vertexFormat->elements) {
145
146 GLint attributeLocation = -1;
147 for (size_t i = 0; i < effect->activeAttributes; i++) {
148 if (effect->attributeSemantic[i].semantic == uint32_t(element.semantic) &&
149 effect->attributeSemantic[i].slot == element.semanticIndex)
150 {
151 attributeLocation = effect->attributeLocation[i];
152 break;
153 }
154 }
155 if (attributeLocation == -1) {
156 // Attribute not active
157 continue;
158 }
159
160 const OpenGLES30::DataFormatInfo format = OpenGLES30::DataFormats[size_t(element.format)];
161 if (format.isVertexFormat == 0) {
162 LOG_WARNING_ONCE(logger, "Encountered unsupported vertex format");
163 continue;
164 }
165
166 const GLvoid* attribOffset = reinterpret_cast<const GLvoid*>((size_t)element.offset + bufferOffset);
167
168 if (element.semantic == ElementSemantic::InstanceMatrix) {
169 if (format.type == GL_FLOAT && format.components == 4 && format.columns == 4) {
170 for (GLuint a = 0; a < 4; a++) {
171 GLuint ix = attributeLocation + a;
172 glVertexAttribPointer(ix, 4, format.type, GL_TRUE, stride, reinterpret_cast<const GLvoid*>(reinterpret_cast<size_t>(attribOffset) + sizeof(GLfloat) * a * 4));
173 glEnableVertexAttribArray(ix);
174 glVertexAttribDivisor(ix, element.instanceStep);
175 attributeMask |= 1 << ix;
176 }
177 }
178 }
179
180 else {
181 if (format.columns == 1) {
182 if (format.isInteger) {
183 glVertexAttribIPointer(attributeLocation, format.components, format.type, stride, attribOffset);
184 }
185 else {
186 glVertexAttribPointer(attributeLocation, format.components, format.type, format.isNormalized ? GL_TRUE : GL_FALSE, stride, attribOffset);
187 }
188 glEnableVertexAttribArray(attributeLocation);
189 glVertexAttribDivisor(attributeLocation, element.instanceStep);
190 attributeMask |= 1 << attributeLocation;
191 }
192 }
193
194 }
195 }
196 vertexBuffers.baseVertex = static_cast<uint32_t>(baseVertex);
197 }
198
199 uint32_t disable = currentAttributeMask & (~attributeMask);
200 while (disable) {
201#ifdef _WIN32
202 DWORD attributeIndex = 0;
203 _BitScanForward(&attributeIndex, disable);
204#else
205 uint32_t attributeIndex = __builtin_ctz(disable);
206#endif
207 assert((1 << attributeIndex) & disable);
208 disable &= ~(1 << attributeIndex);
209 glDisableVertexAttribArray(attributeIndex);
210 }
211 currentAttributeMask = attributeMask;
212
213 }
214 inputLayout.prevHandle = inputLayout.currHandle;
215
216 needVertexAttributeSetup = false;
217}
218
219GLenum Cogs::ContextGLES30::bindBuffer(OpenGLES30::BufferTarget target, GLuint buffer)
220{
221 GLenum glTarget = glBufferTargets[size_t(target)];
222 if (bufferTargets[size_t(target)].buffer != buffer) {
223 bufferTargets[size_t(target)].buffer = buffer;
224 glBindBuffer(glTarget, buffer);
225 }
226 return glTarget;
227}
228
229void Cogs::ContextGLES30::unbindBuffer(GLuint buffer)
230{
231 for (size_t target = 0; target < size_t(OpenGLES30::BufferTarget::Count); target++) {
232 if (bufferTargets[target].buffer == buffer) {
233 glBindBuffer(glBufferTargets[target], 0);
234 bufferTargets[target].buffer = ~0u;
235 }
236 }
237 for (size_t index = 0; index < size_t(OpenGLES30::maxUniformBuffers); index++) {
238 if (uniformBufferTargets[index].buffer == buffer) {
239 glBindBufferBase(GL_UNIFORM_BUFFER, GLuint(index), 0);
240 uniformBufferTargets[index].buffer = ~0u;
241 }
242 }
243}
244
245void Cogs::ContextGLES30::unbindVAO()
246{
247 if (vertexArrayObject.prevHandle != VertexArrayObjectHandle::NoHandle) {
248 vertexArrayObject.prevHandle = VertexArrayObjectHandle::NoHandle;
249 glBindVertexArray(0);
250
251 vertexArrayObject.indexType = GL_INVALID_ENUM;
252 vertexArrayObject.indexCount = 0;
253 vertexArrayObject.indexStride = 0;
254 bufferTargets[size_t(OpenGLES30::BufferTarget::ArrayBuffer)].buffer = ~0u;
255 bufferTargets[size_t(OpenGLES30::BufferTarget::ElementArrayBuffer)].buffer = ~0u;
256 }
257}
258
259
260void Cogs::ContextGLES30::setIndexBuffer(IndexBufferHandle indexBufferHandle, uint32_t stride, uint32_t offset)
261{
262 if (offset != 0) {
263 LOG_ERROR_ONCE(logger, "setIndexBuffer: Cannot bind index buffer with non-zero offset");
264 indexBufferHandle = IndexBufferHandle::InvalidHandle;
265 }
266
267 if (HandleIsValid(indexBufferHandle)) {
268 BufferGLES30& ixbuf = buffers->buffers[indexBufferHandle];
269 if (ixbuf.isIndexBuffer == 0) {
270 LOG_ERROR_ONCE(logger, "setIndexBuffer: Cannot bind non-index buffer as index buffer.");
271 indexBufferHandle = IndexBufferHandle::InvalidHandle;
272 }
273 }
274
275 vertexArrayObject.currHandle = VertexArrayObjectHandle::NoHandle;
276 indexBuffer.handle = indexBufferHandle;
277 indexBuffer.stride = stride;
278 indexBuffer.offset = offset;
279 needVertexAttributeSetup = true;
280}
281
282void Cogs::ContextGLES30::setConstantBuffer(const ConstantBufferBindingHandle bufferBindingHandle, const BufferHandle bufferHandle, const uint32_t offset, const uint32_t size)
283{
284 if (!HandleIsValid(bufferBindingHandle)) return;
285 if (!HandleIsValid(currentEffect.handle)) {
286 LOG_ERROR_ONCE(logger, "setConstantBuffer: Invalid effect handle");
287 return;
288 }
289 assert(currentEffect.ptr);
290
291 if (!HandleIsValid(bufferHandle)) {
292 LOG_ERROR_ONCE(logger, "setConstantBuffer: Invalid buffer handle");
293 return;
294 }
295 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
296 const GLuint index = static_cast<GLuint>(bufferBindingHandle.handle & 0xFFFFFFFF) - 1;
297 assert(index < OpenGLES30::maxUniformBuffers);
298 if ((uniformBufferTargets[index].buffer != buffer.bufferId) ||
299 (uniformBufferTargets[index].offset != offset) ||
300 (uniformBufferTargets[index].size != size))
301 {
302 uniformBufferTargets[index].buffer = buffer.bufferId;
303 uniformBufferTargets[index].offset = offset;
304 uniformBufferTargets[index].size = size;
305 if (offset == 0 && size == 0xffffffffu) {
306 glBindBufferBase(GL_UNIFORM_BUFFER, index, buffer.bufferId);
307 }
308 else {
309 GLsizeiptr _size = GLsizeiptr(size);
310 if (_size == (GLsizeiptr)0xffffffff) {
311 _size = GLsizeiptr(buffer.size - std::min(buffer.size, offset));
312 }
313 glBindBufferRange(GL_UNIFORM_BUFFER, index, buffer.bufferId, offset, _size);
314 }
315 }
316}
317
318bool Cogs::ContextGLES30::setupState()
319{
320 if (currBlendState.handle != nextBlendState.handle) {
321
322 // Blending setup has changed
323 if (HandleIsValid(nextBlendState.handle)) {
324 const BlendStateGLES30& blendState = renderTargets->blendStates[nextBlendState.handle];
325
326 if (currBlendState.state.enabled != blendState.enabled) {
327 currBlendState.state.enabled = blendState.enabled;
328 if (currBlendState.state.enabled) {
329 glEnable(GL_BLEND);
330 }
331 else {
332 glDisable(GL_BLEND);
333 }
334 }
335
336 if (currBlendState.state.enabled) {
337
338 if ((currBlendState.state.blend.colorSrc != blendState.blend.colorSrc) ||
339 (currBlendState.state.blend.colorDst != blendState.blend.colorSrc) ||
340 (currBlendState.state.blend.alphaSrc != blendState.blend.alphaSrc) ||
341 (currBlendState.state.blend.alphaDst != blendState.blend.alphaDst))
342 {
343 currBlendState.state.blend = blendState.blend;
344 glBlendFuncSeparate(Blends[size_t(currBlendState.state.blend.colorSrc)],
345 Blends[size_t(currBlendState.state.blend.colorDst)],
346 Blends[size_t(currBlendState.state.blend.alphaSrc)],
347 Blends[size_t(currBlendState.state.blend.alphaDst)]);
348 }
349
350 if ((currBlendState.state.operation.color != blendState.operation.color) ||
351 (currBlendState.state.operation.alpha != blendState.operation.alpha))
352 {
353 currBlendState.state.operation = blendState.operation;
354 glBlendEquationSeparate(BlendOperations[size_t(currBlendState.state.operation.color)],
355 BlendOperations[size_t(currBlendState.state.operation.alpha)]);
356 }
357
358 if ((currBlendState.constant[0] != nextBlendState.constant[0]) ||
359 (currBlendState.constant[1] != nextBlendState.constant[1]) ||
360 (currBlendState.constant[2] != nextBlendState.constant[2]) ||
361 (currBlendState.constant[3] != nextBlendState.constant[3]))
362 {
363 for (size_t i = 0; i < 4; i++) {
364 currBlendState.constant[i] = nextBlendState.constant[i];
365 }
366 glBlendColor(currBlendState.constant[0],
367 currBlendState.constant[1],
368 currBlendState.constant[2],
369 currBlendState.constant[3]);
370 }
371 }
372 }
373 else if (currBlendState.state.enabled) {
374 currBlendState.state.enabled = false;
375 glDisable(GL_BLEND);
376 }
377
378 currBlendState.handle = nextBlendState.handle;
379 }
380
381 return true;
382}
383
384bool Cogs::ContextGLES30::setupDraw(size_t baseVertex)
385{
386 if (!setupState()) {
387 return false;
388 }
389
390 // --- Give up with no effect
391 if (!HandleIsValid(currentEffect.handle)) {
392 LOG_ERROR_ONCE(logger, "setupIndexedDraw: No valid effect.");
393 return false;
394 }
395
396 // --- Give up with invalid VAO
397 if (vertexArrayObject.currHandle == VertexArrayObjectHandle::InvalidHandle) {
398 LOG_ERROR_ONCE(logger, "setupIndexedDraw: Invalid vertex array object");
399 return false;
400 }
401
402 // --- Set up VAO rendering
403 else if (vertexArrayObject.currHandle != VertexArrayObjectHandle::NoHandle) {
404
405 if (baseVertex != 0) {
406 LOG_ERROR_ONCE(logger, "Unhandled VAO rendering with base vertex %zu != 0", baseVertex);
407 }
408
409 if (vertexArrayObject.prevHandle != vertexArrayObject.currHandle) {
410 vertexArrayObject.prevHandle = vertexArrayObject.currHandle;
411 VertexArrayObjectGLES30& vao = buffers->vertexArrayObjects[vertexArrayObject.currHandle];
412 glBindVertexArray(vao.glName);
413 vertexArrayObject.indexType = vao.indexType;
414 vertexArrayObject.indexCount = vao.indexCount;
415 vertexArrayObject.indexStride = vao.indexStride;
416 }
417 }
418
419 // --- Set up non-VAO rendering with data from setVertexBuffer / set IndexBuffer
420 else {
421 unbindVAO();
422
423 needVertexAttributeSetup = needVertexAttributeSetup || (vertexBuffers.baseVertex != baseVertex);
424 if (needVertexAttributeSetup) { setupVertexAttributes(baseVertex); }
425 }
426
427 return true;
428}
429
430bool Cogs::ContextGLES30::setupIndexedDraw(GLenum& indexType, GLsizei& indexCount, const GLvoid*& indexOffset, const size_t startIndex, const size_t numIndices, const size_t baseVertex)
431{
432 if (!setupState()) {
433 return false;
434 }
435
436 indexType = GL_INVALID_ENUM;
437 indexCount = 0;
438 indexOffset = nullptr;
439
440 // --- Give up with no effect
441 if (!HandleIsValid(currentEffect.handle)) {
442 LOG_ERROR_ONCE(logger, "setupIndexedDraw: No valid effect.");
443 return false;
444 }
445
446 // --- Give up with invalid VAO
447 if (vertexArrayObject.currHandle == VertexArrayObjectHandle::InvalidHandle) {
448 LOG_ERROR_ONCE(logger, "setupIndexedDraw: Invalid vertex array object");
449 return false;
450 }
451
452 // --- Set up VAO rendering
453 else if (vertexArrayObject.currHandle != VertexArrayObjectHandle::NoHandle) {
454
455 if (vertexArrayObject.prevHandle != vertexArrayObject.currHandle) {
456 VertexArrayObjectGLES30& vao = buffers->vertexArrayObjects[vertexArrayObject.currHandle];
457 if (!((vao.indexType == GL_UNSIGNED_SHORT) || (vao.indexType == GL_UNSIGNED_INT))) {
458 LOG_ERROR_ONCE(logger, "setupIndexedDraw: Vertex array object does not contain an index buffer");
459 return false;
460 }
461 vertexArrayObject.prevHandle = vertexArrayObject.currHandle;
462 glBindVertexArray(vao.glName);
463 vertexArrayObject.indexType = vao.indexType;
464 vertexArrayObject.indexCount = vao.indexCount;
465 vertexArrayObject.indexStride = vao.indexStride;
466 }
467
468 const size_t stride = vertexArrayObject.indexStride ? vertexArrayObject.indexStride : (vertexArrayObject.indexType == GL_UNSIGNED_INT ? sizeof(GLuint) : sizeof(GLushort));
469 indexType = vertexArrayObject.indexType;
470 indexCount = static_cast<GLsizei>(numIndices ? numIndices : vertexArrayObject.indexCount);
471 indexOffset = reinterpret_cast<const GLvoid*>(startIndex * stride);
472 }
473
474 // --- Set up non-VAO rendering with data from setVertexBuffer / set IndexBuffer
475 else {
476 unbindVAO();
477 needVertexAttributeSetup = needVertexAttributeSetup || (vertexBuffers.baseVertex != baseVertex);
478 if (needVertexAttributeSetup) { setupVertexAttributes(baseVertex); }
479
480 if (!indexBuffer.handle) {
481 LOG_ERROR_ONCE(logger, "setupIndexedDraw: No index buffer bound.");
482 return false;
483 }
484
485 const auto& buffer = buffers->buffers[indexBuffer.handle];
486 bindBuffer(OpenGLES30::BufferTarget::ElementArrayBuffer, buffer.bufferId);
487 const size_t stride = indexBuffer.stride ? indexBuffer.stride : (indexType == GL_UNSIGNED_INT ? sizeof(GLuint) : sizeof(GLushort));
488 indexType = buffer.indexType;
489 indexCount = static_cast<GLsizei>(numIndices ? numIndices : buffer.size / stride);
490 indexOffset = reinterpret_cast<const GLvoid*>(startIndex * stride);
491 }
492
493 return true;
494}
495
496void Cogs::ContextGLES30::draw(PrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes)
497{
498 if (!setupDraw(0)) return;
499
500 const GLenum glPrimitiveType = OpenGLES30::PrimitiveFormats[static_cast<uint32_t>(primitiveType)];
501 glDrawArrays(currentRasterizerState.wireFrame ? GL_LINES : glPrimitiveType, static_cast<GLint>(startVertex), static_cast<GLsizei>(numVertexes));
502
503 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numVertexes, false); }
504}
505
506void Cogs::ContextGLES30::drawIndexed(PrimitiveType primitiveType, const size_t startIndex, const size_t numIndices, const size_t baseVertex)
507{
508 GLenum indexType = GL_INVALID_ENUM;
509 GLsizei indexCount = 0;
510 const GLvoid* indexOffset = nullptr;
511 if (!setupIndexedDraw(indexType, indexCount, indexOffset, startIndex, numIndices, baseVertex)) return;
512
513 const GLenum glPrimitiveType = OpenGLES30::PrimitiveFormats[static_cast<uint32_t>(primitiveType)];
514 glDrawElements(currentRasterizerState.wireFrame ? GL_LINES : glPrimitiveType, indexCount, indexType, indexOffset);
515
516 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndices, true); }
517}
518
519void Cogs::ContextGLES30::drawInstanced(PrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes, const size_t startInstance, const size_t numInstances)
520{
521 if (startInstance != 0) {
522 LOG_ERROR_ONCE(logger, "drawInstanced: GLES30 does not support nonzero start instance");
523 return;
524 }
525
526 if (!setupDraw(0)) return;
527
528 const GLenum glPrimitiveType = OpenGLES30::PrimitiveFormats[static_cast<uint32_t>(primitiveType)];
529 glDrawArraysInstanced(currentRasterizerState.wireFrame ? GL_LINES : glPrimitiveType, static_cast<GLint>(startVertex), static_cast<GLsizei>(numVertexes), static_cast<GLsizei>(numInstances));
530
531 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numVertexes, false); }
532}
533
534void Cogs::ContextGLES30::drawInstancedIndexed(PrimitiveType primitiveType, const size_t startInstance, const size_t numInstances, const size_t startIndex, const size_t numIndices)
535{
536 if (startInstance != 0) {
537 LOG_ERROR_ONCE(logger, "drawInstancedIndexed: GLES30 does not support nonzero start instance");
538 return;
539 }
540
541 GLenum indexType = GL_INVALID_ENUM;
542 GLsizei indexCount = 0;
543 const GLvoid* indexOffset = nullptr;
544 if (!setupIndexedDraw(indexType, indexCount, indexOffset, startIndex, numIndices, 0)) return;
545
546 const GLenum glPrimitiveType = OpenGLES30::PrimitiveFormats[static_cast<uint32_t>(primitiveType)];
547 glDrawElementsInstanced(currentRasterizerState.wireFrame ? GL_LINES : glPrimitiveType, indexCount, indexType, indexOffset, static_cast<GLsizei>(numInstances));
548
549 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndices, true); }
550}
551
552void Cogs::ContextGLES30::setVertexBuffers(const VertexBufferHandle * handles, const size_t count)
553{
554 vertexArrayObject.currHandle = VertexArrayObjectHandle::NoHandle;
555 vertexBuffers.count = uint32_t(count);
556 for (size_t i = 0; i < count; i++) {
557 vertexBuffers.currItems[i].handle = handles[i];
558 vertexBuffers.currItems[i].stride = 0;
559 vertexBuffers.currItems[i].offset = 0;
560 }
561 needVertexAttributeSetup = true;
562}
563
564void Cogs::ContextGLES30::setVertexBuffers(const VertexBufferHandle* handles, const size_t count, const uint32_t* strides, const uint32_t* offsets)
565{
566 vertexArrayObject.currHandle = VertexArrayObjectHandle::NoHandle;
567 vertexBuffers.count = uint32_t(count);
568 for (size_t i = 0; i < count; i++) {
569 vertexBuffers.currItems[i].handle = handles[i];
570 vertexBuffers.currItems[i].stride = strides[i];
571 vertexBuffers.currItems[i].offset = offsets ? offsets[i] : 0;
572 }
573 needVertexAttributeSetup = true;
574}
575
577{
578 vertexArrayObject.currHandle = vertexArrayObjectHandle;
579 needVertexAttributeSetup = true;
580}
581
582void Cogs::ContextGLES30::setBlendState(const BlendStateHandle handle, const float* constant)
583{
584 nextBlendState.handle = handle;
585 for (size_t i = 0; i < 4; i++) {
586 nextBlendState.constant[i] = constant ? constant[i] : 0.f;
587 }
588}
589
591{
592 assert(!inRenderPass);
593 if (renderTargets->bindRenderTargets(info.renderTargetHandle, info.depthStencilHandle)) {
594 currentRenderTarget = info.renderTargetHandle;
595 currentDepthStencilTarget = info.depthStencilHandle;
596 }
597 else {
598 currentRenderTarget = RenderTargetHandle::InvalidHandle;
599 currentDepthStencilTarget = DepthStencilHandle::InvalidHandle;
600 glBindFramebuffer(GL_FRAMEBUFFER, 0);
601 }
602 {
603 auto & renderTarget = renderTargets->renderTargets[currentRenderTarget];
604 for (int i = 0; i < renderTarget.numViews; ++i) {
605 if(info.loadOp[i] == LoadOp::Clear){
606 glClearBufferfv(GL_COLOR, i, info.clearValue[i]);
607 }
608 }
609 }
610 if(info.depthLoadOp == LoadOp::Clear){
611 clearDepth(info.depthClearValue);
612 }
613 inRenderPass = true;
614 renderPassInfo = info;
615}
616
618{
619 assert(inRenderPass);
620 if(HandleIsValid(renderPassInfo.renderTargetHandle)){
621 RenderTargetGLES30 &target = renderTargets->renderTargets[renderPassInfo.renderTargetHandle];
622 for(size_t i=0; i<target.numViews; i++){
623 if(HandleIsValid(renderPassInfo.resolveHandle[i])){
624 TextureViewDescription &view = textures->views[renderPassInfo.resolveHandle[i]];
625 // Only resolve of default views is supported at the moment for GLES30
626 assert(view.layerIndex == 0);
627 assert(view.numLayers == 1);
628 assert(view.levelIndex == 0);
629 assert(view.numLevels == 1);
630 assert(target.views[i].layerIndex == 0);
631 assert(target.views[i].numLayers == 1);
632 assert(target.views[i].levelIndex == 0);
633 resolveResource(target.views[i].texture, view.texture);
634 }
635 }
636 }
637 inRenderPass = false;
638 renderPassInfo = {};
639}
640
641void Cogs::ContextGLES30::setRenderTarget(const RenderTargetHandle renderTargetHandle, const DepthStencilHandle depthStencilHandle)
642{
643 if (currentRenderTarget != renderTargetHandle || currentDepthStencilTarget != depthStencilHandle) {
644
645 if (renderTargets->bindRenderTargets(renderTargetHandle, depthStencilHandle)) {
646 currentRenderTarget = renderTargetHandle;
647 currentDepthStencilTarget = depthStencilHandle;
648 }
649 else {
650 currentRenderTarget = RenderTargetHandle::InvalidHandle;
651 currentDepthStencilTarget = DepthStencilHandle::InvalidHandle;
652 glBindFramebuffer(GL_FRAMEBUFFER, 0);
653 }
654 }
655}
656
657void Cogs::ContextGLES30::setViewport(const float x, const float y, const float width, const float height)
658{
659 // NOTE: There seems to be a problem when setting the window framebuffer viewport outside an actual context resize.
660 glViewport(static_cast<GLsizei>(x), static_cast<GLsizei>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height));
661}
662
663void Cogs::ContextGLES30::setScissor(const int x, const int y, const int width, const int height)
664{
665 glScissor(x, y, width, height);
666}
667
669{
670 size_t bufferCount = 1;
671 if (HandleIsValid(currentRenderTarget)) {
672 RenderTargetGLES30& renderTarget = renderTargets->renderTargets[currentRenderTarget];
673 bufferCount = renderTarget.numViews;
674 }
675 for (size_t i = 0; i < bufferCount; i++) {
676 glClearBufferfv(GL_COLOR, GLint(i), color);
677 }
678}
679
680void Cogs::ContextGLES30::clearRenderTarget(const float ** colors, int count)
681{
682 if (count < 1) return;
683
684 if (HandleIsValid(currentRenderTarget)) {
685 RenderTargetGLES30& renderTarget = renderTargets->renderTargets[currentRenderTarget];
686
687 GLint n = std::min(GLint(renderTarget.numViews), GLint(count));
688
689 for (GLint i = 0; i < n; ++i) {
690 switch (renderTarget.viewData[i].basicType) {
691 case 0:
692 break;
693 case 1:
694 glClearBufferfv(GL_COLOR, i, colors[i]);
695 break;
696 case 2: {
697 uint32_t ucolors[4] = {
698 static_cast<uint32_t>(colors[i][0]),
699 static_cast<uint32_t>(colors[i][1]),
700 static_cast<uint32_t>(colors[i][2]),
701 static_cast<uint32_t>(colors[i][3])
702 };
703 glClearBufferuiv(GL_COLOR, i, ucolors);
704 break;
705 }
706 case 3: // sint
707 int32_t icolors[4] = {
708 static_cast<int32_t>(colors[i][0]),
709 static_cast<int32_t>(colors[i][1]),
710 static_cast<int32_t>(colors[i][2]),
711 static_cast<int32_t>(colors[i][3])
712 };
713 glClearBufferiv(GL_COLOR, i, icolors);
714 break;
715 }
716 }
717 }
718 else {
719 glClearBufferfv(GL_COLOR, 0, colors[0]);
720 }
721}
722
723void Cogs::ContextGLES30::clearDepth(const float depth)
724{
725 glDepthMask(GL_TRUE);
726 glClearBufferfv(GL_DEPTH, 0, &depth);
727}
728
729
731{
732 if (currentEffect.handle == effectHandle) return;
733
734 if (effectHandle == EffectHandle::InvalidHandle) {
735 LOG_ERROR_ONCE(logger, "Cannot set invalid effect.");
736 currentEffect.handle = EffectHandle::NoHandle;
737 currentEffect.ptr = nullptr;
738 return;
739 }
740 assert((effects->delayFrames == 0 || effects->checkEffect(effectHandle) == ResourceStatus::Ready) &&
741 "Effect used before it finished (fake-async) loading");
742
743 currentEffect.handle = effectHandle;
744 if (effectHandle) {
745 currentEffect.ptr = &effects->effects[effectHandle];
746 glUseProgram(currentEffect.ptr->programId);
747 }
748 else {
749 currentEffect.ptr = nullptr;
750 glUseProgram(0);
751 }
752 needVertexAttributeSetup = true;
753}
754
755
756void Cogs::ContextGLES30::setTexture(const TextureBindingHandle textureBindingHandle, const TextureHandle textureHandle)
757{
758 if (!HandleIsValid(currentEffect.handle)) {
759 LOG_ERROR_ONCE(logger, "setTexture: Current effect handle is invalid");
760 return;
761 }
762 if (textureBindingHandle == TextureBindingHandle::NoHandle) {
763 return;
764 }
765 else if (textureBindingHandle == TextureBindingHandle::InvalidHandle) {
766 LOG_ERROR_ONCE(logger, "setTexture: Texture binding handle is invalid");
767 return;
768 }
769
770 GLint unit = GLint(textureBindingHandle.handle - 1);
771 assert(0 <= unit && unit < GLint(OpenGLES30::maxTexUnits));
772 bindTexture(textureHandle, unit);
773}
774
775void Cogs::ContextGLES30::setTexture(const TextureBindingHandle textureBindingHandle, TextureViewHandle textureViewHandle)
776{
777 if (!HandleIsValid(currentEffect.handle) || !HandleIsValid(textureBindingHandle) || !HandleIsValid(textureViewHandle)) return;
778
779 TextureViewDescription& view = textures->views[textureViewHandle];
780
781 GLint unit = GLint(textureBindingHandle.handle - 1);
782 assert(0 <= unit && unit < GLint(OpenGLES30::maxTexUnits));
783
784 TextureGLES30* texture = bindTexture(view.texture, unit);
785 if (texture) {
786 glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, view.levelIndex);
787 glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, view.levelIndex + view.numLevels - 1);
788 texture->boundAsView = 1;
789 }
790}
791
792Cogs::TextureGLES30* Cogs::ContextGLES30::bindTexture(TextureHandle textureHandle, GLuint unit)
793{
794 if (unit == GLuint(~0u)) {
795 unit = activeTexUnit;
796 }
797 assert(unit < OpenGLES30::maxTexUnits);
798
799 TextureGLES30* texture = nullptr;
800 if (HandleIsValid(textureHandle)) {
801 texture = &textures->textures[textureHandle];
802 }
803 if (texture && texture->target == GL_RENDERBUFFER) {
804 LOG_ERROR_ONCE(logger, "Cannot bind a renderBuffer as a texture sampler");
805 return nullptr;
806 }
807
808 // Early out if we do not change any state
809 if (texUnits[unit].texture == textureHandle && (texture == nullptr || texture->boundAsView == 0)) {
810 return texture;
811 }
812
813 // Switch texture unit if needed
814 if (activeTexUnit != unit) {
815 glActiveTexture(GL_TEXTURE0 + unit);
816 activeTexUnit = unit;
817 }
818
819 // We are binding to a texture
820 if (texture) {
821
822 // If a texture was bound to the unit but to a different target, set the old target to null
823 if (HandleIsValid(texUnits[unit].texture) && texUnits[unit].target != texture->target) {
824 glBindTexture(texUnits[unit].target, 0);
825 }
826
827 glBindTexture(texture->target, texture->textureId);
828 texUnits[unit].target = texture->target;
829 texUnits[unit].texture = textureHandle;
830
831 // If the texture was bound as a view, we remove the view
832 if (texture->boundAsView) {
833 glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0);
834 glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, 1000);
835 texture->boundAsView = 0;
836 }
837
838 return texture;
839 }
840
841 // Unbind a unit
842 else if (textureHandle == TextureHandle::InvalidHandle) {
843 LOG_WARNING_ONCE(logger, "setTexture: Invalid texture handle");
844 }
845
846 if (HandleIsValid(texUnits[unit].texture)) {
847 glBindTexture(texUnits[unit].target, 0);
848 }
849 texUnits[unit].target = GL_TEXTURE_2D;
850 texUnits[unit].texture = TextureHandle::NoHandle;
851
852 return nullptr;
853}
854
855void Cogs::ContextGLES30::setSamplerState(const SamplerStateBindingHandle samplerStateBindingHandle, const SamplerStateHandle samplerStateHandle)
856{
857 if (!samplerStateBindingHandle) return;
858
859 const GLint unit = static_cast<GLint>(samplerStateBindingHandle.handle - 1);
860 assert(0 <= unit && unit < GLint(OpenGLES30::maxTexUnits));
861
862 if (texUnits[unit].sampler != samplerStateHandle) {
863 texUnits[unit].sampler = samplerStateHandle;
864 if (HandleIsValid(samplerStateHandle)) {
865 const SamplerGLES30& sampler = textures->samplers[samplerStateHandle];
866 glBindSampler(unit, sampler.glName);
867 }
868 else {
869 glBindSampler(unit, 0);
870 }
871 }
872}
873
875{
876 const RasterizerState & rasterizerState = (handle == RasterizerStateHandle::NoHandle) ? RasterizerState::DefaultState() : this->renderTargets->rasterizerStates[handle];
877
878 currentRasterizerState.wireFrame = rasterizerState.wireFrame;
879
880 if (currentRasterizerState.frontCounterClockwise != rasterizerState.frontCounterClockwise) {
881 currentRasterizerState.frontCounterClockwise = rasterizerState.frontCounterClockwise;
882 glFrontFace(currentRasterizerState.frontCounterClockwise ? GL_CCW : GL_CW);
883 }
884
885 if (currentRasterizerState.cullMode != rasterizerState.cullMode) {
886 currentRasterizerState.cullMode = rasterizerState.cullMode;
887 switch (rasterizerState.cullMode)
888 {
890 glDisable(GL_CULL_FACE);
891 break;
892
894 glEnable(GL_CULL_FACE);
895 glCullFace(GL_FRONT);
896 break;
897
898 default:
899 glEnable(GL_CULL_FACE);
900 glCullFace(GL_BACK);
901 break;
902 }
903 }
904
905 if (currentRasterizerState.noDepthClip != rasterizerState.noDepthClip) {
906 currentRasterizerState.noDepthClip = rasterizerState.noDepthClip;
907 if (capabilities->getDeviceCapabilities().NoDepthClip) {
908 if (currentRasterizerState.noDepthClip) {
909 glEnable(GL_DEPTH_CLAMP_EXT);
910 }
911 else {
912 glDisable(GL_DEPTH_CLAMP_EXT);
913 }
914 }
915 }
916
917 if ((currentRasterizerState.depthBias != rasterizerState.depthBias) ||
918 (currentRasterizerState.slopeScaledDepthBias != rasterizerState.slopeScaledDepthBias))
919 {
920 currentRasterizerState.depthBias = rasterizerState.depthBias;
921 currentRasterizerState.slopeScaledDepthBias = rasterizerState.slopeScaledDepthBias;
922 if ((currentRasterizerState.depthBias != 0.f) || (currentRasterizerState.slopeScaledDepthBias != 0.f))
923 {
924 glEnable(GL_POLYGON_OFFSET_FILL);
925 glPolygonOffset(currentRasterizerState.slopeScaledDepthBias, currentRasterizerState.depthBias);
926 }
927 else {
928 glPolygonOffset(0, 0);
929 glDisable(GL_POLYGON_OFFSET_FILL);
930 }
931 }
932
933 if (currentRasterizerState.scissor != rasterizerState.scissor) {
934 currentRasterizerState.scissor = rasterizerState.scissor;
935 if (currentRasterizerState.scissor) {
936 glEnable(GL_SCISSOR_TEST);
937 }
938 else {
939 glDisable(GL_SCISSOR_TEST);
940 }
941 }
942}
943
945{
946 inputLayout.currHandle = handle;
947}
948
949void Cogs::ContextGLES30::resolveResource(TextureHandle sourceTextureHandle, TextureHandle targetTextureHandle)
950{
951 TextureGLES30 & sourceTexture = this->textures->textures[sourceTextureHandle];
952 TextureGLES30 & targetTexture = this->textures->textures[targetTextureHandle];
953
954 if (1 < targetTexture.numSamples) {
955 LOG_ERROR_ONCE(logger, "Cannot resolve to multisample target");
956 return;
957 }
958 if (sourceTexture.width != targetTexture.width || sourceTexture.height != targetTexture.height) {
959 LOG_ERROR_ONCE(logger, "Cannot resolve to texture of different size");
960 return;
961 }
962 if (targetTexture.textureId == 0) {
963 LOG_ERROR_ONCE(logger, "Cannot resolve to null texture");
964 return;
965 }
966
967 // Set up source for resolve blit
968 if (sourceTexture.fbo) {
969 glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceTexture.fbo);
970 }
971 else if (!setupFramebuffer(sourceTexture, GL_READ_FRAMEBUFFER)) {
972 return; // Failed
973 }
974
975 // Set up target for resolve blit
976 if (targetTexture.fbo) {
977 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetTexture.fbo);
978 }
979 else if (!setupFramebuffer(targetTexture, GL_DRAW_FRAMEBUFFER)) {
980 return; // Failed
981 }
982
983 // Do resolve
984 if (targetTexture.flags & TextureFlags::DepthBuffer) {
985
986 glClear(GL_DEPTH_BUFFER_BIT); // Break dependency chain
987 glBlitFramebuffer(0, 0, sourceTexture.width, sourceTexture.height,
988 0, 0, targetTexture.width, targetTexture.height,
989 GL_DEPTH_BUFFER_BIT, GL_NEAREST);
990 }
991 else {
992 glClear(GL_COLOR_BUFFER_BIT); // Break dependency chain
993 glBlitFramebuffer(0, 0, sourceTexture.width, sourceTexture.height,
994 0, 0, targetTexture.width, targetTexture.height,
995 GL_COLOR_BUFFER_BIT, GL_NEAREST);
996 }
997 glBindFramebuffer(GL_FRAMEBUFFER, 0);
998}
999
1000void Cogs::ContextGLES30::setDefaults()
1001{
1002 if (emptyUniformBuffer == BufferHandle::NoHandle) {
1003 emptyUniformBuffer = buffers->loadBuffer(nullptr,
1004 0x4000, // GL minimum size
1008 }
1010
1011 setRasterizerState(RasterizerStateHandle::NoHandle);
1012 currentRasterizerState.frontCounterClockwise = false;
1013 currentRasterizerState.cullMode = RasterizerState::CullMode::None;
1014 currentRasterizerState.depthBias = 0.0;
1015 currentRasterizerState.slopeScaledDepthBias = 0.0;
1016 currentRasterizerState.scissor = false;
1017 currentRasterizerState.wireFrame = false;
1018 currentRasterizerState.noDepthClip = false;
1019 glFrontFace(GL_CW);
1020 glDisable(GL_CULL_FACE);
1021 glDisable(GL_POLYGON_OFFSET_FILL);
1022 glDisable(GL_SCISSOR_TEST);
1023 if (capabilities->getDeviceCapabilities().NoDepthClip) {
1024 glDisable(GL_DEPTH_CLAMP_EXT);
1025 }
1026
1027 { // Blend state
1028 currBlendState.handle = BlendStateHandle::NoHandle;
1029 currBlendState.state.blend = { BlendState::Blend::One, BlendState::Blend::Zero, BlendState::Blend::One, BlendState::Blend::Zero };
1030 currBlendState.state.operation = { BlendState::BlendOperation::Add, BlendState::BlendOperation::Add };
1031 currBlendState.state.enabled = false;
1032 nextBlendState.handle = BlendStateHandle::NoHandle;
1033 glDisable(GL_BLEND);
1034 glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
1035 glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
1036 glBlendColor(0.f, 0.f, 0.f, 0.f);
1037 }
1038
1039 setDepthStencilState(DepthStencilStateHandle::NoHandle);
1040 currentDepthStencilState.depthEnabled = true;
1041 currentDepthStencilState.writeEnabled = true;
1042 currentDepthStencilState.depthFunction = DepthStencilState::DepthFunction::Less;
1043 glEnable(GL_DEPTH_TEST);
1044 glDepthMask(GL_TRUE);
1045 glDepthFunc(GL_LESS);
1046
1047 activeTexUnit = 0;
1048 glActiveTexture(GL_TEXTURE0);
1049
1050 vertexArrayObject.prevHandle = VertexArrayObjectHandle::NoHandle;
1051 vertexArrayObject.currHandle = VertexArrayObjectHandle::NoHandle;
1052 glBindVertexArray(0);
1053
1054 inputLayout.prevHandle = InputLayoutHandle::NoHandle;
1055 inputLayout.currHandle = InputLayoutHandle::NoHandle;
1056
1057 indexBuffer.handle = IndexBufferHandle::NoHandle;
1058
1059 currentEffect.handle = EffectHandle::NoHandle;
1060 currentEffect.ptr = nullptr;
1061 glUseProgram(0);
1062
1063 for (size_t i = 0; i < size_t(OpenGLES30::BufferTarget::Count); i++) {
1064 glBindBuffer(glBufferTargets[i], 0);
1065 bufferTargets[i].buffer = 0;
1066 }
1067
1068 for (GLuint i = 0; i < OpenGLES30::maxUniformBuffers; i++) {
1069 if (uniformBufferTargets[i].buffer) {
1070 glBindBufferBase(GL_UNIFORM_BUFFER, i, 0);
1071 }
1072 uniformBufferTargets[i].buffer = 0;
1073 uniformBufferTargets[i].offset = 0;
1074 uniformBufferTargets[i].size = ~0u;
1075 }
1076
1077 // Bind empty uniform buffer to slot index 0, which is the slot-index
1078 // which we use for unused buffers.
1079 if (HandleIsValid(emptyUniformBuffer)) {
1080 const BufferGLES30& buffer = buffers->buffers[emptyUniformBuffer];
1081 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer.bufferId);
1082 }
1083
1084}
1085
1087{
1088 for (GLuint i = 0; i < OpenGLES30::maxTexUnits; i++) {
1089 if (texUnits[i].texture != TextureHandle::NoHandle || texUnits[i].sampler != SamplerStateHandle::NoHandle) {
1090 glActiveTexture(GL_TEXTURE0 + i);
1091 glBindTexture(texUnits[i].target, 0);
1092 texUnits[i].target = GL_TEXTURE_2D;
1093 texUnits[i].texture = TextureHandle::NoHandle;
1094
1095 glBindSampler(i, 0);
1096 texUnits[i].sampler = SamplerStateHandle::NoHandle;
1097 }
1098 }
1099 activeTexUnit = 0;
1100 glActiveTexture(GL_TEXTURE0);
1101
1102 vertexArrayObject.prevHandle = VertexArrayObjectHandle::NoHandle;
1103 vertexArrayObject.currHandle = VertexArrayObjectHandle::NoHandle;
1104 glBindVertexArray(0);
1105
1106 for (GLenum i = 0; i < OpenGLES30::maxVertexAttributes; i++) {
1107 vertexBuffers.currItems[i].handle = VertexBufferHandle::NoHandle;
1108 if (currentAttributeMask & (1 << i)) {
1109 glDisableVertexAttribArray(i);
1110 }
1111 }
1112 vertexBuffers.count = 0;
1113 currentAttributeMask = 0;
1114
1115 currentEffect.handle = EffectHandle::NoHandle;
1116 currentEffect.ptr = nullptr;
1117 glUseProgram(0);
1118}
1119
1121{
1122 DepthStencilState depthStencilState = (handle == DepthStencilStateHandle::NoHandle) ? DepthStencilState::DefaultState() : this->renderTargets->depthStencilStates[handle];
1123
1124 if (currentDepthStencilState.depthEnabled != depthStencilState.depthEnabled) {
1125 currentDepthStencilState.depthEnabled = depthStencilState.depthEnabled;
1126 if (currentDepthStencilState.depthEnabled) {
1127 glEnable(GL_DEPTH_TEST);
1128 }
1129 else {
1130 glDisable(GL_DEPTH_TEST);
1131 }
1132 }
1133
1134 if (currentDepthStencilState.depthEnabled) {
1135
1136 // Depth is never written with depth test enabled, use ALWAYS test to write unconditionally.
1137 if (currentDepthStencilState.writeEnabled != depthStencilState.writeEnabled) {
1138 currentDepthStencilState.writeEnabled = depthStencilState.writeEnabled;
1139 if (currentDepthStencilState.writeEnabled) {
1140 glDepthMask(GL_TRUE);
1141 }
1142 else {
1143 glDepthMask(GL_FALSE);
1144 }
1145 }
1146
1147 // Depth test function only necessary to set when depth test is enabled
1148 if (currentDepthStencilState.depthFunction != depthStencilState.depthFunction) {
1149 currentDepthStencilState.depthFunction = depthStencilState.depthFunction;
1150 glDepthFunc(DepthFunctions[currentDepthStencilState.depthFunction]);
1151 }
1152 }
1153}
1154
1155void Cogs::ContextGLES30::readDepthBuffer(BufferHandle /*bufferHandle*/, int /*x*/, int /*y*/, int /*width*/, int /*height*/, Framebuffer /*framebuffer*/)
1156{
1157 LOG_ERROR_ONCE(logger, "Reading of depth buffer is not supported");
1158}
1159
1160void Cogs::ContextGLES30::readColorBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer /*framebuffer*/)
1161{
1162
1163 if (!HandleIsValid(bufferHandle)) return;
1164 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
1165
1166 size_t elementSize = 4;
1167 GLenum source = GL_BACK;
1168 GLenum format = GL_RGBA;
1169 GLenum type = GL_UNSIGNED_BYTE;
1170
1171 if (currentRenderTarget == RenderTargetHandle::InvalidHandle) {
1172 LOG_ERROR_ONCE(logger, "Reading color buffer of invalid render target");
1173 return;
1174 }
1175
1176 if (HandleIsValid(currentRenderTarget)) {
1177 const RenderTargetGLES30& renderTarget = this->renderTargets->renderTargets[this->currentRenderTarget];
1178
1179 source = GL_COLOR_ATTACHMENT0;
1180
1181 if (renderTarget.numViews && HandleIsValid(renderTarget.views[0].texture)) {
1182 const TextureGLES30& texture = textures->textures[renderTarget.views[0].texture];
1183 elementSize = getFormatInfo(texture.format)->blockSize;
1184 format = OpenGLES30::DataFormats[size_t(texture.format)].format;
1185 type = OpenGLES30::DataFormats[size_t(texture.format)].type;
1186 }
1187 }
1188
1189 if (buffer.size < elementSize * width * height) {
1190 LOG_ERROR_ONCE(logger, "Color buffer read is larger than buffer size.");
1191 return;
1192 }
1193
1194 glReadBuffer(source);
1195 bindBuffer(OpenGLES30::BufferTarget::PixelPackBuffer, buffer.bufferId);
1196 glReadPixels(x, y, width, height, format, type, nullptr);
1197}
1198
1199void* Cogs::ContextGLES30::map(BufferHandle bufferHandle, MapMode::EMapMode mapMode, uint32_t* /*stride*/)
1200{
1201 if (!HandleIsValid(bufferHandle)) return nullptr;
1202
1203
1204 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
1205 if (buffer.isMapped) {
1206 LOG_ERROR_ONCE(logger, "Buffers can only be mapped once at a time");
1207 return nullptr;
1208 }
1209
1210
1211 if (buffer.mappedData.size() != buffer.size) {
1212 buffer.mappedData.resize(buffer.size, false);
1213 }
1214
1215 if (mapMode == MapMode::Read || mapMode == MapMode::ReadWrite) {
1216
1217#ifdef EMSCRIPTEN
1218
1219 // Not available on ES3.x, only WebGL
1220
1221 GLenum glTarget = bindBuffer(OpenGLES30::BufferTarget::CopyReadBuffer, buffer.bufferId);
1222 emscripten_glGetBufferSubData(glTarget, 0, buffer.size, buffer.mappedData.data());
1223
1224#else
1225
1226 GLenum glTarget = bindBuffer(buffer.target, buffer.bufferId);
1227 const void* ptr = glMapBufferRange(glTarget, 0, GLsizei(buffer.size), GL_MAP_READ_BIT);
1228 if (ptr) {
1229 std::memcpy(buffer.mappedData.data(), ptr, buffer.size);
1230 }
1231 glUnmapBuffer(glTarget);
1232
1233#endif
1234
1235 }
1236
1237 buffer.writeBackMap = (mapMode == MapMode::Write || mapMode == MapMode::WriteDiscard || mapMode == MapMode::ReadWrite);
1238 buffer.isMapped = true;
1239 return buffer.mappedData.data();
1240}
1241
1243{
1244 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
1245
1246 if (!buffer.isMapped) {
1247 LOG_ERROR_ONCE(logger, "Unmapping buffer that is not mapped");
1248 return;
1249 }
1250
1251 if (buffer.writeBackMap) {
1252 GLenum glTarget = bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, buffer);
1253 glBufferSubData(glTarget, 0, GLsizeiptr(buffer.mappedData.size()), buffer.mappedData.data());
1254 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.mappedData.size());
1255 }
1256
1257 if (buffer.keepMapBacking == false) {
1258 buffer.mappedData.resize(0, false, true);
1259 }
1260
1261 buffer.isMapped = false;
1262}
1263
1264void Cogs::ContextGLES30::updateBuffer(BufferHandle bufferHandle, const void* data, size_t size)
1265{
1266 if (!HandleIsValid(bufferHandle)) {
1267 LOG_ERROR_ONCE(logger, "updateSubBuffer: invalid handle");
1268 return;
1269 }
1270 BufferGLES30& buffer = buffers->buffers[bufferHandle];
1271 GLenum glTarget = bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, buffer);
1272 if (size < buffer.size) {
1273 // Not enough data to fill the buffer, we invalidate the whole buffer to allow driver to rename buffer.
1274 glBufferSubData(glTarget, 0, buffer.size, nullptr);
1275 glBufferSubData(glTarget, 0, static_cast<GLsizei>(size), data);
1276 }
1277 else {
1278 glBufferSubData(glTarget, 0, buffer.size, data);
1279 }
1280 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.size);
1281
1282}
1283
1284void Cogs::ContextGLES30::updateSubTexture(TextureHandle textureHandle, const size_t level, const void * data)
1285{
1286 TextureGLES30* texture = bindTexture(textureHandle);
1287 if (texture) {
1288 const OpenGLES30::DataFormatInfo& fmt = OpenGLES30::DataFormats[size_t(texture->format)];
1289 if (fmt.isTextureFormat && fmt.isCompressed == 0) {
1290 glTexSubImage2D(texture->target, static_cast<GLint>(level), 0, 0, texture->width, texture->height, fmt.format, fmt.type, data);
1291 if(uploadStatisticsEnabled) uploadStatisticsTextureUpload(texture->estimatedByteSize); // TODO size?
1292 }
1293 }
1294}
1295
1296void Cogs::ContextGLES30::copyTexture(TextureHandle dstHandle, unsigned dstSub, unsigned dstX, unsigned dstY, unsigned dstZ, TextureHandle srcHandle, unsigned srcSub)
1297{
1298 TextureGLES30* dstTexture = bindTexture(dstHandle);
1299 if (!dstTexture) {
1300 LOG_ERROR_ONCE(logger, "copyTexture: invalid destination texture");
1301 return;
1302 }
1303
1304 if (!HandleIsValid(srcHandle)) {
1305 LOG_ERROR_ONCE(logger, "copyTexture: invalid source texture");
1306 return;
1307 }
1308
1309 bool checkCompleteness = false;
1310 GLuint srcFbo = 0; // Source FBO if needed
1311
1312 TextureGLES30& srcTexture = textures->textures[srcHandle];
1313 if (srcTexture.textureId == 0) {
1314 LOG_ERROR_ONCE(logger, "copyTexture: Cannot copy from null texture");
1315 return;
1316 }
1317
1318 if (srcTexture.target == GL_TEXTURE_2D && srcSub == 0) {
1319 if (srcTexture.fbo) {
1320 glBindFramebuffer(GL_READ_FRAMEBUFFER, srcTexture.fbo);
1321 }
1322 else {
1323 glGenFramebuffers(1, &srcTexture.fbo);
1324 glBindFramebuffer(GL_READ_FRAMEBUFFER, srcTexture.fbo);
1325 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexture.textureId, 0);
1326 checkCompleteness = true;
1327 }
1328 }
1329
1330 else if (srcTexture.target == GL_TEXTURE_2D_ARRAY || srcTexture.target == GL_TEXTURE_3D) {
1331 // For 3D/array textures the fbo is specific to subresource, so we don't bother to try
1332 // recycling it like we do for 2D textures, and just create a temporary fbo
1333 glGenFramebuffers(1, &srcFbo);
1334 glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
1335 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcTexture.textureId, 0, srcSub);
1336 checkCompleteness = true;
1337 }
1338
1339
1340 if (checkCompleteness) {
1341 GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
1342 if (status != GL_FRAMEBUFFER_COMPLETE) {
1343 LOG_ERROR_ONCE(logger, "copyTexture: Failed to create source framebuffer: %s", OpenGLES30::framebuffersStatusString(status));
1344 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1345 currentRenderTarget = RenderTargetHandle::InvalidHandle;
1346 currentDepthStencilTarget = DepthStencilHandle::InvalidHandle;
1347 return;
1348 }
1349 }
1350
1351
1352 if (dstTexture->target == GL_TEXTURE_2D) {
1353 glCopyTexSubImage2D(GL_TEXTURE_2D,
1354 dstSub,
1355 dstX, dstY,
1356 0, 0, srcTexture.width, srcTexture.height);
1357 }
1358
1359 else if (dstTexture->target == GL_TEXTURE_2D_ARRAY || dstTexture->target == GL_TEXTURE_3D) {
1360 unsigned dstLevel = 0; // TODO dstSub%LevelCount
1361 unsigned dstLayer = dstSub; // TODO dstSub/LevelCount
1362 glCopyTexSubImage3D(dstTexture->target, dstLevel,
1363 dstX, dstY, dstZ + dstLayer,
1364 0, 0, srcTexture.width, srcTexture.height);
1365
1366 }
1367
1368 else {
1369 LOG_ERROR_ONCE(logger, "copyTexture: unsupported combination of source and destination texture");
1370 }
1371
1372
1373 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1374 currentRenderTarget = RenderTargetHandle::InvalidHandle;
1375 currentDepthStencilTarget = DepthStencilHandle::InvalidHandle;
1376
1377 if (srcFbo != 0) {
1378 glDeleteFramebuffers(1, &srcFbo);
1379 }
1380
1381 return;
1382}
1383
1384
1385
1386void Cogs::ContextGLES30::updateSubBuffer(BufferHandle bufferHandle, const size_t offset, const size_t size, const void * data)
1387{
1388 if (!HandleIsValid(bufferHandle)) {
1389 LOG_ERROR_ONCE(logger, "updateSubBuffer: invalid handle");
1390 return;
1391 }
1392 BufferGLES30& buffer = buffers->buffers[bufferHandle];
1393 if (buffer.size < offset + size) {
1394 LOG_ERROR_ONCE(logger, "updateSubBuffer: updating outside of buffer bounds");
1395 return;
1396 }
1397 GLenum glTarget = bindBufferCopy(buffer.target, buffer);
1398 glBufferSubData(glTarget, static_cast<GLintptr>(offset), static_cast<GLsizei>(size), data);
1399 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1400}
1401
1402void Cogs::ContextGLES30::setBuffer(const BufferBindingHandle /*bufferBindingHandle*/, BufferHandle /*bufferHandle*/)
1403{
1404 return;
1405}
1406
1407void Cogs::ContextGLES30::setBufferCounter(BufferHandle /*bufferHandle*/, uint32_t /*value*/)
1408{
1409 return;
1410}
1411
1412void Cogs::ContextGLES30::setBufferCounter(BufferHandle /*bufferHandle*/, BufferHandle /*sourceBufferHandle*/)
1413{
1414 return;
1415}
1416
1417void Cogs::ContextGLES30::getBufferCounter(BufferHandle /*bufferHandle*/, BufferHandle /*destinationBufferHandle*/)
1418{
1419 return;
1420}
1421
1423{
1424 return 0;
1425}
1426
1427void Cogs::ContextGLES30::copyResource(BufferHandle destinationHandle, BufferHandle sourceHandle)
1428{
1429 if (!HandleIsValid(destinationHandle)) {
1430 LOG_ERROR_ONCE(logger, "copyResource: destination buffer is invalid");
1431 return;
1432 }
1433 BufferGLES30& dstBuffer = buffers->buffers[destinationHandle];
1434 GLenum dstTarget = bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, dstBuffer);
1435
1436 if (!HandleIsValid(sourceHandle)) {
1437 LOG_ERROR_ONCE(logger, "copyResource: source buffer is invalid");
1438 return;
1439 }
1440 BufferGLES30& srcBuffer = buffers->buffers[sourceHandle];
1441 GLenum srcTarget = bindBuffer(OpenGLES30::BufferTarget::CopyReadBuffer, srcBuffer.bufferId);
1442
1443 if (srcTarget == dstTarget) {
1444 LOG_ERROR_ONCE(logger, "copyResource: Ending up copying from and to the same target (0x%04x)", srcTarget);
1445 return;
1446 }
1447
1448 glCopyBufferSubData(srcTarget, dstTarget, 0, 0, srcBuffer.size);
1449}
1450
1451void Cogs::ContextGLES30::copyResource(TextureHandle targetTextureHandle, TextureHandle sourceTextureHandle)
1452{
1453 // Reuse the resolveResource() for texture copies (uses glBlitFramebuffer()...)
1454 resolveResource(sourceTextureHandle, targetTextureHandle);
1455}
1456
1458{
1459 return;
1460}
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
@ Ready
The resource has loaded successfully and is ready for use.
Framebuffer
Framebuffers to select from when doing framebuffer operations.
Definition: Common.h:147
PrimitiveType
Primitive types for interpreting vertex data sent to the graphics pipeline.
Definition: Common.h:112
@ InstanceMatrix
Instance matrix semantic.
@ 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
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 size
Buffer size..
Definition: CommonGLES30.h:68
Memory::MemoryBuffer mappedData
Memory map backing store.
Definition: CommonGLES30.h:62
unsigned short isIndexBuffer
Buffer is an index buffer.
Definition: CommonGLES30.h:76
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
void signal(FenceHandle fenceHandle) override
Insert a fence in the command stream that will signal when all commands before the fence are complete...
void setDepthStencilState(const DepthStencilStateHandle handle) override
Set the current depth stencil state.
void setViewport(const float x, const float y, const float width, const float height) override
Sets the current viewport to the given location and dimensions.
void setInputLayout(const InputLayoutHandle inputLayoutHandle) override
Sets the current input layout.
void drawInstanced(PrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes, const size_t startInstance, const size_t numInstances) override
Draws non-indexed, instanced primitives.
void beginRenderPass(const RenderPassInfo &info) override
Begin a render pass.
void setSamplerState(const SamplerStateBindingHandle samplerStateBindingHandle, const SamplerStateHandle samplerStateHandle) override
Sets the sampler state binding given to the given sampler state.
void * map(BufferHandle bufferHandle, MapMode::EMapMode mapMode, uint32_t *stride=nullptr) override
Maps the given buffer so it can be accessed.
void setBuffer(const BufferBindingHandle bufferBindingHandle, BufferHandle bufferHandle) override
Sets a buffer to bind to the given binding.
void endRenderPass() override
End a render pass.
void setVertexArrayObject(VertexArrayObjectHandle vertexArrayObject) override
void updateSubTexture(TextureHandle textureHandle, const size_t level, const void *data) override
Update the data of a level in the given texture.
void unmap(BufferHandle bufferHandle) override
Unmaps the given buffer, applying any synchronization necessary to reflect changes in the mapped memo...
void setConstantBuffer(const ConstantBufferBindingHandle bufferBindingHandle, const BufferHandle bufferHandle, const uint32_t offset, const uint32_t size) override
Sets a constant buffer to the given constant buffer binding.
void updateSubBuffer(BufferHandle bufferHandle, const size_t offset, const size_t size, const void *data) override
Update a region of data in a buffer.
void readDepthBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer framebuffer) override
Reads data from the current depth target into the given bufferHandle.
void setScissor(const int x, const int y, const int width, const int height) override
Sets the current scissor rectangle.
void setBlendState(const BlendStateHandle handle, const float *constant) override
Set the current blend state.
void setRasterizerState(const RasterizerStateHandle handle) override
Set the current rasterizer state.
void readColorBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer framebuffer) override
Reads data from the current render target into the given bufferHandle.
void resolveResource(TextureHandle source, TextureHandle destination) override
Resolves the given source resource target into the given destination texture.
void reset() override
Resets all state changes made to the GPU since the last call to beginFrame.
void clearDepth(const float depth=1.0f) override
Clear the currently set depth/stencil target to the given depth.
void getBufferCounter(BufferHandle bufferHandle, BufferHandle destinationBufferHandle) override
Get the associated counter of a buffer.
void clearRenderTarget(const float *color) override
Clear the currently set render target to the given value (4 component floating point RGBA).
void setBufferCounter(BufferHandle bufferHandle, uint32_t value) override
Set the associated counter of a buffer.
void setIndexBuffer(IndexBufferHandle indexBufferHandle, uint32_t stride, uint32_t offset) override
Sets the current index buffer.
void drawInstancedIndexed(PrimitiveType primitiveType, const size_t startInstance, const size_t numInstances, const size_t startIndex, const size_t numIndexes) override
Draws indexed, instanced primitives.
void clearCachedState() final
Prepare context for external manipulation of graphics device.
void draw(PrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes) override
Draws non-indexed, non-instanced primitives.
void drawIndexed(PrimitiveType primitiveType, const size_t startIndex, const size_t numIndexes, const size_t startVertex=0) override
Draws indexed, non-instanced primitives.
void setEffect(EffectHandle handle) override
Set the current effect.
void setVertexBuffers(const VertexBufferHandle *vertexBufferHandles, const size_t count, const uint32_t *strides, const uint32_t *offsets) override
Sets the current vertex buffers.
void setRenderTarget(const RenderTargetHandle handle, const DepthStencilHandle depthStencilHandle) override
Sets the current render target and an associated depth stencil target.
void updateBuffer(BufferHandle bufferHandle, const void *data, size_t size) override
Replace contents of buffer with new data.
Encapsulates state for depth buffer usage and stencil buffer usage in a state object.
bool depthEnabled
If depth testing is enabled/disabled. Default is true.
DepthFunction depthFunction
The depth function to use for depth testing.
static DepthStencilState DefaultState()
Constructs a depth stencil state object initialized with the default values.
bool writeEnabled
If writes to the depth buffer are enabled/disabled. Default is true.
uint8_t blockSize
Bytesize of one block of data.
Definition: DataFormat.h:261
Handle template class used to provide opaque, non-converting handles.
Definition: Common.h:23
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
handle_type handle
Internal resource handle.
Definition: Common.h:75
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:81
Provides effects and shader management functionality.
Definition: IEffects.h:158
EMapMode
Mapping mode enumeration.
Definition: Flags.h:93
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
Definition: Flags.h:103
@ ReadWrite
Read and write access.
Definition: Flags.h:101
Encapsulates state for primitive rasterization in a state object.
static RasterizerState DefaultState()
Constructs a rasterizer state initialized with the default values.
bool scissor
Enable scissor rect.
bool frontCounterClockwise
If counter clockwise polygon winding is used to specify front facing polygons. Default is false.
bool noDepthClip
Clamp depth value instead of clipping against near and depth planes.
CullMode cullMode
Which face culling mode to apply to primitives before rasterization.
float depthBias
Depth bias to apply to depth values after initial rasterization before depth values are written.
float slopeScaledDepthBias
Slope scaled depth bias value controlling the depth bias value based on the area of the polygon on sc...
@ None
Do not perform any face culling.
@ Front
Cull front facing primitives.
bool wireFrame
If only wire frames should be rasterized. Default is false.
uint16_t layerIndex
Index of the first layer (if array) to render to.
uint16_t numLayers
Number of available layers to render to.
TextureHandle texture
Texture handle.
uint8_t levelIndex
Index of the mipmap level to render to.
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.
Definition: Flags.h:122
unsigned short boundAsView
True if last use of texture was as a view.
Describes how to fetch data from a texture in shaders.
Definition: ITextures.h:13
uint32_t layerIndex
Index of the first layer (if array) to fetch from.
Definition: ITextures.h:17
uint32_t numLayers
Number of array layers available.
Definition: ITextures.h:19
uint32_t numLevels
Number of mipmap levels available.
Definition: ITextures.h:23
uint32_t levelIndex
First mipmap level to fetch data from.
Definition: ITextures.h:21
TextureHandle texture
Texture.
Definition: ITextures.h:15
@ Static
Buffer will be loaded once and used to render many subsequent frames without any updates.
Definition: Flags.h:28