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 currentEffect.handle = effectHandle;
741 if (effectHandle) {
742 currentEffect.ptr = &effects->effects[effectHandle];
743 glUseProgram(currentEffect.ptr->programId);
744 }
745 else {
746 currentEffect.ptr = nullptr;
747 glUseProgram(0);
748 }
749 needVertexAttributeSetup = true;
750}
751
752
753void Cogs::ContextGLES30::setTexture(const TextureBindingHandle textureBindingHandle, const TextureHandle textureHandle)
754{
755 if (!HandleIsValid(currentEffect.handle)) {
756 LOG_ERROR_ONCE(logger, "setTexture: Current effect handle is invalid");
757 return;
758 }
759 if (textureBindingHandle == TextureBindingHandle::NoHandle) {
760 return;
761 }
762 else if (textureBindingHandle == TextureBindingHandle::InvalidHandle) {
763 LOG_ERROR_ONCE(logger, "setTexture: Texture binding handle is invalid");
764 return;
765 }
766
767 GLint unit = GLint(textureBindingHandle.handle - 1);
768 assert(0 <= unit && unit < GLint(OpenGLES30::maxTexUnits));
769 bindTexture(textureHandle, unit);
770}
771
772void Cogs::ContextGLES30::setTexture(const TextureBindingHandle textureBindingHandle, TextureViewHandle textureViewHandle)
773{
774 if (!HandleIsValid(currentEffect.handle) || !HandleIsValid(textureBindingHandle) || !HandleIsValid(textureViewHandle)) return;
775
776 TextureViewDescription& view = textures->views[textureViewHandle];
777
778 GLint unit = GLint(textureBindingHandle.handle - 1);
779 assert(0 <= unit && unit < GLint(OpenGLES30::maxTexUnits));
780
781 TextureGLES30* texture = bindTexture(view.texture, unit);
782 if (texture) {
783 glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, view.levelIndex);
784 glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, view.levelIndex + view.numLevels - 1);
785 texture->boundAsView = 1;
786 }
787}
788
789Cogs::TextureGLES30* Cogs::ContextGLES30::bindTexture(TextureHandle textureHandle, GLuint unit)
790{
791 if (unit == GLuint(~0u)) {
792 unit = activeTexUnit;
793 }
794 assert(unit < OpenGLES30::maxTexUnits);
795
796 TextureGLES30* texture = nullptr;
797 if (HandleIsValid(textureHandle)) {
798 texture = &textures->textures[textureHandle];
799 }
800 if (texture && texture->target == GL_RENDERBUFFER) {
801 LOG_ERROR_ONCE(logger, "Cannot bind a renderBuffer as a texture sampler");
802 return nullptr;
803 }
804
805 // Early out if we do not change any state
806 if (texUnits[unit].texture == textureHandle && (texture == nullptr || texture->boundAsView == 0)) {
807 return texture;
808 }
809
810 // Switch texture unit if needed
811 if (activeTexUnit != unit) {
812 glActiveTexture(GL_TEXTURE0 + unit);
813 activeTexUnit = unit;
814 }
815
816 // We are binding to a texture
817 if (texture) {
818
819 // If a texture was bound to the unit but to a different target, set the old target to null
820 if (HandleIsValid(texUnits[unit].texture) && texUnits[unit].target != texture->target) {
821 glBindTexture(texUnits[unit].target, 0);
822 }
823
824 glBindTexture(texture->target, texture->textureId);
825 texUnits[unit].target = texture->target;
826 texUnits[unit].texture = textureHandle;
827
828 // If the texture was bound as a view, we remove the view
829 if (texture->boundAsView) {
830 glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0);
831 glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, 1000);
832 texture->boundAsView = 0;
833 }
834
835 return texture;
836 }
837
838 // Unbind a unit
839 else if (textureHandle == TextureHandle::InvalidHandle) {
840 LOG_WARNING_ONCE(logger, "setTexture: Invalid texture handle");
841 }
842
843 if (HandleIsValid(texUnits[unit].texture)) {
844 glBindTexture(texUnits[unit].target, 0);
845 }
846 texUnits[unit].target = GL_TEXTURE_2D;
847 texUnits[unit].texture = TextureHandle::NoHandle;
848
849 return nullptr;
850}
851
852void Cogs::ContextGLES30::setSamplerState(const SamplerStateBindingHandle samplerStateBindingHandle, const SamplerStateHandle samplerStateHandle)
853{
854 if (!samplerStateBindingHandle) return;
855
856 const GLint unit = static_cast<GLint>(samplerStateBindingHandle.handle - 1);
857 assert(0 <= unit && unit < GLint(OpenGLES30::maxTexUnits));
858
859 if (texUnits[unit].sampler != samplerStateHandle) {
860 texUnits[unit].sampler = samplerStateHandle;
861 if (HandleIsValid(samplerStateHandle)) {
862 const SamplerGLES30& sampler = textures->samplers[samplerStateHandle];
863 glBindSampler(unit, sampler.glName);
864 }
865 else {
866 glBindSampler(unit, 0);
867 }
868 }
869}
870
872{
873 const RasterizerState & rasterizerState = (handle == RasterizerStateHandle::NoHandle) ? RasterizerState::DefaultState() : this->renderTargets->rasterizerStates[handle];
874
875 currentRasterizerState.wireFrame = rasterizerState.wireFrame;
876
877 if (currentRasterizerState.frontCounterClockwise != rasterizerState.frontCounterClockwise) {
878 currentRasterizerState.frontCounterClockwise = rasterizerState.frontCounterClockwise;
879 glFrontFace(currentRasterizerState.frontCounterClockwise ? GL_CCW : GL_CW);
880 }
881
882 if (currentRasterizerState.cullMode != rasterizerState.cullMode) {
883 currentRasterizerState.cullMode = rasterizerState.cullMode;
884 switch (rasterizerState.cullMode)
885 {
887 glDisable(GL_CULL_FACE);
888 break;
889
891 glEnable(GL_CULL_FACE);
892 glCullFace(GL_FRONT);
893 break;
894
895 default:
896 glEnable(GL_CULL_FACE);
897 glCullFace(GL_BACK);
898 break;
899 }
900 }
901
902 if (currentRasterizerState.noDepthClip != rasterizerState.noDepthClip) {
903 currentRasterizerState.noDepthClip = rasterizerState.noDepthClip;
904 if (capabilities->getDeviceCapabilities().NoDepthClip) {
905 if (currentRasterizerState.noDepthClip) {
906 glEnable(GL_DEPTH_CLAMP_EXT);
907 }
908 else {
909 glDisable(GL_DEPTH_CLAMP_EXT);
910 }
911 }
912 }
913
914 if ((currentRasterizerState.depthBias != rasterizerState.depthBias) ||
915 (currentRasterizerState.slopeScaledDepthBias != rasterizerState.slopeScaledDepthBias))
916 {
917 currentRasterizerState.depthBias = rasterizerState.depthBias;
918 currentRasterizerState.slopeScaledDepthBias = rasterizerState.slopeScaledDepthBias;
919 if ((currentRasterizerState.depthBias != 0.f) || (currentRasterizerState.slopeScaledDepthBias != 0.f))
920 {
921 glEnable(GL_POLYGON_OFFSET_FILL);
922 glPolygonOffset(currentRasterizerState.slopeScaledDepthBias, currentRasterizerState.depthBias);
923 }
924 else {
925 glPolygonOffset(0, 0);
926 glDisable(GL_POLYGON_OFFSET_FILL);
927 }
928 }
929
930 if (currentRasterizerState.scissor != rasterizerState.scissor) {
931 currentRasterizerState.scissor = rasterizerState.scissor;
932 if (currentRasterizerState.scissor) {
933 glEnable(GL_SCISSOR_TEST);
934 }
935 else {
936 glDisable(GL_SCISSOR_TEST);
937 }
938 }
939}
940
942{
943 inputLayout.currHandle = handle;
944}
945
946void Cogs::ContextGLES30::resolveResource(TextureHandle sourceTextureHandle, TextureHandle targetTextureHandle)
947{
948 TextureGLES30 & sourceTexture = this->textures->textures[sourceTextureHandle];
949 TextureGLES30 & targetTexture = this->textures->textures[targetTextureHandle];
950
951 if (1 < targetTexture.numSamples) {
952 LOG_ERROR_ONCE(logger, "Cannot resolve to multisample target");
953 return;
954 }
955 if (sourceTexture.width != targetTexture.width || sourceTexture.height != targetTexture.height) {
956 LOG_ERROR_ONCE(logger, "Cannot resolve to texture of different size");
957 return;
958 }
959 if (targetTexture.textureId == 0) {
960 LOG_ERROR_ONCE(logger, "Cannot resolve to null texture");
961 return;
962 }
963
964 // Set up source for resolve blit
965 if (sourceTexture.fbo) {
966 glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceTexture.fbo);
967 }
968 else if (!setupFramebuffer(sourceTexture, GL_READ_FRAMEBUFFER)) {
969 return; // Failed
970 }
971
972 // Set up target for resolve blit
973 if (targetTexture.fbo) {
974 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetTexture.fbo);
975 }
976 else if (!setupFramebuffer(targetTexture, GL_DRAW_FRAMEBUFFER)) {
977 return; // Failed
978 }
979
980 // Do resolve
981 if (targetTexture.flags & TextureFlags::DepthBuffer) {
982
983 glClear(GL_DEPTH_BUFFER_BIT); // Break dependency chain
984 glBlitFramebuffer(0, 0, sourceTexture.width, sourceTexture.height,
985 0, 0, targetTexture.width, targetTexture.height,
986 GL_DEPTH_BUFFER_BIT, GL_NEAREST);
987 }
988 else {
989 glClear(GL_COLOR_BUFFER_BIT); // Break dependency chain
990 glBlitFramebuffer(0, 0, sourceTexture.width, sourceTexture.height,
991 0, 0, targetTexture.width, targetTexture.height,
992 GL_COLOR_BUFFER_BIT, GL_NEAREST);
993 }
994 glBindFramebuffer(GL_FRAMEBUFFER, 0);
995}
996
997void Cogs::ContextGLES30::setDefaults()
998{
999 if (emptyUniformBuffer == BufferHandle::NoHandle) {
1000 emptyUniformBuffer = buffers->loadBuffer(nullptr,
1001 0x4000, // GL minimum size
1005 }
1007
1008 setRasterizerState(RasterizerStateHandle::NoHandle);
1009 currentRasterizerState.frontCounterClockwise = false;
1010 currentRasterizerState.cullMode = RasterizerState::CullMode::None;
1011 currentRasterizerState.depthBias = 0.0;
1012 currentRasterizerState.slopeScaledDepthBias = 0.0;
1013 currentRasterizerState.scissor = false;
1014 currentRasterizerState.wireFrame = false;
1015 currentRasterizerState.noDepthClip = false;
1016 glFrontFace(GL_CW);
1017 glDisable(GL_CULL_FACE);
1018 glDisable(GL_POLYGON_OFFSET_FILL);
1019 glDisable(GL_SCISSOR_TEST);
1020 if (capabilities->getDeviceCapabilities().NoDepthClip) {
1021 glDisable(GL_DEPTH_CLAMP_EXT);
1022 }
1023
1024 { // Blend state
1025 currBlendState.handle = BlendStateHandle::NoHandle;
1026 currBlendState.state.blend = { BlendState::Blend::One, BlendState::Blend::Zero, BlendState::Blend::One, BlendState::Blend::Zero };
1027 currBlendState.state.operation = { BlendState::BlendOperation::Add, BlendState::BlendOperation::Add };
1028 currBlendState.state.enabled = false;
1029 nextBlendState.handle = BlendStateHandle::NoHandle;
1030 glDisable(GL_BLEND);
1031 glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
1032 glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
1033 glBlendColor(0.f, 0.f, 0.f, 0.f);
1034 }
1035
1036 setDepthStencilState(DepthStencilStateHandle::NoHandle);
1037 currentDepthStencilState.depthEnabled = true;
1038 currentDepthStencilState.writeEnabled = true;
1039 currentDepthStencilState.depthFunction = DepthStencilState::DepthFunction::Less;
1040 glEnable(GL_DEPTH_TEST);
1041 glDepthMask(GL_TRUE);
1042 glDepthFunc(GL_LESS);
1043
1044 activeTexUnit = 0;
1045 glActiveTexture(GL_TEXTURE0);
1046
1047 vertexArrayObject.prevHandle = VertexArrayObjectHandle::NoHandle;
1048 vertexArrayObject.currHandle = VertexArrayObjectHandle::NoHandle;
1049 glBindVertexArray(0);
1050
1051 inputLayout.prevHandle = InputLayoutHandle::NoHandle;
1052 inputLayout.currHandle = InputLayoutHandle::NoHandle;
1053
1054 indexBuffer.handle = IndexBufferHandle::NoHandle;
1055
1056 currentEffect.handle = EffectHandle::NoHandle;
1057 currentEffect.ptr = nullptr;
1058 glUseProgram(0);
1059
1060 for (size_t i = 0; i < size_t(OpenGLES30::BufferTarget::Count); i++) {
1061 glBindBuffer(glBufferTargets[i], 0);
1062 bufferTargets[i].buffer = 0;
1063 }
1064
1065 for (GLuint i = 0; i < OpenGLES30::maxUniformBuffers; i++) {
1066 if (uniformBufferTargets[i].buffer) {
1067 glBindBufferBase(GL_UNIFORM_BUFFER, i, 0);
1068 }
1069 uniformBufferTargets[i].buffer = 0;
1070 uniformBufferTargets[i].offset = 0;
1071 uniformBufferTargets[i].size = ~0u;
1072 }
1073
1074 // Bind empty uniform buffer to slot index 0, which is the slot-index
1075 // which we use for unused buffers.
1076 if (HandleIsValid(emptyUniformBuffer)) {
1077 const BufferGLES30& buffer = buffers->buffers[emptyUniformBuffer];
1078 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer.bufferId);
1079 }
1080
1081}
1082
1084{
1085 for (GLuint i = 0; i < OpenGLES30::maxTexUnits; i++) {
1086 if (texUnits[i].texture != TextureHandle::NoHandle || texUnits[i].sampler != SamplerStateHandle::NoHandle) {
1087 glActiveTexture(GL_TEXTURE0 + i);
1088 glBindTexture(texUnits[i].target, 0);
1089 texUnits[i].target = GL_TEXTURE_2D;
1090 texUnits[i].texture = TextureHandle::NoHandle;
1091
1092 glBindSampler(i, 0);
1093 texUnits[i].sampler = SamplerStateHandle::NoHandle;
1094 }
1095 }
1096 activeTexUnit = 0;
1097 glActiveTexture(GL_TEXTURE0);
1098
1099 vertexArrayObject.prevHandle = VertexArrayObjectHandle::NoHandle;
1100 vertexArrayObject.currHandle = VertexArrayObjectHandle::NoHandle;
1101 glBindVertexArray(0);
1102
1103 for (GLenum i = 0; i < OpenGLES30::maxVertexAttributes; i++) {
1104 vertexBuffers.currItems[i].handle = VertexBufferHandle::NoHandle;
1105 if (currentAttributeMask & (1 << i)) {
1106 glDisableVertexAttribArray(i);
1107 }
1108 }
1109 vertexBuffers.count = 0;
1110 currentAttributeMask = 0;
1111
1112 currentEffect.handle = EffectHandle::NoHandle;
1113 currentEffect.ptr = nullptr;
1114 glUseProgram(0);
1115}
1116
1118{
1119 DepthStencilState depthStencilState = (handle == DepthStencilStateHandle::NoHandle) ? DepthStencilState::DefaultState() : this->renderTargets->depthStencilStates[handle];
1120
1121 if (currentDepthStencilState.depthEnabled != depthStencilState.depthEnabled) {
1122 currentDepthStencilState.depthEnabled = depthStencilState.depthEnabled;
1123 if (currentDepthStencilState.depthEnabled) {
1124 glEnable(GL_DEPTH_TEST);
1125 }
1126 else {
1127 glDisable(GL_DEPTH_TEST);
1128 }
1129 }
1130
1131 if (currentDepthStencilState.depthEnabled) {
1132
1133 // Depth is never written with depth test enabled, use ALWAYS test to write unconditionally.
1134 if (currentDepthStencilState.writeEnabled != depthStencilState.writeEnabled) {
1135 currentDepthStencilState.writeEnabled = depthStencilState.writeEnabled;
1136 if (currentDepthStencilState.writeEnabled) {
1137 glDepthMask(GL_TRUE);
1138 }
1139 else {
1140 glDepthMask(GL_FALSE);
1141 }
1142 }
1143
1144 // Depth test function only necessary to set when depth test is enabled
1145 if (currentDepthStencilState.depthFunction != depthStencilState.depthFunction) {
1146 currentDepthStencilState.depthFunction = depthStencilState.depthFunction;
1147 glDepthFunc(DepthFunctions[currentDepthStencilState.depthFunction]);
1148 }
1149 }
1150}
1151
1152void Cogs::ContextGLES30::readDepthBuffer(BufferHandle /*bufferHandle*/, int /*x*/, int /*y*/, int /*width*/, int /*height*/, Framebuffer /*framebuffer*/)
1153{
1154 LOG_ERROR_ONCE(logger, "Reading of depth buffer is not supported");
1155}
1156
1157void Cogs::ContextGLES30::readColorBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer /*framebuffer*/)
1158{
1159
1160 if (!HandleIsValid(bufferHandle)) return;
1161 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
1162
1163 size_t elementSize = 4;
1164 GLenum source = GL_BACK;
1165 GLenum format = GL_RGBA;
1166 GLenum type = GL_UNSIGNED_BYTE;
1167
1168 if (currentRenderTarget == RenderTargetHandle::InvalidHandle) {
1169 LOG_ERROR_ONCE(logger, "Reading color buffer of invalid render target");
1170 return;
1171 }
1172
1173 if (HandleIsValid(currentRenderTarget)) {
1174 const RenderTargetGLES30& renderTarget = this->renderTargets->renderTargets[this->currentRenderTarget];
1175
1176 source = GL_COLOR_ATTACHMENT0;
1177
1178 if (renderTarget.numViews && HandleIsValid(renderTarget.views[0].texture)) {
1179 const TextureGLES30& texture = textures->textures[renderTarget.views[0].texture];
1180 elementSize = getFormatInfo(texture.format)->blockSize;
1181 format = OpenGLES30::DataFormats[size_t(texture.format)].format;
1182 type = OpenGLES30::DataFormats[size_t(texture.format)].type;
1183 }
1184 }
1185
1186 if (buffer.size < elementSize * width * height) {
1187 LOG_ERROR_ONCE(logger, "Color buffer read is larger than buffer size.");
1188 return;
1189 }
1190
1191 glReadBuffer(source);
1192 bindBuffer(OpenGLES30::BufferTarget::PixelPackBuffer, buffer.bufferId);
1193 glReadPixels(x, y, width, height, format, type, nullptr);
1194}
1195
1196void* Cogs::ContextGLES30::map(BufferHandle bufferHandle, MapMode::EMapMode mapMode, uint32_t* /*stride*/)
1197{
1198 if (!HandleIsValid(bufferHandle)) return nullptr;
1199
1200
1201 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
1202 if (buffer.isMapped) {
1203 LOG_ERROR_ONCE(logger, "Buffers can only be mapped once at a time");
1204 return nullptr;
1205 }
1206
1207
1208 if (buffer.mappedData.size() != buffer.size) {
1209 buffer.mappedData.resize(buffer.size, false);
1210 }
1211
1212 if (mapMode == MapMode::Read || mapMode == MapMode::ReadWrite) {
1213
1214#ifdef EMSCRIPTEN
1215
1216 // Not available on ES3.x, only WebGL
1217
1218 GLenum glTarget = bindBuffer(OpenGLES30::BufferTarget::CopyReadBuffer, buffer.bufferId);
1219 emscripten_glGetBufferSubData(glTarget, 0, buffer.size, buffer.mappedData.data());
1220
1221#else
1222
1223 GLenum glTarget = bindBuffer(buffer.target, buffer.bufferId);
1224 const void* ptr = glMapBufferRange(glTarget, 0, GLsizei(buffer.size), GL_MAP_READ_BIT);
1225 if (ptr) {
1226 std::memcpy(buffer.mappedData.data(), ptr, buffer.size);
1227 }
1228 glUnmapBuffer(glTarget);
1229
1230#endif
1231
1232 }
1233
1234 buffer.writeBackMap = (mapMode == MapMode::Write || mapMode == MapMode::WriteDiscard || mapMode == MapMode::ReadWrite);
1235 buffer.isMapped = true;
1236 return buffer.mappedData.data();
1237}
1238
1240{
1241 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
1242
1243 if (!buffer.isMapped) {
1244 LOG_ERROR_ONCE(logger, "Unmapping buffer that is not mapped");
1245 return;
1246 }
1247
1248 if (buffer.writeBackMap) {
1249 GLenum glTarget = bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, buffer);
1250 glBufferSubData(glTarget, 0, GLsizeiptr(buffer.mappedData.size()), buffer.mappedData.data());
1251 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.mappedData.size());
1252 }
1253
1254 if (buffer.keepMapBacking == false) {
1255 buffer.mappedData.resize(0, false, true);
1256 }
1257
1258 buffer.isMapped = false;
1259}
1260
1261void Cogs::ContextGLES30::updateBuffer(BufferHandle bufferHandle, const void* data, size_t size)
1262{
1263 if (!HandleIsValid(bufferHandle)) {
1264 LOG_ERROR_ONCE(logger, "updateSubBuffer: invalid handle");
1265 return;
1266 }
1267 BufferGLES30& buffer = buffers->buffers[bufferHandle];
1268 GLenum glTarget = bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, buffer);
1269 if (size < buffer.size) {
1270 // Not enough data to fill the buffer, we invalidate the whole buffer to allow driver to rename buffer.
1271 glBufferSubData(glTarget, 0, buffer.size, nullptr);
1272 glBufferSubData(glTarget, 0, static_cast<GLsizei>(size), data);
1273 }
1274 else {
1275 glBufferSubData(glTarget, 0, buffer.size, data);
1276 }
1277 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.size);
1278
1279}
1280
1281void Cogs::ContextGLES30::updateSubTexture(TextureHandle textureHandle, const size_t level, const void * data)
1282{
1283 TextureGLES30* texture = bindTexture(textureHandle);
1284 if (texture) {
1285 const OpenGLES30::DataFormatInfo& fmt = OpenGLES30::DataFormats[size_t(texture->format)];
1286 if (fmt.isTextureFormat && fmt.isCompressed == 0) {
1287 glTexSubImage2D(texture->target, static_cast<GLint>(level), 0, 0, texture->width, texture->height, fmt.format, fmt.type, data);
1288 if(uploadStatisticsEnabled) uploadStatisticsTextureUpload(texture->estimatedByteSize); // TODO size?
1289 }
1290 }
1291}
1292
1293void Cogs::ContextGLES30::copyTexture(TextureHandle dstHandle, unsigned dstSub, unsigned dstX, unsigned dstY, unsigned dstZ, TextureHandle srcHandle, unsigned srcSub)
1294{
1295 TextureGLES30* dstTexture = bindTexture(dstHandle);
1296 if (!dstTexture) {
1297 LOG_ERROR_ONCE(logger, "copyTexture: invalid destination texture");
1298 return;
1299 }
1300
1301 if (!HandleIsValid(srcHandle)) {
1302 LOG_ERROR_ONCE(logger, "copyTexture: invalid source texture");
1303 return;
1304 }
1305
1306 bool checkCompleteness = false;
1307 GLuint srcFbo = 0; // Source FBO if needed
1308
1309 TextureGLES30& srcTexture = textures->textures[srcHandle];
1310 if (srcTexture.textureId == 0) {
1311 LOG_ERROR_ONCE(logger, "copyTexture: Cannot copy from null texture");
1312 return;
1313 }
1314
1315 if (srcTexture.target == GL_TEXTURE_2D && srcSub == 0) {
1316 if (srcTexture.fbo) {
1317 glBindFramebuffer(GL_READ_FRAMEBUFFER, srcTexture.fbo);
1318 }
1319 else {
1320 glGenFramebuffers(1, &srcTexture.fbo);
1321 glBindFramebuffer(GL_READ_FRAMEBUFFER, srcTexture.fbo);
1322 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexture.textureId, 0);
1323 checkCompleteness = true;
1324 }
1325 }
1326
1327 else if (srcTexture.target == GL_TEXTURE_2D_ARRAY || srcTexture.target == GL_TEXTURE_3D) {
1328 // For 3D/array textures the fbo is specific to subresource, so we don't bother to try
1329 // recycling it like we do for 2D textures, and just create a temporary fbo
1330 glGenFramebuffers(1, &srcFbo);
1331 glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
1332 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcTexture.textureId, 0, srcSub);
1333 checkCompleteness = true;
1334 }
1335
1336
1337 if (checkCompleteness) {
1338 GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
1339 if (status != GL_FRAMEBUFFER_COMPLETE) {
1340 LOG_ERROR_ONCE(logger, "copyTexture: Failed to create source framebuffer: %s", OpenGLES30::framebuffersStatusString(status));
1341 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1342 currentRenderTarget = RenderTargetHandle::InvalidHandle;
1343 currentDepthStencilTarget = DepthStencilHandle::InvalidHandle;
1344 return;
1345 }
1346 }
1347
1348
1349 if (dstTexture->target == GL_TEXTURE_2D) {
1350 glCopyTexSubImage2D(GL_TEXTURE_2D,
1351 dstSub,
1352 dstX, dstY,
1353 0, 0, srcTexture.width, srcTexture.height);
1354 }
1355
1356 else if (dstTexture->target == GL_TEXTURE_2D_ARRAY || dstTexture->target == GL_TEXTURE_3D) {
1357 unsigned dstLevel = 0; // TODO dstSub%LevelCount
1358 unsigned dstLayer = dstSub; // TODO dstSub/LevelCount
1359 glCopyTexSubImage3D(dstTexture->target, dstLevel,
1360 dstX, dstY, dstZ + dstLayer,
1361 0, 0, srcTexture.width, srcTexture.height);
1362
1363 }
1364
1365 else {
1366 LOG_ERROR_ONCE(logger, "copyTexture: unsupported combination of source and destination texture");
1367 }
1368
1369
1370 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1371 currentRenderTarget = RenderTargetHandle::InvalidHandle;
1372 currentDepthStencilTarget = DepthStencilHandle::InvalidHandle;
1373
1374 if (srcFbo != 0) {
1375 glDeleteFramebuffers(1, &srcFbo);
1376 }
1377
1378 return;
1379}
1380
1381
1382
1383void Cogs::ContextGLES30::updateSubBuffer(BufferHandle bufferHandle, const size_t offset, const size_t size, const void * data)
1384{
1385 if (!HandleIsValid(bufferHandle)) {
1386 LOG_ERROR_ONCE(logger, "updateSubBuffer: invalid handle");
1387 return;
1388 }
1389 BufferGLES30& buffer = buffers->buffers[bufferHandle];
1390 if (buffer.size < offset + size) {
1391 LOG_ERROR_ONCE(logger, "updateSubBuffer: updating outside of buffer bounds");
1392 return;
1393 }
1394 GLenum glTarget = bindBufferCopy(buffer.target, buffer);
1395 glBufferSubData(glTarget, static_cast<GLintptr>(offset), static_cast<GLsizei>(size), data);
1396 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1397}
1398
1399void Cogs::ContextGLES30::setBuffer(const BufferBindingHandle /*bufferBindingHandle*/, BufferHandle /*bufferHandle*/)
1400{
1401 return;
1402}
1403
1404void Cogs::ContextGLES30::setBufferCounter(BufferHandle /*bufferHandle*/, uint32_t /*value*/)
1405{
1406 return;
1407}
1408
1409void Cogs::ContextGLES30::setBufferCounter(BufferHandle /*bufferHandle*/, BufferHandle /*sourceBufferHandle*/)
1410{
1411 return;
1412}
1413
1414void Cogs::ContextGLES30::getBufferCounter(BufferHandle /*bufferHandle*/, BufferHandle /*destinationBufferHandle*/)
1415{
1416 return;
1417}
1418
1420{
1421 return 0;
1422}
1423
1424void Cogs::ContextGLES30::copyResource(BufferHandle destinationHandle, BufferHandle sourceHandle)
1425{
1426 if (!HandleIsValid(destinationHandle)) {
1427 LOG_ERROR_ONCE(logger, "copyResource: destination buffer is invalid");
1428 return;
1429 }
1430 BufferGLES30& dstBuffer = buffers->buffers[destinationHandle];
1431 GLenum dstTarget = bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, dstBuffer);
1432
1433 if (!HandleIsValid(sourceHandle)) {
1434 LOG_ERROR_ONCE(logger, "copyResource: source buffer is invalid");
1435 return;
1436 }
1437 BufferGLES30& srcBuffer = buffers->buffers[sourceHandle];
1438 GLenum srcTarget = bindBuffer(OpenGLES30::BufferTarget::CopyReadBuffer, srcBuffer.bufferId);
1439
1440 if (srcTarget == dstTarget) {
1441 LOG_ERROR_ONCE(logger, "copyResource: Ending up copying from and to the same target (0x%04x)", srcTarget);
1442 return;
1443 }
1444
1445 glCopyBufferSubData(srcTarget, dstTarget, 0, 0, srcBuffer.size);
1446}
1447
1448void Cogs::ContextGLES30::copyResource(TextureHandle targetTextureHandle, TextureHandle sourceTextureHandle)
1449{
1450 // Reuse the resolveResource() for texture copies (uses glBlitFramebuffer()...)
1451 resolveResource(sourceTextureHandle, targetTextureHandle);
1452}
1453
1455{
1456 return;
1457}
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
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:74
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:75
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
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:257
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:148
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