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"
31 namespace Dali::Graphics::GLES
35 Impl(EglGraphicsController& controller)
36 : mController(controller)
43 * Sets the initial GL state.
45 void InitializeGlState()
47 auto& gl = *mController.GetGL();
49 mGlStateCache.mClearColorSet = false;
50 mGlStateCache.mColorMask = true;
51 mGlStateCache.mStencilMask = 0xFF;
52 mGlStateCache.mBlendEnabled = false;
53 mGlStateCache.mDepthBufferEnabled = false;
54 mGlStateCache.mDepthMaskEnabled = false;
55 mGlStateCache.mScissorTestEnabled = false;
56 mGlStateCache.mStencilBufferEnabled = false;
58 gl.Disable(GL_DITHER);
60 mGlStateCache.mBoundArrayBufferId = 0;
61 mGlStateCache.mBoundElementArrayBufferId = 0;
62 mGlStateCache.mActiveTextureUnit = 0;
64 mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE;
65 mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO;
66 mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE;
67 mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO;
69 // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes
70 mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD;
71 mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD;
73 mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back
75 //Initialze vertex attribute cache
76 memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState));
77 memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState));
79 //Initialize bound 2d texture cache
80 memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId));
82 mGlStateCache.mFrameBufferStateCache.Reset();
86 * Flushes vertex attribute location changes to the driver
88 void FlushVertexAttributeLocations()
90 auto& gl = *mController.GetGL();
92 for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i)
94 // see if the cached state is different to the actual state
95 if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i])
97 // it's different so make the change to the driver and update the cached state
98 mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i];
100 if(mGlStateCache.mVertexAttributeCurrentState[i])
102 gl.EnableVertexAttribArray(i);
106 gl.DisableVertexAttribArray(i);
113 * Either enables or disables a vertex attribute location in the cache
114 * The cahnges won't take affect until FlushVertexAttributeLocations is called
115 * @param location attribute location
116 * @param state attribute state
118 void SetVertexAttributeLocation(unsigned int location, bool state)
120 auto& gl = *mController.GetGL();
122 if(location >= MAX_ATTRIBUTE_CACHE_SIZE)
124 // not cached, make the gl call through context
127 gl.EnableVertexAttribArray(location);
131 gl.DisableVertexAttribArray(location);
136 // set the cached state, it will be set at the next draw call
137 // if it's different from the current driver state
138 mGlStateCache.mVertexAttributeCachedState[location] = state;
142 EglGraphicsController& mController;
144 const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
145 const GLES::PipelineImpl* mNewPipeline{nullptr}; ///< New pipeline to be set on flush
147 std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
148 std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
149 GLES::IndexBufferBindingDescriptor mCurrentIndexBufferBinding{};
151 struct VertexBufferBinding
153 GLES::Buffer* buffer{nullptr};
157 // Currently bound buffers
158 std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
160 // Currently bound UBOs (check if it's needed per program!)
161 std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
162 UniformBufferBindingDescriptor mCurrentStandaloneUBOBinding{};
164 // Current render pass and render target
165 const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
166 const GLES::RenderPass* mCurrentRenderPass{nullptr};
168 GLStateCache mGlStateCache{}; ///< GL status cache
170 bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
173 Context::Context(EglGraphicsController& controller)
175 mImpl = std::make_unique<Impl>(controller);
178 Context::~Context() = default;
180 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
182 auto& gl = *mImpl->mController.GetGL();
184 // Execute states if pipeline is changed
185 const auto& currentProgram = mImpl->mCurrentPipeline ? static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program) : nullptr;
186 const auto& newProgram = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
188 if(mImpl->mCurrentPipeline != mImpl->mNewPipeline)
190 if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
192 mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram());
198 // Resolve rasterization state
199 ResolveRasterizationState();
202 // Resolve uniform buffers
203 ResolveUniformBuffers();
206 // Map binding# to sampler location
207 const auto& reflection = newProgram->GetReflection();
208 const auto& samplers = reflection.GetSamplers();
209 for(const auto& binding : mImpl->mCurrentTextureBindings)
211 auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
213 // Texture may not have been initialized yet...(tbm_surface timing issue?)
214 if(!texture->GetGLTexture())
216 // Attempt to reinitialize
217 // @todo need to put this somewhere else where it isn't const.
218 // Maybe post it back on end of initialize queue if initialization fails?
219 texture->InitializeResource();
222 texture->Bind(binding);
224 texture->Prepare(); // @todo also non-const.
226 if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order)
228 // Offset is set to the lexical offset within the frag shader, map it to the texture unit
229 // @todo Explicitly set the texture unit through the graphics interface
230 gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset);
234 // for each attribute bind vertices
235 const auto& pipelineState = mImpl->mNewPipeline->GetCreateInfo();
236 const auto& vi = pipelineState.vertexInputState;
237 for(const auto& attr : vi->attributes)
240 mImpl->SetVertexAttributeLocation(attr.location, true);
242 const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
243 const auto& bufferBinding = vi->bufferBindings[attr.binding];
245 auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
248 BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
250 gl.VertexAttribPointer(attr.location,
251 GLVertexFormat(attr.format).size,
252 GLVertexFormat(attr.format).format,
254 bufferBinding.stride,
255 reinterpret_cast<void*>(attr.offset));
259 const auto& ia = mImpl->mNewPipeline->GetCreateInfo().inputAssemblyState;
264 switch(drawCall.type)
266 case DrawCallDescriptor::Type::DRAW:
268 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
269 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
270 mImpl->mGlStateCache.StencilBufferWriteEnabled());
271 mImpl->FlushVertexAttributeLocations();
273 gl.DrawArrays(GLESTopology(ia->topology),
274 drawCall.draw.firstVertex,
275 drawCall.draw.vertexCount);
278 case DrawCallDescriptor::Type::DRAW_INDEXED:
280 const auto& binding = mImpl->mCurrentIndexBufferBinding;
281 BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding.buffer->GetGLBuffer());
283 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
284 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
285 mImpl->mGlStateCache.StencilBufferWriteEnabled());
286 mImpl->FlushVertexAttributeLocations();
288 auto indexBufferFormat = GLIndexFormat(binding.format).format;
289 gl.DrawElements(GLESTopology(ia->topology),
290 drawCall.drawIndexed.indexCount,
292 reinterpret_cast<void*>(binding.offset));
295 case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
304 if(mImpl->mNewPipeline)
306 mImpl->mCurrentPipeline = mImpl->mNewPipeline;
307 mImpl->mNewPipeline = nullptr;
311 void Context::BindTextures(const std::vector<Graphics::TextureBinding>& bindings)
313 // for each texture allocate slot
314 for(const auto& binding : bindings)
316 // Resize binding array if needed
317 if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
319 mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
321 // Store the binding details
322 mImpl->mCurrentTextureBindings[binding.binding] = binding;
326 void Context::BindVertexBuffers(const std::vector<GLES::VertexBufferBindingDescriptor>& bindings)
328 if(bindings.size() > mImpl->mCurrentVertexBufferBindings.size())
330 mImpl->mCurrentVertexBufferBindings.resize(bindings.size());
332 // Copy only set slots
333 std::copy_if(bindings.begin(), bindings.end(), mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
334 return (nullptr != item.buffer);
338 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
340 mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
343 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
345 DALI_ASSERT_ALWAYS(newPipeline && "Invalid pipeline");
346 mImpl->mNewPipeline = &newPipeline->GetPipeline();
349 void Context::BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings,
350 const UniformBufferBindingDescriptor& standaloneBindings)
352 if(standaloneBindings.buffer)
354 mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
357 if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size())
359 mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1);
362 auto it = uboBindings.begin();
363 for(auto i = 0u; i < uboBindings.size(); ++i)
367 mImpl->mCurrentUBOBindings[i] = *it;
372 void Context::ResolveBlendState()
374 const auto& currentBlendState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().colorBlendState : nullptr;
375 const auto& newBlendState = mImpl->mNewPipeline->GetCreateInfo().colorBlendState;
377 // TODO: prevent leaking the state
383 auto& gl = *mImpl->mController.GetGL();
385 if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable)
387 if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled)
389 mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable;
390 newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
394 if(!newBlendState->blendEnable)
399 BlendFactor newSrcRGB(newBlendState->srcColorBlendFactor);
400 BlendFactor newDstRGB(newBlendState->dstColorBlendFactor);
401 BlendFactor newSrcAlpha(newBlendState->srcAlphaBlendFactor);
402 BlendFactor newDstAlpha(newBlendState->dstAlphaBlendFactor);
404 if(!currentBlendState ||
405 currentBlendState->srcColorBlendFactor != newSrcRGB ||
406 currentBlendState->dstColorBlendFactor != newDstRGB ||
407 currentBlendState->srcAlphaBlendFactor != newSrcAlpha ||
408 currentBlendState->dstAlphaBlendFactor != newDstAlpha)
410 if((mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB != newSrcRGB) ||
411 (mImpl->mGlStateCache.mBlendFuncSeparateDstRGB != newDstRGB) ||
412 (mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha != newSrcAlpha) ||
413 (mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha != newDstAlpha))
415 mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB = newSrcRGB;
416 mImpl->mGlStateCache.mBlendFuncSeparateDstRGB = newDstRGB;
417 mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha = newSrcAlpha;
418 mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha = newDstAlpha;
420 if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha)
422 gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB));
426 gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha));
431 if(!currentBlendState ||
432 currentBlendState->colorBlendOp != newBlendState->colorBlendOp ||
433 currentBlendState->alphaBlendOp != newBlendState->alphaBlendOp)
435 if(mImpl->mGlStateCache.mBlendEquationSeparateModeRGB != newBlendState->colorBlendOp ||
436 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha != newBlendState->alphaBlendOp)
438 mImpl->mGlStateCache.mBlendEquationSeparateModeRGB = newBlendState->colorBlendOp;
439 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha = newBlendState->alphaBlendOp;
441 if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp)
443 gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp));
447 gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp));
453 void Context::ResolveRasterizationState()
455 const auto& currentRasterizationState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().rasterizationState : nullptr;
456 const auto& newRasterizationState = mImpl->mNewPipeline->GetCreateInfo().rasterizationState;
458 // TODO: prevent leaking the state
459 if(!newRasterizationState)
464 auto& gl = *mImpl->mController.GetGL();
466 if(!currentRasterizationState ||
467 currentRasterizationState->cullMode != newRasterizationState->cullMode)
469 if(mImpl->mGlStateCache.mCullFaceMode != newRasterizationState->cullMode)
471 mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode;
472 if(newRasterizationState->cullMode == CullMode::NONE)
474 gl.Disable(GL_CULL_FACE);
478 gl.Enable(GL_CULL_FACE);
479 gl.CullFace(GLCullMode(newRasterizationState->cullMode));
483 // TODO: implement polygon mode (fill, line, points)
484 // seems like we don't support it (no glPolygonMode())
487 void Context::ResolveUniformBuffers()
489 // Resolve standalone uniforms if we have binding
490 if(mImpl->mCurrentStandaloneUBOBinding.buffer)
492 ResolveStandaloneUniforms();
496 void Context::ResolveStandaloneUniforms()
498 auto& gl = *mImpl->mController.GetGL();
500 // Find reflection for program
501 const auto program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
503 const auto& reflection = program->GetReflection();
505 auto extraInfos = reflection.GetStandaloneUniformExtraInfo();
507 const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
509 for(const auto& info : extraInfos)
511 auto type = GLTypeConversion(info.type).type;
512 auto offset = info.offset;
515 case GLType::FLOAT_VEC2:
517 gl.Uniform2fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
520 case GLType::FLOAT_VEC3:
522 gl.Uniform3fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
525 case GLType::FLOAT_VEC4:
527 gl.Uniform4fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
530 case GLType::INT_VEC2:
532 gl.Uniform2iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
535 case GLType::INT_VEC3:
537 gl.Uniform3iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
540 case GLType::INT_VEC4:
542 gl.Uniform4iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
547 // not supported by DALi
550 case GLType::BOOL_VEC2:
552 // not supported by DALi
555 case GLType::BOOL_VEC3:
557 // not supported by DALi
560 case GLType::BOOL_VEC4:
562 // not supported by DALi
567 gl.Uniform1fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
570 case GLType::FLOAT_MAT2:
572 gl.UniformMatrix2fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
575 case GLType::FLOAT_MAT3:
577 gl.UniformMatrix3fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
580 case GLType::FLOAT_MAT4:
582 gl.UniformMatrix4fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
585 case GLType::SAMPLER_2D:
589 case GLType::SAMPLER_CUBE:
600 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
602 auto& renderPass = *renderPassBegin.renderPass;
603 auto& renderTarget = *renderPassBegin.renderTarget;
605 const auto& targetInfo = renderTarget.GetCreateInfo();
607 auto& gl = *mImpl->mController.GetGL();
609 if(targetInfo.surface)
612 BindFrameBuffer(GL_FRAMEBUFFER, 0);
614 else if(targetInfo.framebuffer)
616 // bind framebuffer and swap.
617 renderTarget.GetFramebuffer()->Bind();
620 // clear (ideally cache the setup)
622 // In GL we assume that the last attachment is depth/stencil (we may need
623 // to cache extra information inside GLES RenderTarget if we want to be
624 // more specific in case of MRT)
626 const auto& attachments = *renderPass.GetCreateInfo().attachments;
627 const auto& color0 = attachments[0];
629 if(color0.loadOp == AttachmentLoadOp::CLEAR)
631 mask |= GL_COLOR_BUFFER_BIT;
634 // Something goes wrong here if Alpha mask is GL_TRUE
637 if(!mImpl->mGlStateCache.mClearColorSet ||
638 mImpl->mGlStateCache.mClearColor.r != renderPassBegin.clearValues[0].color.r ||
639 mImpl->mGlStateCache.mClearColor.g != renderPassBegin.clearValues[0].color.g ||
640 mImpl->mGlStateCache.mClearColor.b != renderPassBegin.clearValues[0].color.b ||
641 mImpl->mGlStateCache.mClearColor.a != renderPassBegin.clearValues[0].color.a)
643 gl.ClearColor(renderPassBegin.clearValues[0].color.r,
644 renderPassBegin.clearValues[0].color.g,
645 renderPassBegin.clearValues[0].color.b,
646 renderPassBegin.clearValues[0].color.a);
648 mImpl->mGlStateCache.mClearColorSet = true;
649 mImpl->mGlStateCache.mClearColor = Vector4(renderPassBegin.clearValues[0].color.r,
650 renderPassBegin.clearValues[0].color.g,
651 renderPassBegin.clearValues[0].color.b,
652 renderPassBegin.clearValues[0].color.a);
656 // check for depth stencil
657 if(attachments.size() > 1)
659 const auto& depthStencil = attachments.back();
660 if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
662 if(!mImpl->mGlStateCache.mDepthMaskEnabled)
664 mImpl->mGlStateCache.mDepthMaskEnabled = true;
667 mask |= GL_DEPTH_BUFFER_BIT;
669 if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
671 if(mImpl->mGlStateCache.mStencilMask != 0xFF)
673 mImpl->mGlStateCache.mStencilMask = 0xFF;
674 gl.StencilMask(0xFF);
676 mask |= GL_STENCIL_BUFFER_BIT;
680 SetScissorTestEnabled(true);
681 gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
682 ClearBuffer(mask, true);
683 SetScissorTestEnabled(false);
685 mImpl->mCurrentRenderPass = &renderPass;
686 mImpl->mCurrentRenderTarget = &renderTarget;
689 void Context::EndRenderPass()
691 if(mImpl->mCurrentRenderTarget)
693 if(mImpl->mCurrentRenderTarget->GetFramebuffer())
695 auto& gl = *mImpl->mController.GetGL();
701 void Context::ClearState()
703 mImpl->mCurrentTextureBindings.clear();
706 void Context::ColorMask(bool enabled)
708 if(enabled != mImpl->mGlStateCache.mColorMask)
710 mImpl->mGlStateCache.mColorMask = enabled;
712 auto& gl = *mImpl->mController.GetGL();
713 gl.ColorMask(enabled, enabled, enabled, enabled);
717 void Context::ClearStencilBuffer()
719 ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
722 void Context::ClearDepthBuffer()
724 ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
727 void Context::ClearBuffer(uint32_t mask, bool forceClear)
729 mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
732 auto& gl = *mImpl->mController.GetGL();
737 void Context::SetScissorTestEnabled(bool scissorEnabled)
739 if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
741 mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
743 auto& gl = *mImpl->mController.GetGL();
746 gl.Enable(GL_SCISSOR_TEST);
750 gl.Disable(GL_SCISSOR_TEST);
755 void Context::SetStencilTestEnable(bool stencilEnable)
757 if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
759 mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
761 auto& gl = *mImpl->mController.GetGL();
764 gl.Enable(GL_STENCIL_TEST);
768 gl.Disable(GL_STENCIL_TEST);
773 void Context::StencilMask(uint32_t writeMask)
775 if(writeMask != mImpl->mGlStateCache.mStencilMask)
777 mImpl->mGlStateCache.mStencilMask = writeMask;
779 auto& gl = *mImpl->mController.GetGL();
780 gl.StencilMask(writeMask);
784 void Context::StencilFunc(Graphics::CompareOp compareOp,
786 uint32_t compareMask)
788 if(compareOp != mImpl->mGlStateCache.mStencilFunc ||
789 reference != mImpl->mGlStateCache.mStencilFuncRef ||
790 compareMask != mImpl->mGlStateCache.mStencilFuncMask)
792 mImpl->mGlStateCache.mStencilFunc = compareOp;
793 mImpl->mGlStateCache.mStencilFuncRef = reference;
794 mImpl->mGlStateCache.mStencilFuncMask = compareMask;
796 auto& gl = *mImpl->mController.GetGL();
797 gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
801 void Context::StencilOp(Graphics::StencilOp failOp,
802 Graphics::StencilOp depthFailOp,
803 Graphics::StencilOp passOp)
805 if(failOp != mImpl->mGlStateCache.mStencilOpFail ||
806 depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail ||
807 passOp != mImpl->mGlStateCache.mStencilOpDepthPass)
809 mImpl->mGlStateCache.mStencilOpFail = failOp;
810 mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp;
811 mImpl->mGlStateCache.mStencilOpDepthPass = passOp;
813 auto& gl = *mImpl->mController.GetGL();
814 gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
818 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
820 if(compareOp != mImpl->mGlStateCache.mDepthFunction)
822 mImpl->mGlStateCache.mDepthFunction = compareOp;
823 auto& gl = *mImpl->mController.GetGL();
824 gl.DepthFunc(GLCompareOp(compareOp).op);
828 void Context::SetDepthTestEnable(bool depthTestEnable)
830 if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
832 mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
834 auto& gl = *mImpl->mController.GetGL();
837 gl.Enable(GL_DEPTH_TEST);
841 gl.Disable(GL_DEPTH_TEST);
846 void Context::SetDepthWriteEnable(bool depthWriteEnable)
848 if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
850 mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
852 auto& gl = *mImpl->mController.GetGL();
853 gl.DepthMask(depthWriteEnable);
857 void Context::ActiveTexture(uint32_t textureBindingIndex)
859 if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
861 mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
863 auto& gl = *mImpl->mController.GetGL();
864 gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
868 void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
870 uint32_t typeId = static_cast<uint32_t>(textureTypeId);
871 if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId)
873 mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId;
875 auto& gl = *mImpl->mController.GetGL();
876 gl.BindTexture(target, textureId);
880 void Context::GenerateMipmap(GLenum target)
882 auto& gl = *mImpl->mController.GetGL();
883 gl.GenerateMipmap(target);
886 void Context::BindBuffer(GLenum target, uint32_t bufferId)
888 if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId)
890 mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
892 auto& gl = *mImpl->mController.GetGL();
893 gl.BindBuffer(target, bufferId);
897 void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
899 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
900 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
901 mImpl->mGlStateCache.StencilBufferWriteEnabled());
903 auto& gl = *mImpl->mController.GetGL();
904 gl.DrawBuffers(count, buffers);
907 void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
909 mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
911 auto& gl = *mImpl->mController.GetGL();
912 gl.BindFramebuffer(target, bufferId);
915 void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers)
917 auto& gl = *mImpl->mController.GetGL();
918 gl.GenFramebuffers(count, framebuffers);
920 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers);
923 void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
925 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
927 auto& gl = *mImpl->mController.GetGL();
928 gl.DeleteFramebuffers(count, framebuffers);
931 GLStateCache& Context::GetGLStateCache()
933 return mImpl->mGlStateCache;
936 void Context::GlContextCreated()
938 if(!mImpl->mGlContextCreated)
940 mImpl->mGlContextCreated = true;
942 // Set the initial GL state
943 mImpl->InitializeGlState();
947 void Context::GlContextDestroyed()
949 mImpl->mGlContextCreated = false;
952 void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
954 // Since the pipeline is deleted, invalidate the cached pipeline.
955 if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
957 mImpl->mCurrentPipeline = nullptr;
961 } // namespace Dali::Graphics::GLES