f020e5b026f37203136519254a2d1b6aacd5e1f7
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-context.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
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>
23
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"
30
31 #include <map>
32 #include <assert.h>
33
34 namespace Dali::Graphics::GLES
35 {
36 struct Context::Impl
37 {
38   Impl(EglGraphicsController& controller)
39   : mController(controller)
40   {
41   }
42
43   ~Impl() = default;
44
45   /**
46    * Binds (and creates) VAO
47    *
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.
50    *
51    */
52   void BindProgramVAO(GLES::ProgramImpl* program, const VertexInputState& vertexInputState)
53   {
54     auto& gl   = *mController.GetGL();
55     auto  iter = mProgramVAOMap.find(program);
56     if(iter != mProgramVAOMap.end())
57     {
58       if(mProgramVAOCurrentState != iter->second)
59       {
60         mProgramVAOCurrentState = iter->second;
61         gl.BindVertexArray(iter->second);
62       }
63       return;
64     }
65
66     uint32_t vao;
67     gl.GenVertexArrays(1, &vao);
68     gl.BindVertexArray(vao);
69     mProgramVAOMap[program] = vao;
70     for(const auto& attr : vertexInputState.attributes)
71     {
72       gl.EnableVertexAttribArray(attr.location);
73     }
74
75     mProgramVAOCurrentState = vao;
76   }
77
78   /**
79    * Sets the initial GL state.
80    */
81   void InitializeGlState()
82   {
83     auto& gl = *mController.GetGL();
84
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;
93
94     gl.Disable(GL_DITHER);
95
96     mGlStateCache.mBoundArrayBufferId        = 0;
97     mGlStateCache.mBoundElementArrayBufferId = 0;
98     mGlStateCache.mActiveTextureUnit         = 0;
99
100     mGlStateCache.mBlendFuncSeparateSrcRGB   = BlendFactor::ONE;
101     mGlStateCache.mBlendFuncSeparateDstRGB   = BlendFactor::ZERO;
102     mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE;
103     mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO;
104
105     // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes
106     mGlStateCache.mBlendEquationSeparateModeRGB   = BlendOp::ADD;
107     mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD;
108
109     mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back
110
111     //Initialze vertex attribute cache
112     memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState));
113     memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState));
114
115     //Initialize bound 2d texture cache
116     memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId));
117
118     mGlStateCache.mFrameBufferStateCache.Reset();
119   }
120
121   /**
122    * Flushes vertex attribute location changes to the driver
123    */
124   void FlushVertexAttributeLocations()
125   {
126     auto& gl = *mController.GetGL();
127
128     for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i)
129     {
130       // see if the cached state is different to the actual state
131       if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i])
132       {
133         // it's different so make the change to the driver and update the cached state
134         mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i];
135
136         if(mGlStateCache.mVertexAttributeCurrentState[i])
137         {
138           gl.EnableVertexAttribArray(i);
139         }
140         else
141         {
142           gl.DisableVertexAttribArray(i);
143         }
144       }
145     }
146   }
147
148   /**
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
153    */
154   void SetVertexAttributeLocation(unsigned int location, bool state)
155   {
156     auto& gl = *mController.GetGL();
157
158     if(location >= MAX_ATTRIBUTE_CACHE_SIZE)
159     {
160       // not cached, make the gl call through context
161       if(state)
162       {
163         gl.EnableVertexAttribArray(location);
164       }
165       else
166       {
167         gl.DisableVertexAttribArray(location);
168       }
169     }
170     else
171     {
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;
175     }
176   }
177
178   EglGraphicsController& mController;
179
180   const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
181   const GLES::PipelineImpl* mNewPipeline{nullptr};     ///< New pipeline to be set on flush
182
183   std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
184   std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
185   GLES::IndexBufferBindingDescriptor    mCurrentIndexBufferBinding{};
186
187   struct VertexBufferBinding
188   {
189     GLES::Buffer* buffer{nullptr};
190     uint32_t      offset{0u};
191   };
192
193   // Currently bound buffers
194   std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
195
196   // Currently bound UBOs (check if it's needed per program!)
197   std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
198   UniformBufferBindingDescriptor              mCurrentStandaloneUBOBinding{};
199
200   // Current render pass and render target
201   const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
202   const GLES::RenderPass*   mCurrentRenderPass{nullptr};
203
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
208
209   bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
210 };
211
212 Context::Context(EglGraphicsController& controller)
213 {
214   mImpl = std::make_unique<Impl>(controller);
215 }
216
217 Context::~Context() = default;
218
219 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
220 {
221   auto& gl = *mImpl->mController.GetGL();
222
223   static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30);
224
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)
228   {
229     return;
230   }
231
232   // Execute states if pipeline is changed
233   const auto currentProgram = mImpl->mCurrentPipeline ? static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program) : nullptr;
234
235   // case when new pipeline has been set
236   const GLES::Program* newProgram = nullptr;
237
238   if(mImpl->mNewPipeline)
239   {
240     newProgram = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
241   }
242
243   if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline)
244   {
245     if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
246     {
247       mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram());
248     }
249
250     // Blend state
251     ResolveBlendState();
252
253     // Resolve rasterization state
254     ResolveRasterizationState();
255   }
256
257   // Resolve uniform buffers
258   ResolveUniformBuffers();
259
260   // Bind textures
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)
265   {
266     auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
267
268     // Texture may not have been initialized yet...(tbm_surface timing issue?)
269     if(!texture->GetGLTexture())
270     {
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();
275     }
276
277     texture->Bind(binding);
278
279     texture->Prepare(); // @todo also non-const.
280
281     if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order)
282     {
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);
286     }
287   }
288
289   // for each attribute bind vertices
290
291   const auto& pipelineState    = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo();
292   const auto& vertexInputState = pipelineState.vertexInputState;
293
294   if(hasGLES3)
295   {
296     mImpl->BindProgramVAO(static_cast<const GLES::Program*>(pipelineState.programState->program)->GetImplementation(), *vertexInputState);
297   }
298
299   for(const auto& attr : vertexInputState->attributes)
300   {
301     // Enable location
302     if(!hasGLES3)
303     {
304       mImpl->SetVertexAttributeLocation(attr.location, true);
305     }
306
307     const auto& bufferSlot    = mImpl->mCurrentVertexBufferBindings[attr.binding];
308     const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding];
309
310     auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
311
312     // Bind buffer
313     BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
314
315     gl.VertexAttribPointer(attr.location,
316                            GLVertexFormat(attr.format).size,
317                            GLVertexFormat(attr.format).format,
318                            GL_FALSE,
319                            bufferBinding.stride,
320                            reinterpret_cast<void*>(attr.offset));
321   }
322
323   // Resolve topology
324   const auto& ia = pipelineState.inputAssemblyState;
325
326   // Bind uniforms
327
328   // Resolve draw call
329   switch(drawCall.type)
330   {
331     case DrawCallDescriptor::Type::DRAW:
332     {
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
337       if(!hasGLES3)
338       {
339         mImpl->FlushVertexAttributeLocations();
340       }
341
342       gl.DrawArrays(GLESTopology(ia->topology),
343                     drawCall.draw.firstVertex,
344                     drawCall.draw.vertexCount);
345       break;
346     }
347     case DrawCallDescriptor::Type::DRAW_INDEXED:
348     {
349       const auto& binding = mImpl->mCurrentIndexBufferBinding;
350       BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding.buffer->GetGLBuffer());
351
352       mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
353                                                                 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
354                                                                 mImpl->mGlStateCache.StencilBufferWriteEnabled());
355
356       // For GLES3+ we use VAO, for GLES2 internal cache
357       if(!hasGLES3)
358       {
359         mImpl->FlushVertexAttributeLocations();
360       }
361
362       auto indexBufferFormat = GLIndexFormat(binding.format).format;
363       gl.DrawElements(GLESTopology(ia->topology),
364                       drawCall.drawIndexed.indexCount,
365                       indexBufferFormat,
366                       reinterpret_cast<void*>(binding.offset));
367       break;
368     }
369     case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
370     {
371       break;
372     }
373   }
374
375   ClearState();
376
377   // Change pipeline
378   if(mImpl->mNewPipeline)
379   {
380     mImpl->mCurrentPipeline = mImpl->mNewPipeline;
381     mImpl->mNewPipeline     = nullptr;
382   }
383 }
384
385 void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count)
386 {
387   // for each texture allocate slot
388   for(auto i = 0u; i < count; ++i)
389   {
390     auto& binding = bindings[i];
391
392     // Resize binding array if needed
393     if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
394     {
395       mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
396     }
397     // Store the binding details
398     mImpl->mCurrentTextureBindings[binding.binding] = binding;
399   }
400 }
401
402 void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count)
403 {
404   if(count > mImpl->mCurrentVertexBufferBindings.size())
405   {
406     mImpl->mCurrentVertexBufferBindings.resize(count);
407   }
408   // Copy only set slots
409   std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
410     return (nullptr != item.buffer);
411   });
412 }
413
414 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
415 {
416   mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
417 }
418
419 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
420 {
421   DALI_ASSERT_ALWAYS(newPipeline && "Invalid pipeline");
422   mImpl->mNewPipeline = &newPipeline->GetPipeline();
423 }
424
425 void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings,
426                                  uint32_t                              uboCount,
427                                  const UniformBufferBindingDescriptor& standaloneBindings)
428 {
429   if(standaloneBindings.buffer)
430   {
431     mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
432   }
433
434   if(uboCount >= mImpl->mCurrentUBOBindings.size())
435   {
436     mImpl->mCurrentUBOBindings.resize(uboCount + 1);
437   }
438
439   auto it = uboBindings;
440   for(auto i = 0u; i < uboCount; ++i)
441   {
442     if(it->buffer)
443     {
444       mImpl->mCurrentUBOBindings[i] = *it;
445     }
446   }
447 }
448
449 void Context::ResolveBlendState()
450 {
451   const auto& currentBlendState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().colorBlendState : nullptr;
452   const auto& newBlendState     = mImpl->mNewPipeline->GetCreateInfo().colorBlendState;
453
454   // TODO: prevent leaking the state
455   if(!newBlendState)
456   {
457     return;
458   }
459
460   auto& gl = *mImpl->mController.GetGL();
461
462   if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable)
463   {
464     if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled)
465     {
466       mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable;
467       newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
468     }
469   }
470
471   if(!newBlendState->blendEnable)
472   {
473     return;
474   }
475
476   BlendFactor newSrcRGB(newBlendState->srcColorBlendFactor);
477   BlendFactor newDstRGB(newBlendState->dstColorBlendFactor);
478   BlendFactor newSrcAlpha(newBlendState->srcAlphaBlendFactor);
479   BlendFactor newDstAlpha(newBlendState->dstAlphaBlendFactor);
480
481   if(!currentBlendState ||
482      currentBlendState->srcColorBlendFactor != newSrcRGB ||
483      currentBlendState->dstColorBlendFactor != newDstRGB ||
484      currentBlendState->srcAlphaBlendFactor != newSrcAlpha ||
485      currentBlendState->dstAlphaBlendFactor != newDstAlpha)
486   {
487     if((mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB != newSrcRGB) ||
488        (mImpl->mGlStateCache.mBlendFuncSeparateDstRGB != newDstRGB) ||
489        (mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha != newSrcAlpha) ||
490        (mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha != newDstAlpha))
491     {
492       mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB   = newSrcRGB;
493       mImpl->mGlStateCache.mBlendFuncSeparateDstRGB   = newDstRGB;
494       mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha = newSrcAlpha;
495       mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha = newDstAlpha;
496
497       if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha)
498       {
499         gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB));
500       }
501       else
502       {
503         gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha));
504       }
505     }
506   }
507
508   if(!currentBlendState ||
509      currentBlendState->colorBlendOp != newBlendState->colorBlendOp ||
510      currentBlendState->alphaBlendOp != newBlendState->alphaBlendOp)
511   {
512     if(mImpl->mGlStateCache.mBlendEquationSeparateModeRGB != newBlendState->colorBlendOp ||
513        mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha != newBlendState->alphaBlendOp)
514     {
515       mImpl->mGlStateCache.mBlendEquationSeparateModeRGB   = newBlendState->colorBlendOp;
516       mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha = newBlendState->alphaBlendOp;
517
518       if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp)
519       {
520         gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp));
521         if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START)
522         {
523           gl.BlendBarrier();
524         }
525       }
526       else
527       {
528         gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp));
529       }
530     }
531   }
532 }
533
534 void Context::ResolveRasterizationState()
535 {
536   const auto& currentRasterizationState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().rasterizationState : nullptr;
537   const auto& newRasterizationState     = mImpl->mNewPipeline->GetCreateInfo().rasterizationState;
538
539   // TODO: prevent leaking the state
540   if(!newRasterizationState)
541   {
542     return;
543   }
544
545   auto& gl = *mImpl->mController.GetGL();
546
547   if(!currentRasterizationState ||
548      currentRasterizationState->cullMode != newRasterizationState->cullMode)
549   {
550     if(mImpl->mGlStateCache.mCullFaceMode != newRasterizationState->cullMode)
551     {
552       mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode;
553       if(newRasterizationState->cullMode == CullMode::NONE)
554       {
555         gl.Disable(GL_CULL_FACE);
556       }
557       else
558       {
559         gl.Enable(GL_CULL_FACE);
560         gl.CullFace(GLCullMode(newRasterizationState->cullMode));
561       }
562     }
563   }
564   // TODO: implement polygon mode (fill, line, points)
565   //       seems like we don't support it (no glPolygonMode())
566 }
567
568 void Context::ResolveUniformBuffers()
569 {
570   // Resolve standalone uniforms if we have binding
571   if(mImpl->mCurrentStandaloneUBOBinding.buffer)
572   {
573     ResolveStandaloneUniforms();
574   }
575 }
576
577 void Context::ResolveStandaloneUniforms()
578 {
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;
582
583   // Update program uniforms
584   program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
585 }
586
587 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
588 {
589   auto& renderPass   = *renderPassBegin.renderPass;
590   auto& renderTarget = *renderPassBegin.renderTarget;
591
592   const auto& targetInfo = renderTarget.GetCreateInfo();
593
594   auto& gl = *mImpl->mController.GetGL();
595
596   if(targetInfo.surface)
597   {
598     // Bind surface FB
599     BindFrameBuffer(GL_FRAMEBUFFER, 0);
600   }
601   else if(targetInfo.framebuffer)
602   {
603     // bind framebuffer and swap.
604     renderTarget.GetFramebuffer()->Bind();
605   }
606
607   // clear (ideally cache the setup)
608
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)
612
613   const auto& attachments = *renderPass.GetCreateInfo().attachments;
614   const auto& color0      = attachments[0];
615   GLuint      mask        = 0;
616   if(color0.loadOp == AttachmentLoadOp::CLEAR)
617   {
618     mask |= GL_COLOR_BUFFER_BIT;
619
620     // Set clear color
621     // Something goes wrong here if Alpha mask is GL_TRUE
622     ColorMask(true);
623
624     const auto clearValues = renderPassBegin.clearValues.Ptr();
625
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)
631     {
632       gl.ClearColor(clearValues[0].color.r,
633                     clearValues[0].color.g,
634                     clearValues[0].color.b,
635                     clearValues[0].color.a);
636
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);
642     }
643   }
644
645   // check for depth stencil
646   if(attachments.size() > 1)
647   {
648     const auto& depthStencil = attachments.back();
649     if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
650     {
651       if(!mImpl->mGlStateCache.mDepthMaskEnabled)
652       {
653         mImpl->mGlStateCache.mDepthMaskEnabled = true;
654         gl.DepthMask(true);
655       }
656       mask |= GL_DEPTH_BUFFER_BIT;
657     }
658     if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
659     {
660       if(mImpl->mGlStateCache.mStencilMask != 0xFF)
661       {
662         mImpl->mGlStateCache.mStencilMask = 0xFF;
663         gl.StencilMask(0xFF);
664       }
665       mask |= GL_STENCIL_BUFFER_BIT;
666     }
667   }
668
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);
673
674   mImpl->mCurrentRenderPass   = &renderPass;
675   mImpl->mCurrentRenderTarget = &renderTarget;
676 }
677
678 void Context::EndRenderPass()
679 {
680   if(mImpl->mCurrentRenderTarget)
681   {
682     if(mImpl->mCurrentRenderTarget->GetFramebuffer())
683     {
684       auto& gl = *mImpl->mController.GetGL();
685       gl.Flush();
686     }
687   }
688 }
689
690 void Context::ClearState()
691 {
692   mImpl->mCurrentTextureBindings.clear();
693 }
694
695 void Context::ColorMask(bool enabled)
696 {
697   if(enabled != mImpl->mGlStateCache.mColorMask)
698   {
699     mImpl->mGlStateCache.mColorMask = enabled;
700
701     auto& gl = *mImpl->mController.GetGL();
702     gl.ColorMask(enabled, enabled, enabled, enabled);
703   }
704 }
705
706 void Context::ClearStencilBuffer()
707 {
708   ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
709 }
710
711 void Context::ClearDepthBuffer()
712 {
713   ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
714 }
715
716 void Context::ClearBuffer(uint32_t mask, bool forceClear)
717 {
718   mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
719   if(mask > 0)
720   {
721     auto& gl = *mImpl->mController.GetGL();
722     gl.Clear(mask);
723   }
724 }
725
726 void Context::InvalidateDepthStencilBuffers()
727 {
728   auto& gl = *mImpl->mController.GetGL();
729
730   GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
731   gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
732 }
733
734 void Context::SetScissorTestEnabled(bool scissorEnabled)
735 {
736   if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
737   {
738     mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
739
740     auto& gl = *mImpl->mController.GetGL();
741     if(scissorEnabled)
742     {
743       gl.Enable(GL_SCISSOR_TEST);
744     }
745     else
746     {
747       gl.Disable(GL_SCISSOR_TEST);
748     }
749   }
750 }
751
752 void Context::SetStencilTestEnable(bool stencilEnable)
753 {
754   if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
755   {
756     mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
757
758     auto& gl = *mImpl->mController.GetGL();
759     if(stencilEnable)
760     {
761       gl.Enable(GL_STENCIL_TEST);
762     }
763     else
764     {
765       gl.Disable(GL_STENCIL_TEST);
766     }
767   }
768 }
769
770 void Context::StencilMask(uint32_t writeMask)
771 {
772   if(writeMask != mImpl->mGlStateCache.mStencilMask)
773   {
774     mImpl->mGlStateCache.mStencilMask = writeMask;
775
776     auto& gl = *mImpl->mController.GetGL();
777     gl.StencilMask(writeMask);
778   }
779 }
780
781 void Context::StencilFunc(Graphics::CompareOp compareOp,
782                           uint32_t            reference,
783                           uint32_t            compareMask)
784 {
785   if(compareOp != mImpl->mGlStateCache.mStencilFunc ||
786      reference != mImpl->mGlStateCache.mStencilFuncRef ||
787      compareMask != mImpl->mGlStateCache.mStencilFuncMask)
788   {
789     mImpl->mGlStateCache.mStencilFunc     = compareOp;
790     mImpl->mGlStateCache.mStencilFuncRef  = reference;
791     mImpl->mGlStateCache.mStencilFuncMask = compareMask;
792
793     auto& gl = *mImpl->mController.GetGL();
794     gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
795   }
796 }
797
798 void Context::StencilOp(Graphics::StencilOp failOp,
799                         Graphics::StencilOp depthFailOp,
800                         Graphics::StencilOp passOp)
801 {
802   if(failOp != mImpl->mGlStateCache.mStencilOpFail ||
803      depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail ||
804      passOp != mImpl->mGlStateCache.mStencilOpDepthPass)
805   {
806     mImpl->mGlStateCache.mStencilOpFail      = failOp;
807     mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp;
808     mImpl->mGlStateCache.mStencilOpDepthPass = passOp;
809
810     auto& gl = *mImpl->mController.GetGL();
811     gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
812   }
813 }
814
815 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
816 {
817   if(compareOp != mImpl->mGlStateCache.mDepthFunction)
818   {
819     mImpl->mGlStateCache.mDepthFunction = compareOp;
820     auto& gl                            = *mImpl->mController.GetGL();
821     gl.DepthFunc(GLCompareOp(compareOp).op);
822   }
823 }
824
825 void Context::SetDepthTestEnable(bool depthTestEnable)
826 {
827   if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
828   {
829     mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
830
831     auto& gl = *mImpl->mController.GetGL();
832     if(depthTestEnable)
833     {
834       gl.Enable(GL_DEPTH_TEST);
835     }
836     else
837     {
838       gl.Disable(GL_DEPTH_TEST);
839     }
840   }
841 }
842
843 void Context::SetDepthWriteEnable(bool depthWriteEnable)
844 {
845   if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
846   {
847     mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
848
849     auto& gl = *mImpl->mController.GetGL();
850     gl.DepthMask(depthWriteEnable);
851   }
852 }
853
854 void Context::ActiveTexture(uint32_t textureBindingIndex)
855 {
856   if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
857   {
858     mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
859
860     auto& gl = *mImpl->mController.GetGL();
861     gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
862   }
863 }
864
865 void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
866 {
867   uint32_t typeId = static_cast<uint32_t>(textureTypeId);
868   if(mImpl->mGlStateCache.mActiveTextureUnit >= MAX_TEXTURE_UNITS || typeId >= MAX_TEXTURE_TARGET)
869   {
870     DALI_LOG_ERROR("Invalid index (%d, %d)\n", mImpl->mGlStateCache.mActiveTextureUnit, typeId);
871     assert(0);
872   }
873
874   if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId)
875   {
876     mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId;
877
878     auto& gl = *mImpl->mController.GetGL();
879     gl.BindTexture(target, textureId);
880   }
881 }
882
883 void Context::GenerateMipmap(GLenum target)
884 {
885   auto& gl = *mImpl->mController.GetGL();
886   gl.GenerateMipmap(target);
887 }
888
889 void Context::BindBuffer(GLenum target, uint32_t bufferId)
890 {
891   if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId)
892   {
893     mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
894
895     auto& gl = *mImpl->mController.GetGL();
896     gl.BindBuffer(target, bufferId);
897   }
898 }
899
900 void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
901 {
902   mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
903                                                             mImpl->mGlStateCache.DepthBufferWriteEnabled(),
904                                                             mImpl->mGlStateCache.StencilBufferWriteEnabled());
905
906   auto& gl = *mImpl->mController.GetGL();
907   gl.DrawBuffers(count, buffers);
908 }
909
910 void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
911 {
912   mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
913
914   auto& gl = *mImpl->mController.GetGL();
915   gl.BindFramebuffer(target, bufferId);
916 }
917
918 void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers)
919 {
920   auto& gl = *mImpl->mController.GetGL();
921   gl.GenFramebuffers(count, framebuffers);
922
923   mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers);
924 }
925
926 void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
927 {
928   mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
929
930   auto& gl = *mImpl->mController.GetGL();
931   gl.DeleteFramebuffers(count, framebuffers);
932 }
933
934 GLStateCache& Context::GetGLStateCache()
935 {
936   return mImpl->mGlStateCache;
937 }
938
939 void Context::GlContextCreated()
940 {
941   if(!mImpl->mGlContextCreated)
942   {
943     mImpl->mGlContextCreated = true;
944
945     // Set the initial GL state
946     mImpl->InitializeGlState();
947   }
948 }
949
950 void Context::GlContextDestroyed()
951 {
952   mImpl->mGlContextCreated = false;
953 }
954
955 void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
956 {
957   // Since the pipeline is deleted, invalidate the cached pipeline.
958   if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
959   {
960     mImpl->mCurrentPipeline = nullptr;
961   }
962 }
963
964 } // namespace Dali::Graphics::GLES