1#include "ContextGLES30.h"
3#include "BuffersGLES30.h"
4#include "TexturesGLES30.h"
5#include "EffectsGLES30.h"
6#include "RenderTargetsGLES30.h"
7#include "FormatsGLES30.h"
8#include "CapabilitiesGLES30.h"
11#include <webgl/webgl2.h>
22 GL_ONE_MINUS_SRC_COLOR,
24 GL_ONE_MINUS_SRC_ALPHA,
26 GL_ONE_MINUS_DST_ALPHA,
28 GL_ONE_MINUS_DST_COLOR,
29 GL_SRC_ALPHA_SATURATE,
31 GL_ONE_MINUS_CONSTANT_COLOR
33 static_assert(
sizeof(Blends) ==
sizeof(Blends[0]) * size_t(Cogs::BlendState::Blend::Count));
35 GLenum BlendOperations[] = {
38 GL_FUNC_REVERSE_SUBTRACT,
42 static_assert(
sizeof(BlendOperations) ==
sizeof(BlendOperations[0]) * size_t(Cogs::BlendState::BlendOperation::Count));
44 GLenum DepthFunctions[] = {
55 GLenum glBufferTargets[] = {
57 GL_ELEMENT_ARRAY_BUFFER,
62 GL_TRANSFORM_FEEDBACK_BUFFER
64 static_assert(
sizeof(glBufferTargets) ==
sizeof(glBufferTargets[0]) * size_t(Cogs::OpenGLES30::BufferTarget::Count));
68 switch (texture.target) {
70 if (texture.textureId == 0) {
71 LOG_ERROR_ONCE(logger,
"Cannot resolve to/from null texture");
76 if (texture.renderBuffer == 0) {
77 LOG_ERROR_ONCE(logger,
"Cannot resolve to/from null renderbuffer");
82 LOG_ERROR_ONCE(logger,
"Cannot resolve to/from this kind of texture target");
86 glGenFramebuffers(1, &texture.fbo);
87 glBindFramebuffer(framebufferTarget, texture.fbo);
91 switch (texture.target) {
93 glFramebufferTexture2D(framebufferTarget, framebufferAttachment, GL_TEXTURE_2D, texture.textureId, 0);
96 glFramebufferRenderbuffer(framebufferTarget, framebufferAttachment, GL_RENDERBUFFER, texture.renderBuffer);
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);
116Cogs::IEffects* Cogs::ContextGLES30::getEffects() {
return effects; }
120 syncObjects->signal(fenceHandle);
123void Cogs::ContextGLES30::setupVertexAttributes(
size_t baseVertex)
125 if (inputLayout.currHandle && currentEffect.ptr) {
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);
136 for (
size_t b = 0; b < layout.numFormats; ++b) {
137 auto& vertexBuffer = vertexBuffers.currItems[b];
139 BufferGLES30& buffer = buffers->buffers[vertexBuffer.handle];
140 const VertexFormat* vertexFormat = layout.formats[b];
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) {
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)
151 attributeLocation = effect->attributeLocation[i];
155 if (attributeLocation == -1) {
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");
166 const GLvoid* attribOffset =
reinterpret_cast<const GLvoid*
>((size_t)element.offset + bufferOffset);
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;
181 if (format.columns == 1) {
182 if (format.isInteger) {
183 glVertexAttribIPointer(attributeLocation, format.components, format.type, stride, attribOffset);
186 glVertexAttribPointer(attributeLocation, format.components, format.type, format.isNormalized ? GL_TRUE : GL_FALSE, stride, attribOffset);
188 glEnableVertexAttribArray(attributeLocation);
189 glVertexAttribDivisor(attributeLocation, element.instanceStep);
190 attributeMask |= 1 << attributeLocation;
196 vertexBuffers.baseVertex =
static_cast<uint32_t
>(baseVertex);
199 uint32_t disable = currentAttributeMask & (~attributeMask);
202 DWORD attributeIndex = 0;
203 _BitScanForward(&attributeIndex, disable);
205 uint32_t attributeIndex = __builtin_ctz(disable);
207 assert((1 << attributeIndex) & disable);
208 disable &= ~(1 << attributeIndex);
209 glDisableVertexAttribArray(attributeIndex);
211 currentAttributeMask = attributeMask;
214 inputLayout.prevHandle = inputLayout.currHandle;
216 needVertexAttributeSetup =
false;
219GLenum Cogs::ContextGLES30::bindBuffer(OpenGLES30::BufferTarget target, GLuint buffer)
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);
229void Cogs::ContextGLES30::unbindBuffer(GLuint buffer)
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;
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;
245void Cogs::ContextGLES30::unbindVAO()
249 glBindVertexArray(0);
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;
263 LOG_ERROR_ONCE(logger,
"setIndexBuffer: Cannot bind index buffer with non-zero offset");
267 if (HandleIsValid(indexBufferHandle)) {
268 BufferGLES30& ixbuf = buffers->buffers[indexBufferHandle];
270 LOG_ERROR_ONCE(logger,
"setIndexBuffer: Cannot bind non-index buffer as index buffer.");
276 indexBuffer.
handle = indexBufferHandle;
277 indexBuffer.stride = stride;
278 indexBuffer.offset = offset;
279 needVertexAttributeSetup =
true;
284 if (!HandleIsValid(bufferBindingHandle))
return;
285 if (!HandleIsValid(currentEffect.handle)) {
286 LOG_ERROR_ONCE(logger,
"setConstantBuffer: Invalid effect handle");
289 assert(currentEffect.ptr);
291 if (!HandleIsValid(bufferHandle)) {
292 LOG_ERROR_ONCE(logger,
"setConstantBuffer: Invalid buffer handle");
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))
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);
309 GLsizeiptr _size = GLsizeiptr(size);
310 if (_size == (GLsizeiptr)0xffffffff) {
311 _size = GLsizeiptr(buffer.
size - std::min(buffer.
size, offset));
313 glBindBufferRange(GL_UNIFORM_BUFFER, index, buffer.
bufferId, offset, _size);
318bool Cogs::ContextGLES30::setupState()
320 if (currBlendState.handle != nextBlendState.handle) {
323 if (HandleIsValid(nextBlendState.handle)) {
324 const BlendStateGLES30& blendState = renderTargets->blendStates[nextBlendState.handle];
326 if (currBlendState.state.enabled != blendState.enabled) {
327 currBlendState.state.enabled = blendState.enabled;
328 if (currBlendState.state.enabled) {
336 if (currBlendState.state.enabled) {
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))
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)]);
350 if ((currBlendState.state.operation.color != blendState.operation.color) ||
351 (currBlendState.state.operation.alpha != blendState.operation.alpha))
353 currBlendState.state.operation = blendState.operation;
354 glBlendEquationSeparate(BlendOperations[
size_t(currBlendState.state.operation.color)],
355 BlendOperations[
size_t(currBlendState.state.operation.alpha)]);
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]))
363 for (
size_t i = 0; i < 4; i++) {
364 currBlendState.constant[i] = nextBlendState.constant[i];
366 glBlendColor(currBlendState.constant[0],
367 currBlendState.constant[1],
368 currBlendState.constant[2],
369 currBlendState.constant[3]);
373 else if (currBlendState.state.enabled) {
374 currBlendState.state.enabled =
false;
378 currBlendState.handle = nextBlendState.handle;
384bool Cogs::ContextGLES30::setupDraw(
size_t baseVertex)
392 LOG_ERROR_ONCE(logger,
"setupIndexedDraw: No valid effect.");
398 LOG_ERROR_ONCE(logger,
"setupIndexedDraw: Invalid vertex array object");
405 if (baseVertex != 0) {
406 LOG_ERROR_ONCE(logger,
"Unhandled VAO rendering with base vertex %zu != 0", baseVertex);
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;
423 needVertexAttributeSetup = needVertexAttributeSetup || (vertexBuffers.baseVertex != baseVertex);
424 if (needVertexAttributeSetup) { setupVertexAttributes(baseVertex); }
430bool Cogs::ContextGLES30::setupIndexedDraw(GLenum& indexType, GLsizei& indexCount,
const GLvoid*& indexOffset,
const size_t startIndex,
const size_t numIndices,
const size_t baseVertex)
436 indexType = GL_INVALID_ENUM;
438 indexOffset =
nullptr;
442 LOG_ERROR_ONCE(logger,
"setupIndexedDraw: No valid effect.");
448 LOG_ERROR_ONCE(logger,
"setupIndexedDraw: Invalid vertex array object");
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");
461 vertexArrayObject.prevHandle = vertexArrayObject.currHandle;
462 glBindVertexArray(vao.glName);
463 vertexArrayObject.indexType = vao.indexType;
464 vertexArrayObject.indexCount = vao.indexCount;
465 vertexArrayObject.indexStride = vao.indexStride;
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);
477 needVertexAttributeSetup = needVertexAttributeSetup || (vertexBuffers.baseVertex != baseVertex);
478 if (needVertexAttributeSetup) { setupVertexAttributes(baseVertex); }
480 if (!indexBuffer.handle) {
481 LOG_ERROR_ONCE(logger,
"setupIndexedDraw: No index buffer bound.");
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);
498 if (!setupDraw(0))
return;
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));
503 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numVertexes,
false); }
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;
513 const GLenum glPrimitiveType = OpenGLES30::PrimitiveFormats[
static_cast<uint32_t
>(primitiveType)];
514 glDrawElements(currentRasterizerState.wireFrame ? GL_LINES : glPrimitiveType, indexCount, indexType, indexOffset);
516 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndices,
true); }
521 if (startInstance != 0) {
522 LOG_ERROR_ONCE(logger,
"drawInstanced: GLES30 does not support nonzero start instance");
526 if (!setupDraw(0))
return;
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));
531 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numVertexes,
false); }
536 if (startInstance != 0) {
537 LOG_ERROR_ONCE(logger,
"drawInstancedIndexed: GLES30 does not support nonzero start instance");
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;
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));
549 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndices,
true); }
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;
561 needVertexAttributeSetup =
true;
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;
573 needVertexAttributeSetup =
true;
578 vertexArrayObject.currHandle = vertexArrayObjectHandle;
579 needVertexAttributeSetup =
true;
584 nextBlendState.handle = handle;
585 for (
size_t i = 0; i < 4; i++) {
586 nextBlendState.constant[i] = constant ? constant[i] : 0.f;
592 assert(!inRenderPass);
593 if (renderTargets->bindRenderTargets(info.renderTargetHandle, info.depthStencilHandle)) {
594 currentRenderTarget = info.renderTargetHandle;
595 currentDepthStencilTarget = info.depthStencilHandle;
600 glBindFramebuffer(GL_FRAMEBUFFER, 0);
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]);
610 if(info.depthLoadOp == LoadOp::Clear){
611 clearDepth(info.depthClearValue);
614 renderPassInfo = info;
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])){
637 inRenderPass =
false;
643 if (currentRenderTarget != renderTargetHandle || currentDepthStencilTarget != depthStencilHandle) {
645 if (renderTargets->bindRenderTargets(renderTargetHandle, depthStencilHandle)) {
646 currentRenderTarget = renderTargetHandle;
647 currentDepthStencilTarget = depthStencilHandle;
652 glBindFramebuffer(GL_FRAMEBUFFER, 0);
660 glViewport(
static_cast<GLsizei
>(x),
static_cast<GLsizei
>(y),
static_cast<GLsizei
>(width),
static_cast<GLsizei
>(height));
665 glScissor(x, y, width, height);
670 size_t bufferCount = 1;
671 if (HandleIsValid(currentRenderTarget)) {
673 bufferCount = renderTarget.numViews;
675 for (
size_t i = 0; i < bufferCount; i++) {
676 glClearBufferfv(GL_COLOR, GLint(i), color);
682 if (count < 1)
return;
684 if (HandleIsValid(currentRenderTarget)) {
687 GLint n = std::min(GLint(renderTarget.numViews), GLint(count));
689 for (GLint i = 0; i < n; ++i) {
690 switch (renderTarget.viewData[i].basicType) {
694 glClearBufferfv(GL_COLOR, i, colors[i]);
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])
703 glClearBufferuiv(GL_COLOR, i, ucolors);
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])
713 glClearBufferiv(GL_COLOR, i, icolors);
719 glClearBufferfv(GL_COLOR, 0, colors[0]);
725 glDepthMask(GL_TRUE);
726 glClearBufferfv(GL_DEPTH, 0, &depth);
732 if (currentEffect.handle == effectHandle)
return;
735 LOG_ERROR_ONCE(logger,
"Cannot set invalid effect.");
737 currentEffect.ptr =
nullptr;
741 "Effect used before it finished (fake-async) loading");
743 currentEffect.handle = effectHandle;
745 currentEffect.ptr = &effects->effects[effectHandle];
746 glUseProgram(currentEffect.ptr->programId);
749 currentEffect.ptr =
nullptr;
752 needVertexAttributeSetup =
true;
758 if (!HandleIsValid(currentEffect.handle)) {
759 LOG_ERROR_ONCE(logger,
"setTexture: Current effect handle is invalid");
766 LOG_ERROR_ONCE(logger,
"setTexture: Texture binding handle is invalid");
770 GLint unit = GLint(textureBindingHandle.
handle - 1);
771 assert(0 <= unit && unit < GLint(OpenGLES30::maxTexUnits));
772 bindTexture(textureHandle, unit);
777 if (!HandleIsValid(currentEffect.handle) || !HandleIsValid(textureBindingHandle) || !HandleIsValid(textureViewHandle))
return;
781 GLint unit = GLint(textureBindingHandle.
handle - 1);
782 assert(0 <= unit && unit < GLint(OpenGLES30::maxTexUnits));
786 glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, view.
levelIndex);
787 glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, view.
levelIndex + view.
numLevels - 1);
792Cogs::TextureGLES30* Cogs::ContextGLES30::bindTexture(TextureHandle textureHandle, GLuint unit)
794 if (unit == GLuint(~0u)) {
795 unit = activeTexUnit;
797 assert(unit < OpenGLES30::maxTexUnits);
799 TextureGLES30* texture =
nullptr;
801 texture = &textures->textures[textureHandle];
803 if (texture && texture->target == GL_RENDERBUFFER) {
804 LOG_ERROR_ONCE(logger,
"Cannot bind a renderBuffer as a texture sampler");
809 if (texUnits[unit].texture == textureHandle && (texture ==
nullptr || texture->boundAsView == 0)) {
814 if (activeTexUnit != unit) {
815 glActiveTexture(GL_TEXTURE0 + unit);
816 activeTexUnit = unit;
823 if (
HandleIsValid(texUnits[unit].texture) && texUnits[unit].target != texture->target) {
824 glBindTexture(texUnits[unit].target, 0);
827 glBindTexture(texture->target, texture->textureId);
828 texUnits[unit].target = texture->target;
829 texUnits[unit].texture = textureHandle;
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;
843 LOG_WARNING_ONCE(logger,
"setTexture: Invalid texture handle");
847 glBindTexture(texUnits[unit].target, 0);
849 texUnits[unit].target = GL_TEXTURE_2D;
857 if (!samplerStateBindingHandle)
return;
859 const GLint unit =
static_cast<GLint
>(samplerStateBindingHandle.
handle - 1);
860 assert(0 <= unit && unit < GLint(OpenGLES30::maxTexUnits));
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);
869 glBindSampler(unit, 0);
882 glFrontFace(currentRasterizerState.frontCounterClockwise ? GL_CCW : GL_CW);
885 if (currentRasterizerState.cullMode != rasterizerState.
cullMode) {
886 currentRasterizerState.cullMode = rasterizerState.
cullMode;
890 glDisable(GL_CULL_FACE);
894 glEnable(GL_CULL_FACE);
895 glCullFace(GL_FRONT);
899 glEnable(GL_CULL_FACE);
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);
912 glDisable(GL_DEPTH_CLAMP_EXT);
917 if ((currentRasterizerState.depthBias != rasterizerState.
depthBias) ||
920 currentRasterizerState.depthBias = rasterizerState.
depthBias;
922 if ((currentRasterizerState.depthBias != 0.f) || (currentRasterizerState.slopeScaledDepthBias != 0.f))
924 glEnable(GL_POLYGON_OFFSET_FILL);
925 glPolygonOffset(currentRasterizerState.slopeScaledDepthBias, currentRasterizerState.depthBias);
928 glPolygonOffset(0, 0);
929 glDisable(GL_POLYGON_OFFSET_FILL);
933 if (currentRasterizerState.scissor != rasterizerState.
scissor) {
934 currentRasterizerState.scissor = rasterizerState.
scissor;
935 if (currentRasterizerState.scissor) {
936 glEnable(GL_SCISSOR_TEST);
939 glDisable(GL_SCISSOR_TEST);
946 inputLayout.currHandle = handle;
951 TextureGLES30 & sourceTexture = this->textures->textures[sourceTextureHandle];
952 TextureGLES30 & targetTexture = this->textures->textures[targetTextureHandle];
954 if (1 < targetTexture.numSamples) {
955 LOG_ERROR_ONCE(logger,
"Cannot resolve to multisample target");
958 if (sourceTexture.width != targetTexture.width || sourceTexture.height != targetTexture.height) {
959 LOG_ERROR_ONCE(logger,
"Cannot resolve to texture of different size");
962 if (targetTexture.textureId == 0) {
963 LOG_ERROR_ONCE(logger,
"Cannot resolve to null texture");
968 if (sourceTexture.fbo) {
969 glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceTexture.fbo);
971 else if (!setupFramebuffer(sourceTexture, GL_READ_FRAMEBUFFER)) {
976 if (targetTexture.fbo) {
977 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetTexture.fbo);
979 else if (!setupFramebuffer(targetTexture, GL_DRAW_FRAMEBUFFER)) {
986 glClear(GL_DEPTH_BUFFER_BIT);
987 glBlitFramebuffer(0, 0, sourceTexture.width, sourceTexture.height,
988 0, 0, targetTexture.width, targetTexture.height,
989 GL_DEPTH_BUFFER_BIT, GL_NEAREST);
992 glClear(GL_COLOR_BUFFER_BIT);
993 glBlitFramebuffer(0, 0, sourceTexture.width, sourceTexture.height,
994 0, 0, targetTexture.width, targetTexture.height,
995 GL_COLOR_BUFFER_BIT, GL_NEAREST);
997 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1000void Cogs::ContextGLES30::setDefaults()
1003 emptyUniformBuffer = buffers->loadBuffer(
nullptr,
1012 currentRasterizerState.frontCounterClockwise =
false;
1014 currentRasterizerState.depthBias = 0.0;
1015 currentRasterizerState.slopeScaledDepthBias = 0.0;
1016 currentRasterizerState.scissor =
false;
1017 currentRasterizerState.wireFrame =
false;
1018 currentRasterizerState.noDepthClip =
false;
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);
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;
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);
1040 currentDepthStencilState.depthEnabled =
true;
1041 currentDepthStencilState.writeEnabled =
true;
1043 glEnable(GL_DEPTH_TEST);
1044 glDepthMask(GL_TRUE);
1045 glDepthFunc(GL_LESS);
1048 glActiveTexture(GL_TEXTURE0);
1052 glBindVertexArray(0);
1060 currentEffect.ptr =
nullptr;
1063 for (
size_t i = 0; i < size_t(OpenGLES30::BufferTarget::Count); i++) {
1064 glBindBuffer(glBufferTargets[i], 0);
1065 bufferTargets[i].buffer = 0;
1068 for (GLuint i = 0; i < OpenGLES30::maxUniformBuffers; i++) {
1069 if (uniformBufferTargets[i].buffer) {
1070 glBindBufferBase(GL_UNIFORM_BUFFER, i, 0);
1072 uniformBufferTargets[i].buffer = 0;
1073 uniformBufferTargets[i].offset = 0;
1074 uniformBufferTargets[i].size = ~0u;
1080 const BufferGLES30& buffer = buffers->buffers[emptyUniformBuffer];
1081 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer.bufferId);
1088 for (GLuint i = 0; i < OpenGLES30::maxTexUnits; i++) {
1090 glActiveTexture(GL_TEXTURE0 + i);
1091 glBindTexture(texUnits[i].target, 0);
1092 texUnits[i].target = GL_TEXTURE_2D;
1095 glBindSampler(i, 0);
1100 glActiveTexture(GL_TEXTURE0);
1104 glBindVertexArray(0);
1106 for (GLenum i = 0; i < OpenGLES30::maxVertexAttributes; i++) {
1108 if (currentAttributeMask & (1 << i)) {
1109 glDisableVertexAttribArray(i);
1112 vertexBuffers.count = 0;
1113 currentAttributeMask = 0;
1116 currentEffect.ptr =
nullptr;
1124 if (currentDepthStencilState.depthEnabled != depthStencilState.
depthEnabled) {
1126 if (currentDepthStencilState.depthEnabled) {
1127 glEnable(GL_DEPTH_TEST);
1130 glDisable(GL_DEPTH_TEST);
1134 if (currentDepthStencilState.depthEnabled) {
1137 if (currentDepthStencilState.writeEnabled != depthStencilState.
writeEnabled) {
1138 currentDepthStencilState.writeEnabled = depthStencilState.
writeEnabled;
1139 if (currentDepthStencilState.writeEnabled) {
1140 glDepthMask(GL_TRUE);
1143 glDepthMask(GL_FALSE);
1148 if (currentDepthStencilState.depthFunction != depthStencilState.
depthFunction) {
1149 currentDepthStencilState.depthFunction = depthStencilState.
depthFunction;
1150 glDepthFunc(DepthFunctions[currentDepthStencilState.depthFunction]);
1157 LOG_ERROR_ONCE(logger,
"Reading of depth buffer is not supported");
1163 if (!HandleIsValid(bufferHandle))
return;
1164 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
1166 size_t elementSize = 4;
1167 GLenum source = GL_BACK;
1168 GLenum format = GL_RGBA;
1169 GLenum type = GL_UNSIGNED_BYTE;
1172 LOG_ERROR_ONCE(logger,
"Reading color buffer of invalid render target");
1176 if (HandleIsValid(currentRenderTarget)) {
1177 const RenderTargetGLES30& renderTarget = this->renderTargets->renderTargets[this->currentRenderTarget];
1179 source = GL_COLOR_ATTACHMENT0;
1181 if (renderTarget.numViews && HandleIsValid(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;
1189 if (buffer.
size < elementSize * width * height) {
1190 LOG_ERROR_ONCE(logger,
"Color buffer read is larger than buffer size.");
1194 glReadBuffer(source);
1195 bindBuffer(OpenGLES30::BufferTarget::PixelPackBuffer, buffer.
bufferId);
1196 glReadPixels(x, y, width, height, format, type,
nullptr);
1201 if (!HandleIsValid(bufferHandle))
return nullptr;
1204 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
1206 LOG_ERROR_ONCE(logger,
"Buffers can only be mapped once at a time");
1221 GLenum glTarget = bindBuffer(OpenGLES30::BufferTarget::CopyReadBuffer, buffer.
bufferId);
1222 emscripten_glGetBufferSubData(glTarget, 0, buffer.
size, buffer.
mappedData.data());
1227 const void* ptr = glMapBufferRange(glTarget, 0, GLsizei(buffer.
size), GL_MAP_READ_BIT);
1231 glUnmapBuffer(glTarget);
1244 BufferGLES30& buffer = this->buffers->buffers[bufferHandle];
1247 LOG_ERROR_ONCE(logger,
"Unmapping buffer that is not mapped");
1252 GLenum glTarget = bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, buffer);
1254 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.
mappedData.size());
1266 if (!HandleIsValid(bufferHandle)) {
1267 LOG_ERROR_ONCE(logger,
"updateSubBuffer: invalid handle");
1271 GLenum glTarget = bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, buffer);
1272 if (size < buffer.
size) {
1274 glBufferSubData(glTarget, 0, buffer.
size,
nullptr);
1275 glBufferSubData(glTarget, 0,
static_cast<GLsizei
>(size), data);
1278 glBufferSubData(glTarget, 0, buffer.
size, data);
1280 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.
size);
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);
1296void Cogs::ContextGLES30::copyTexture(
TextureHandle dstHandle,
unsigned dstSub,
unsigned dstX,
unsigned dstY,
unsigned dstZ,
TextureHandle srcHandle,
unsigned srcSub)
1300 LOG_ERROR_ONCE(logger,
"copyTexture: invalid destination texture");
1304 if (!HandleIsValid(srcHandle)) {
1305 LOG_ERROR_ONCE(logger,
"copyTexture: invalid source texture");
1309 bool checkCompleteness =
false;
1312 TextureGLES30& srcTexture = textures->textures[srcHandle];
1313 if (srcTexture.textureId == 0) {
1314 LOG_ERROR_ONCE(logger,
"copyTexture: Cannot copy from null texture");
1318 if (srcTexture.target == GL_TEXTURE_2D && srcSub == 0) {
1319 if (srcTexture.fbo) {
1320 glBindFramebuffer(GL_READ_FRAMEBUFFER, srcTexture.fbo);
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;
1330 else if (srcTexture.target == GL_TEXTURE_2D_ARRAY || srcTexture.target == GL_TEXTURE_3D) {
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;
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);
1352 if (dstTexture->target == GL_TEXTURE_2D) {
1353 glCopyTexSubImage2D(GL_TEXTURE_2D,
1356 0, 0, srcTexture.width, srcTexture.height);
1359 else if (dstTexture->target == GL_TEXTURE_2D_ARRAY || dstTexture->target == GL_TEXTURE_3D) {
1360 unsigned dstLevel = 0;
1361 unsigned dstLayer = dstSub;
1362 glCopyTexSubImage3D(dstTexture->target, dstLevel,
1363 dstX, dstY, dstZ + dstLayer,
1364 0, 0, srcTexture.width, srcTexture.height);
1369 LOG_ERROR_ONCE(logger,
"copyTexture: unsupported combination of source and destination texture");
1373 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1378 glDeleteFramebuffers(1, &srcFbo);
1388 if (!HandleIsValid(bufferHandle)) {
1389 LOG_ERROR_ONCE(logger,
"updateSubBuffer: invalid handle");
1393 if (buffer.
size < offset + size) {
1394 LOG_ERROR_ONCE(logger,
"updateSubBuffer: updating outside of buffer bounds");
1397 GLenum glTarget = bindBufferCopy(buffer.
target, buffer);
1398 glBufferSubData(glTarget,
static_cast<GLintptr
>(offset),
static_cast<GLsizei
>(size), data);
1399 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1429 if (!HandleIsValid(destinationHandle)) {
1430 LOG_ERROR_ONCE(logger,
"copyResource: destination buffer is invalid");
1433 BufferGLES30& dstBuffer = buffers->buffers[destinationHandle];
1434 GLenum dstTarget = bindBufferCopy(OpenGLES30::BufferTarget::CopyWriteBuffer, dstBuffer);
1436 if (!HandleIsValid(sourceHandle)) {
1437 LOG_ERROR_ONCE(logger,
"copyResource: source buffer is invalid");
1440 BufferGLES30& srcBuffer = buffers->buffers[sourceHandle];
1441 GLenum srcTarget = bindBuffer(OpenGLES30::BufferTarget::CopyReadBuffer, srcBuffer.bufferId);
1443 if (srcTarget == dstTarget) {
1444 LOG_ERROR_ONCE(logger,
"copyResource: Ending up copying from and to the same target (0x%04x)", srcTarget);
1448 glCopyBufferSubData(srcTarget, dstTarget, 0, 0, srcBuffer.size);
1451void Cogs::ContextGLES30::copyResource(TextureHandle targetTextureHandle, TextureHandle sourceTextureHandle)
1454 resolveResource(sourceTextureHandle, targetTextureHandle);
Log implementation class.
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
@ Ready
The resource has loaded successfully and is ready for use.
Framebuffer
Framebuffers to select from when doing framebuffer operations.
PrimitiveType
Primitive types for interpreting vertex data sent to the graphics pipeline.
@ InstanceMatrix
Instance matrix semantic.
@ None
The buffer can not be either read from or written to by the CPU after creation.
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
GLuint bufferId
OpenGL buffer name.
unsigned short isMapped
Buffer is currently mapped.
OpenGLES30::BufferTarget target
OpenGL bind target.
uint32_t size
Buffer size..
Memory::MemoryBuffer mappedData
Memory map backing store.
unsigned short isIndexBuffer
Buffer is an index buffer.
unsigned short keepMapBacking
Do not release memory mapping backing store after unmap, set to 1 for repeatedly mapped buffers.
unsigned short writeBackMap
Set by map, if one, write back results to GL after unmap (i.e. map with write flags).
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.
Handle template class used to provide opaque, non-converting handles.
static const Handle_t NoHandle
Represents a handle to nothing.
handle_type handle
Internal resource handle.
static const Handle_t InvalidHandle
Represents an invalid handle.
Provides effects and shader management functionality.
EMapMode
Mapping mode enumeration.
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
@ ReadWrite
Read and write access.
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.
unsigned short boundAsView
True if last use of texture was as a view.
Describes how to fetch data from a texture in shaders.
uint32_t layerIndex
Index of the first layer (if array) to fetch from.
uint32_t numLayers
Number of array layers available.
uint32_t numLevels
Number of mipmap levels available.
uint32_t levelIndex
First mipmap level to fetch data from.
TextureHandle texture
Texture.
@ Static
Buffer will be loaded once and used to render many subsequent frames without any updates.