2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "gles-context.h"
19 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
20 #include <dali/integration-api/gl-abstraction.h>
21 #include <dali/integration-api/gl-defines.h>
22 #include <dali/internal/graphics/common/graphics-interface.h>
24 #include "egl-graphics-controller.h"
25 #include "gles-graphics-buffer.h"
26 #include "gles-graphics-pipeline.h"
27 #include "gles-graphics-program.h"
28 #include "gles-graphics-render-pass.h"
29 #include "gles-graphics-render-target.h"
34 namespace Dali::Graphics::GLES
38 Impl(EglGraphicsController& controller)
39 : mController(controller)
46 * Binds (and creates) VAO
48 * VAO is fixed per program so it has to be created only once assuming
49 * that VertexInputState has been set correctly for the pipeline.
52 void BindProgramVAO(GLES::ProgramImpl* program, const VertexInputState& vertexInputState)
54 auto& gl = *mController.GetGL();
55 auto iter = mProgramVAOMap.find(program);
56 if(iter != mProgramVAOMap.end())
58 if(mProgramVAOCurrentState != iter->second)
60 mProgramVAOCurrentState = iter->second;
61 gl.BindVertexArray(iter->second);
67 gl.GenVertexArrays(1, &vao);
68 gl.BindVertexArray(vao);
69 mProgramVAOMap[program] = vao;
70 for(const auto& attr : vertexInputState.attributes)
72 gl.EnableVertexAttribArray(attr.location);
75 mProgramVAOCurrentState = vao;
79 * Sets the initial GL state.
81 void InitializeGlState()
83 auto& gl = *mController.GetGL();
85 mGlStateCache.mClearColorSet = false;
86 mGlStateCache.mColorMask = true;
87 mGlStateCache.mStencilMask = 0xFF;
88 mGlStateCache.mBlendEnabled = false;
89 mGlStateCache.mDepthBufferEnabled = false;
90 mGlStateCache.mDepthMaskEnabled = false;
91 mGlStateCache.mScissorTestEnabled = false;
92 mGlStateCache.mStencilBufferEnabled = false;
94 gl.Disable(GL_DITHER);
96 mGlStateCache.mBoundArrayBufferId = 0;
97 mGlStateCache.mBoundElementArrayBufferId = 0;
98 mGlStateCache.mActiveTextureUnit = 0;
100 mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE;
101 mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO;
102 mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE;
103 mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO;
105 // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes
106 mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD;
107 mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD;
109 mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back
111 //Initialze vertex attribute cache
112 memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState));
113 memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState));
115 //Initialize bound 2d texture cache
116 memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId));
118 mGlStateCache.mFrameBufferStateCache.Reset();
122 * Flushes vertex attribute location changes to the driver
124 void FlushVertexAttributeLocations()
126 auto& gl = *mController.GetGL();
128 for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i)
130 // see if the cached state is different to the actual state
131 if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i])
133 // it's different so make the change to the driver and update the cached state
134 mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i];
136 if(mGlStateCache.mVertexAttributeCurrentState[i])
138 gl.EnableVertexAttribArray(i);
142 gl.DisableVertexAttribArray(i);
149 * Either enables or disables a vertex attribute location in the cache
150 * The cahnges won't take affect until FlushVertexAttributeLocations is called
151 * @param location attribute location
152 * @param state attribute state
154 void SetVertexAttributeLocation(unsigned int location, bool state)
156 auto& gl = *mController.GetGL();
158 if(location >= MAX_ATTRIBUTE_CACHE_SIZE)
160 // not cached, make the gl call through context
163 gl.EnableVertexAttribArray(location);
167 gl.DisableVertexAttribArray(location);
172 // set the cached state, it will be set at the next draw call
173 // if it's different from the current driver state
174 mGlStateCache.mVertexAttributeCachedState[location] = state;
178 EglGraphicsController& mController;
180 const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
181 const GLES::PipelineImpl* mNewPipeline{nullptr}; ///< New pipeline to be set on flush
183 std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
184 std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
185 GLES::IndexBufferBindingDescriptor mCurrentIndexBufferBinding{};
187 struct VertexBufferBinding
189 GLES::Buffer* buffer{nullptr};
193 // Currently bound buffers
194 std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
196 // Currently bound UBOs (check if it's needed per program!)
197 std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
198 UniformBufferBindingDescriptor mCurrentStandaloneUBOBinding{};
200 // Current render pass and render target
201 const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
202 const GLES::RenderPass* mCurrentRenderPass{nullptr};
204 // Each context must have own VAOs as they cannot be shared
205 std::map<GLES::ProgramImpl*, uint32_t> mProgramVAOMap; ///< GL program-VAO map
206 uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO
207 GLStateCache mGlStateCache{}; ///< GL status cache
209 bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
212 Context::Context(EglGraphicsController& controller)
214 mImpl = std::make_unique<Impl>(controller);
217 Context::~Context() = default;
219 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
221 auto& gl = *mImpl->mController.GetGL();
223 static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30);
225 // early out if neither current nor new pipelines are set
226 // this behaviour may be valid so no assert
227 if(!mImpl->mCurrentPipeline && !mImpl->mNewPipeline)
232 // Execute states if pipeline is changed
233 const auto currentProgram = mImpl->mCurrentPipeline ? static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program) : nullptr;
235 // case when new pipeline has been set
236 const GLES::Program* newProgram = nullptr;
238 if(mImpl->mNewPipeline)
240 newProgram = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
243 if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline)
245 if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
247 mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram());
253 // Resolve rasterization state
254 ResolveRasterizationState();
257 // Resolve uniform buffers
258 ResolveUniformBuffers();
261 // Map binding# to sampler location
262 const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection();
263 const auto& samplers = reflection.GetSamplers();
264 for(const auto& binding : mImpl->mCurrentTextureBindings)
266 auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
268 // Texture may not have been initialized yet...(tbm_surface timing issue?)
269 if(!texture->GetGLTexture())
271 // Attempt to reinitialize
272 // @todo need to put this somewhere else where it isn't const.
273 // Maybe post it back on end of initialize queue if initialization fails?
274 texture->InitializeResource();
277 texture->Bind(binding);
279 texture->Prepare(); // @todo also non-const.
281 if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order)
283 // Offset is set to the lexical offset within the frag shader, map it to the texture unit
284 // @todo Explicitly set the texture unit through the graphics interface
285 gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset);
289 // for each attribute bind vertices
291 const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo();
292 const auto& vertexInputState = pipelineState.vertexInputState;
296 mImpl->BindProgramVAO(static_cast<const GLES::Program*>(pipelineState.programState->program)->GetImplementation(), *vertexInputState);
299 for(const auto& attr : vertexInputState->attributes)
304 mImpl->SetVertexAttributeLocation(attr.location, true);
307 const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
308 const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding];
310 auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
313 BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
315 gl.VertexAttribPointer(attr.location,
316 GLVertexFormat(attr.format).size,
317 GLVertexFormat(attr.format).format,
319 bufferBinding.stride,
320 reinterpret_cast<void*>(attr.offset));
324 const auto& ia = pipelineState.inputAssemblyState;
329 switch(drawCall.type)
331 case DrawCallDescriptor::Type::DRAW:
333 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
334 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
335 mImpl->mGlStateCache.StencilBufferWriteEnabled());
336 // For GLES3+ we use VAO, for GLES2 internal cache
339 mImpl->FlushVertexAttributeLocations();
342 gl.DrawArrays(GLESTopology(ia->topology),
343 drawCall.draw.firstVertex,
344 drawCall.draw.vertexCount);
347 case DrawCallDescriptor::Type::DRAW_INDEXED:
349 const auto& binding = mImpl->mCurrentIndexBufferBinding;
350 BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding.buffer->GetGLBuffer());
352 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
353 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
354 mImpl->mGlStateCache.StencilBufferWriteEnabled());
356 // For GLES3+ we use VAO, for GLES2 internal cache
359 mImpl->FlushVertexAttributeLocations();
362 auto indexBufferFormat = GLIndexFormat(binding.format).format;
363 gl.DrawElements(GLESTopology(ia->topology),
364 drawCall.drawIndexed.indexCount,
366 reinterpret_cast<void*>(binding.offset));
369 case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
378 if(mImpl->mNewPipeline)
380 mImpl->mCurrentPipeline = mImpl->mNewPipeline;
381 mImpl->mNewPipeline = nullptr;
385 void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count)
387 // for each texture allocate slot
388 for(auto i = 0u; i < count; ++i)
390 auto& binding = bindings[i];
392 // Resize binding array if needed
393 if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
395 mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
397 // Store the binding details
398 mImpl->mCurrentTextureBindings[binding.binding] = binding;
402 void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count)
404 if(count > mImpl->mCurrentVertexBufferBindings.size())
406 mImpl->mCurrentVertexBufferBindings.resize(count);
408 // Copy only set slots
409 std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
410 return (nullptr != item.buffer);
414 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
416 mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
419 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
421 DALI_ASSERT_ALWAYS(newPipeline && "Invalid pipeline");
422 mImpl->mNewPipeline = &newPipeline->GetPipeline();
425 void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings,
427 const UniformBufferBindingDescriptor& standaloneBindings)
429 if(standaloneBindings.buffer)
431 mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
434 if(uboCount >= mImpl->mCurrentUBOBindings.size())
436 mImpl->mCurrentUBOBindings.resize(uboCount + 1);
439 auto it = uboBindings;
440 for(auto i = 0u; i < uboCount; ++i)
444 mImpl->mCurrentUBOBindings[i] = *it;
449 void Context::ResolveBlendState()
451 const auto& currentBlendState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().colorBlendState : nullptr;
452 const auto& newBlendState = mImpl->mNewPipeline->GetCreateInfo().colorBlendState;
454 // TODO: prevent leaking the state
460 auto& gl = *mImpl->mController.GetGL();
462 if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable)
464 if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled)
466 mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable;
467 newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
471 if(!newBlendState->blendEnable)
476 BlendFactor newSrcRGB(newBlendState->srcColorBlendFactor);
477 BlendFactor newDstRGB(newBlendState->dstColorBlendFactor);
478 BlendFactor newSrcAlpha(newBlendState->srcAlphaBlendFactor);
479 BlendFactor newDstAlpha(newBlendState->dstAlphaBlendFactor);
481 if(!currentBlendState ||
482 currentBlendState->srcColorBlendFactor != newSrcRGB ||
483 currentBlendState->dstColorBlendFactor != newDstRGB ||
484 currentBlendState->srcAlphaBlendFactor != newSrcAlpha ||
485 currentBlendState->dstAlphaBlendFactor != newDstAlpha)
487 if((mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB != newSrcRGB) ||
488 (mImpl->mGlStateCache.mBlendFuncSeparateDstRGB != newDstRGB) ||
489 (mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha != newSrcAlpha) ||
490 (mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha != newDstAlpha))
492 mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB = newSrcRGB;
493 mImpl->mGlStateCache.mBlendFuncSeparateDstRGB = newDstRGB;
494 mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha = newSrcAlpha;
495 mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha = newDstAlpha;
497 if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha)
499 gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB));
503 gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha));
508 if(!currentBlendState ||
509 currentBlendState->colorBlendOp != newBlendState->colorBlendOp ||
510 currentBlendState->alphaBlendOp != newBlendState->alphaBlendOp)
512 if(mImpl->mGlStateCache.mBlendEquationSeparateModeRGB != newBlendState->colorBlendOp ||
513 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha != newBlendState->alphaBlendOp)
515 mImpl->mGlStateCache.mBlendEquationSeparateModeRGB = newBlendState->colorBlendOp;
516 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha = newBlendState->alphaBlendOp;
518 if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp)
520 gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp));
521 if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START)
528 gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp));
534 void Context::ResolveRasterizationState()
536 const auto& currentRasterizationState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().rasterizationState : nullptr;
537 const auto& newRasterizationState = mImpl->mNewPipeline->GetCreateInfo().rasterizationState;
539 // TODO: prevent leaking the state
540 if(!newRasterizationState)
545 auto& gl = *mImpl->mController.GetGL();
547 if(!currentRasterizationState ||
548 currentRasterizationState->cullMode != newRasterizationState->cullMode)
550 if(mImpl->mGlStateCache.mCullFaceMode != newRasterizationState->cullMode)
552 mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode;
553 if(newRasterizationState->cullMode == CullMode::NONE)
555 gl.Disable(GL_CULL_FACE);
559 gl.Enable(GL_CULL_FACE);
560 gl.CullFace(GLCullMode(newRasterizationState->cullMode));
564 // TODO: implement polygon mode (fill, line, points)
565 // seems like we don't support it (no glPolygonMode())
568 void Context::ResolveUniformBuffers()
570 // Resolve standalone uniforms if we have binding
571 if(mImpl->mCurrentStandaloneUBOBinding.buffer)
573 ResolveStandaloneUniforms();
577 void Context::ResolveStandaloneUniforms()
579 // Find reflection for program
580 const auto program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
581 const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
583 // Update program uniforms
584 program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
587 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
589 auto& renderPass = *renderPassBegin.renderPass;
590 auto& renderTarget = *renderPassBegin.renderTarget;
592 const auto& targetInfo = renderTarget.GetCreateInfo();
594 auto& gl = *mImpl->mController.GetGL();
596 if(targetInfo.surface)
599 BindFrameBuffer(GL_FRAMEBUFFER, 0);
601 else if(targetInfo.framebuffer)
603 // bind framebuffer and swap.
604 renderTarget.GetFramebuffer()->Bind();
607 // clear (ideally cache the setup)
609 // In GL we assume that the last attachment is depth/stencil (we may need
610 // to cache extra information inside GLES RenderTarget if we want to be
611 // more specific in case of MRT)
613 const auto& attachments = *renderPass.GetCreateInfo().attachments;
614 const auto& color0 = attachments[0];
616 if(color0.loadOp == AttachmentLoadOp::CLEAR)
618 mask |= GL_COLOR_BUFFER_BIT;
621 // Something goes wrong here if Alpha mask is GL_TRUE
624 const auto clearValues = renderPassBegin.clearValues.Ptr();
626 if(!mImpl->mGlStateCache.mClearColorSet ||
627 mImpl->mGlStateCache.mClearColor.r != clearValues[0].color.r ||
628 mImpl->mGlStateCache.mClearColor.g != clearValues[0].color.g ||
629 mImpl->mGlStateCache.mClearColor.b != clearValues[0].color.b ||
630 mImpl->mGlStateCache.mClearColor.a != clearValues[0].color.a)
632 gl.ClearColor(clearValues[0].color.r,
633 clearValues[0].color.g,
634 clearValues[0].color.b,
635 clearValues[0].color.a);
637 mImpl->mGlStateCache.mClearColorSet = true;
638 mImpl->mGlStateCache.mClearColor = Vector4(clearValues[0].color.r,
639 clearValues[0].color.g,
640 clearValues[0].color.b,
641 clearValues[0].color.a);
645 // check for depth stencil
646 if(attachments.size() > 1)
648 const auto& depthStencil = attachments.back();
649 if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
651 if(!mImpl->mGlStateCache.mDepthMaskEnabled)
653 mImpl->mGlStateCache.mDepthMaskEnabled = true;
656 mask |= GL_DEPTH_BUFFER_BIT;
658 if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
660 if(mImpl->mGlStateCache.mStencilMask != 0xFF)
662 mImpl->mGlStateCache.mStencilMask = 0xFF;
663 gl.StencilMask(0xFF);
665 mask |= GL_STENCIL_BUFFER_BIT;
669 SetScissorTestEnabled(true);
670 gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
671 ClearBuffer(mask, true);
672 SetScissorTestEnabled(false);
674 mImpl->mCurrentRenderPass = &renderPass;
675 mImpl->mCurrentRenderTarget = &renderTarget;
678 void Context::EndRenderPass()
680 if(mImpl->mCurrentRenderTarget)
682 if(mImpl->mCurrentRenderTarget->GetFramebuffer())
684 auto& gl = *mImpl->mController.GetGL();
690 void Context::ClearState()
692 mImpl->mCurrentTextureBindings.clear();
695 void Context::ColorMask(bool enabled)
697 if(enabled != mImpl->mGlStateCache.mColorMask)
699 mImpl->mGlStateCache.mColorMask = enabled;
701 auto& gl = *mImpl->mController.GetGL();
702 gl.ColorMask(enabled, enabled, enabled, enabled);
706 void Context::ClearStencilBuffer()
708 ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
711 void Context::ClearDepthBuffer()
713 ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
716 void Context::ClearBuffer(uint32_t mask, bool forceClear)
718 mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
721 auto& gl = *mImpl->mController.GetGL();
726 void Context::InvalidateDepthStencilBuffers()
728 auto& gl = *mImpl->mController.GetGL();
730 GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
731 gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
734 void Context::SetScissorTestEnabled(bool scissorEnabled)
736 if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
738 mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
740 auto& gl = *mImpl->mController.GetGL();
743 gl.Enable(GL_SCISSOR_TEST);
747 gl.Disable(GL_SCISSOR_TEST);
752 void Context::SetStencilTestEnable(bool stencilEnable)
754 if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
756 mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
758 auto& gl = *mImpl->mController.GetGL();
761 gl.Enable(GL_STENCIL_TEST);
765 gl.Disable(GL_STENCIL_TEST);
770 void Context::StencilMask(uint32_t writeMask)
772 if(writeMask != mImpl->mGlStateCache.mStencilMask)
774 mImpl->mGlStateCache.mStencilMask = writeMask;
776 auto& gl = *mImpl->mController.GetGL();
777 gl.StencilMask(writeMask);
781 void Context::StencilFunc(Graphics::CompareOp compareOp,
783 uint32_t compareMask)
785 if(compareOp != mImpl->mGlStateCache.mStencilFunc ||
786 reference != mImpl->mGlStateCache.mStencilFuncRef ||
787 compareMask != mImpl->mGlStateCache.mStencilFuncMask)
789 mImpl->mGlStateCache.mStencilFunc = compareOp;
790 mImpl->mGlStateCache.mStencilFuncRef = reference;
791 mImpl->mGlStateCache.mStencilFuncMask = compareMask;
793 auto& gl = *mImpl->mController.GetGL();
794 gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
798 void Context::StencilOp(Graphics::StencilOp failOp,
799 Graphics::StencilOp depthFailOp,
800 Graphics::StencilOp passOp)
802 if(failOp != mImpl->mGlStateCache.mStencilOpFail ||
803 depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail ||
804 passOp != mImpl->mGlStateCache.mStencilOpDepthPass)
806 mImpl->mGlStateCache.mStencilOpFail = failOp;
807 mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp;
808 mImpl->mGlStateCache.mStencilOpDepthPass = passOp;
810 auto& gl = *mImpl->mController.GetGL();
811 gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
815 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
817 if(compareOp != mImpl->mGlStateCache.mDepthFunction)
819 mImpl->mGlStateCache.mDepthFunction = compareOp;
820 auto& gl = *mImpl->mController.GetGL();
821 gl.DepthFunc(GLCompareOp(compareOp).op);
825 void Context::SetDepthTestEnable(bool depthTestEnable)
827 if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
829 mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
831 auto& gl = *mImpl->mController.GetGL();
834 gl.Enable(GL_DEPTH_TEST);
838 gl.Disable(GL_DEPTH_TEST);
843 void Context::SetDepthWriteEnable(bool depthWriteEnable)
845 if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
847 mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
849 auto& gl = *mImpl->mController.GetGL();
850 gl.DepthMask(depthWriteEnable);
854 void Context::ActiveTexture(uint32_t textureBindingIndex)
856 if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
858 mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
860 auto& gl = *mImpl->mController.GetGL();
861 gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
865 void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
867 uint32_t typeId = static_cast<uint32_t>(textureTypeId);
868 if(mImpl->mGlStateCache.mActiveTextureUnit >= MAX_TEXTURE_UNITS || typeId >= MAX_TEXTURE_TARGET)
870 DALI_LOG_ERROR("Invalid index (%d, %d)\n", mImpl->mGlStateCache.mActiveTextureUnit, typeId);
874 if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId)
876 mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId;
878 auto& gl = *mImpl->mController.GetGL();
879 gl.BindTexture(target, textureId);
883 void Context::GenerateMipmap(GLenum target)
885 auto& gl = *mImpl->mController.GetGL();
886 gl.GenerateMipmap(target);
889 void Context::BindBuffer(GLenum target, uint32_t bufferId)
891 if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId)
893 mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
895 auto& gl = *mImpl->mController.GetGL();
896 gl.BindBuffer(target, bufferId);
900 void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
902 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
903 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
904 mImpl->mGlStateCache.StencilBufferWriteEnabled());
906 auto& gl = *mImpl->mController.GetGL();
907 gl.DrawBuffers(count, buffers);
910 void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
912 mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
914 auto& gl = *mImpl->mController.GetGL();
915 gl.BindFramebuffer(target, bufferId);
918 void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers)
920 auto& gl = *mImpl->mController.GetGL();
921 gl.GenFramebuffers(count, framebuffers);
923 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers);
926 void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
928 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
930 auto& gl = *mImpl->mController.GetGL();
931 gl.DeleteFramebuffers(count, framebuffers);
934 GLStateCache& Context::GetGLStateCache()
936 return mImpl->mGlStateCache;
939 void Context::GlContextCreated()
941 if(!mImpl->mGlContextCreated)
943 mImpl->mGlContextCreated = true;
945 // Set the initial GL state
946 mImpl->InitializeGlState();
950 void Context::GlContextDestroyed()
952 mImpl->mGlContextCreated = false;
955 void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
957 // Since the pipeline is deleted, invalidate the cached pipeline.
958 if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
960 mImpl->mCurrentPipeline = nullptr;
964 } // namespace Dali::Graphics::GLES