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