Merge "Changed when depth/stencil renderbuffers are created" into devel/master
[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   // early out if neither current nor new pipelines are set
185   // this behaviour may be valid so no assert
186   if(!mImpl->mCurrentPipeline && !mImpl->mNewPipeline)
187   {
188     return;
189   }
190
191   // Execute states if pipeline is changed
192   const auto currentProgram = mImpl->mCurrentPipeline ? static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program) : nullptr;
193
194   // case when new pipeline has been set
195   const GLES::Program* newProgram = nullptr;
196
197   if(mImpl->mNewPipeline)
198   {
199     newProgram = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
200   }
201
202   if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline)
203   {
204     if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
205     {
206       mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram());
207     }
208
209     // Blend state
210     ResolveBlendState();
211
212     // Resolve rasterization state
213     ResolveRasterizationState();
214   }
215
216   // Resolve uniform buffers
217   ResolveUniformBuffers();
218
219   // Bind textures
220   // Map binding# to sampler location
221   const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection();
222   const auto& samplers   = reflection.GetSamplers();
223   for(const auto& binding : mImpl->mCurrentTextureBindings)
224   {
225     auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
226
227     // Texture may not have been initialized yet...(tbm_surface timing issue?)
228     if(!texture->GetGLTexture())
229     {
230       // Attempt to reinitialize
231       // @todo need to put this somewhere else where it isn't const.
232       // Maybe post it back on end of initialize queue if initialization fails?
233       texture->InitializeResource();
234     }
235
236     texture->Bind(binding);
237
238     texture->Prepare(); // @todo also non-const.
239
240     if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order)
241     {
242       // Offset is set to the lexical offset within the frag shader, map it to the texture unit
243       // @todo Explicitly set the texture unit through the graphics interface
244       gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset);
245     }
246   }
247
248   // for each attribute bind vertices
249   const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo();
250   const auto& vi            = pipelineState.vertexInputState;
251   for(const auto& attr : vi->attributes)
252   {
253     // Enable location
254     mImpl->SetVertexAttributeLocation(attr.location, true);
255
256     const auto& bufferSlot    = mImpl->mCurrentVertexBufferBindings[attr.binding];
257     const auto& bufferBinding = vi->bufferBindings[attr.binding];
258
259     auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
260
261     // Bind buffer
262     BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
263
264     gl.VertexAttribPointer(attr.location,
265                            GLVertexFormat(attr.format).size,
266                            GLVertexFormat(attr.format).format,
267                            GL_FALSE,
268                            bufferBinding.stride,
269                            reinterpret_cast<void*>(attr.offset));
270   }
271
272   // Resolve topology
273   const auto& ia = pipelineState.inputAssemblyState;
274
275   // Bind uniforms
276
277   // Resolve draw call
278   switch(drawCall.type)
279   {
280     case DrawCallDescriptor::Type::DRAW:
281     {
282       mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
283                                                                 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
284                                                                 mImpl->mGlStateCache.StencilBufferWriteEnabled());
285       mImpl->FlushVertexAttributeLocations();
286
287       gl.DrawArrays(GLESTopology(ia->topology),
288                     drawCall.draw.firstVertex,
289                     drawCall.draw.vertexCount);
290       break;
291     }
292     case DrawCallDescriptor::Type::DRAW_INDEXED:
293     {
294       const auto& binding = mImpl->mCurrentIndexBufferBinding;
295       BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding.buffer->GetGLBuffer());
296
297       mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
298                                                                 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
299                                                                 mImpl->mGlStateCache.StencilBufferWriteEnabled());
300       mImpl->FlushVertexAttributeLocations();
301
302       auto indexBufferFormat = GLIndexFormat(binding.format).format;
303       gl.DrawElements(GLESTopology(ia->topology),
304                       drawCall.drawIndexed.indexCount,
305                       indexBufferFormat,
306                       reinterpret_cast<void*>(binding.offset));
307       break;
308     }
309     case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
310     {
311       break;
312     }
313   }
314
315   ClearState();
316
317   // Change pipeline
318   if(mImpl->mNewPipeline)
319   {
320     mImpl->mCurrentPipeline = mImpl->mNewPipeline;
321     mImpl->mNewPipeline     = nullptr;
322   }
323 }
324
325 void Context::BindTextures(const std::vector<Graphics::TextureBinding>& bindings)
326 {
327   // for each texture allocate slot
328   for(const auto& binding : bindings)
329   {
330     // Resize binding array if needed
331     if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
332     {
333       mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
334     }
335     // Store the binding details
336     mImpl->mCurrentTextureBindings[binding.binding] = binding;
337   }
338 }
339
340 void Context::BindVertexBuffers(const std::vector<GLES::VertexBufferBindingDescriptor>& bindings)
341 {
342   if(bindings.size() > mImpl->mCurrentVertexBufferBindings.size())
343   {
344     mImpl->mCurrentVertexBufferBindings.resize(bindings.size());
345   }
346   // Copy only set slots
347   std::copy_if(bindings.begin(), bindings.end(), mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
348     return (nullptr != item.buffer);
349   });
350 }
351
352 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
353 {
354   mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
355 }
356
357 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
358 {
359   DALI_ASSERT_ALWAYS(newPipeline && "Invalid pipeline");
360   mImpl->mNewPipeline = &newPipeline->GetPipeline();
361 }
362
363 void Context::BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings,
364                                  const UniformBufferBindingDescriptor&              standaloneBindings)
365 {
366   if(standaloneBindings.buffer)
367   {
368     mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
369   }
370
371   if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size())
372   {
373     mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1);
374   }
375
376   auto it = uboBindings.begin();
377   for(auto i = 0u; i < uboBindings.size(); ++i)
378   {
379     if(it->buffer)
380     {
381       mImpl->mCurrentUBOBindings[i] = *it;
382     }
383   }
384 }
385
386 void Context::ResolveBlendState()
387 {
388   const auto& currentBlendState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().colorBlendState : nullptr;
389   const auto& newBlendState     = mImpl->mNewPipeline->GetCreateInfo().colorBlendState;
390
391   // TODO: prevent leaking the state
392   if(!newBlendState)
393   {
394     return;
395   }
396
397   auto& gl = *mImpl->mController.GetGL();
398
399   if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable)
400   {
401     if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled)
402     {
403       mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable;
404       newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
405     }
406   }
407
408   if(!newBlendState->blendEnable)
409   {
410     return;
411   }
412
413   BlendFactor newSrcRGB(newBlendState->srcColorBlendFactor);
414   BlendFactor newDstRGB(newBlendState->dstColorBlendFactor);
415   BlendFactor newSrcAlpha(newBlendState->srcAlphaBlendFactor);
416   BlendFactor newDstAlpha(newBlendState->dstAlphaBlendFactor);
417
418   if(!currentBlendState ||
419      currentBlendState->srcColorBlendFactor != newSrcRGB ||
420      currentBlendState->dstColorBlendFactor != newDstRGB ||
421      currentBlendState->srcAlphaBlendFactor != newSrcAlpha ||
422      currentBlendState->dstAlphaBlendFactor != newDstAlpha)
423   {
424     if((mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB != newSrcRGB) ||
425        (mImpl->mGlStateCache.mBlendFuncSeparateDstRGB != newDstRGB) ||
426        (mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha != newSrcAlpha) ||
427        (mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha != newDstAlpha))
428     {
429       mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB   = newSrcRGB;
430       mImpl->mGlStateCache.mBlendFuncSeparateDstRGB   = newDstRGB;
431       mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha = newSrcAlpha;
432       mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha = newDstAlpha;
433
434       if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha)
435       {
436         gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB));
437       }
438       else
439       {
440         gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha));
441       }
442     }
443   }
444
445   if(!currentBlendState ||
446      currentBlendState->colorBlendOp != newBlendState->colorBlendOp ||
447      currentBlendState->alphaBlendOp != newBlendState->alphaBlendOp)
448   {
449     if(mImpl->mGlStateCache.mBlendEquationSeparateModeRGB != newBlendState->colorBlendOp ||
450        mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha != newBlendState->alphaBlendOp)
451     {
452       mImpl->mGlStateCache.mBlendEquationSeparateModeRGB   = newBlendState->colorBlendOp;
453       mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha = newBlendState->alphaBlendOp;
454
455       if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp)
456       {
457         gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp));
458       }
459       else
460       {
461         gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp));
462       }
463     }
464   }
465 }
466
467 void Context::ResolveRasterizationState()
468 {
469   const auto& currentRasterizationState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().rasterizationState : nullptr;
470   const auto& newRasterizationState     = mImpl->mNewPipeline->GetCreateInfo().rasterizationState;
471
472   // TODO: prevent leaking the state
473   if(!newRasterizationState)
474   {
475     return;
476   }
477
478   auto& gl = *mImpl->mController.GetGL();
479
480   if(!currentRasterizationState ||
481      currentRasterizationState->cullMode != newRasterizationState->cullMode)
482   {
483     if(mImpl->mGlStateCache.mCullFaceMode != newRasterizationState->cullMode)
484     {
485       mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode;
486       if(newRasterizationState->cullMode == CullMode::NONE)
487       {
488         gl.Disable(GL_CULL_FACE);
489       }
490       else
491       {
492         gl.Enable(GL_CULL_FACE);
493         gl.CullFace(GLCullMode(newRasterizationState->cullMode));
494       }
495     }
496   }
497   // TODO: implement polygon mode (fill, line, points)
498   //       seems like we don't support it (no glPolygonMode())
499 }
500
501 void Context::ResolveUniformBuffers()
502 {
503   // Resolve standalone uniforms if we have binding
504   if(mImpl->mCurrentStandaloneUBOBinding.buffer)
505   {
506     ResolveStandaloneUniforms();
507   }
508 }
509
510 void Context::ResolveStandaloneUniforms()
511 {
512   auto& gl = *mImpl->mController.GetGL();
513
514   // Find reflection for program
515   const auto program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
516
517   const auto& reflection = program->GetReflection();
518
519   auto extraInfos = reflection.GetStandaloneUniformExtraInfo();
520
521   const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
522
523   for(const auto& info : extraInfos)
524   {
525     auto type   = GLTypeConversion(info.type).type;
526     auto offset = info.offset;
527     switch(type)
528     {
529       case GLType::FLOAT_VEC2:
530       {
531         gl.Uniform2fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
532         break;
533       }
534       case GLType::FLOAT_VEC3:
535       {
536         gl.Uniform3fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
537         break;
538       }
539       case GLType::FLOAT_VEC4:
540       {
541         gl.Uniform4fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
542         break;
543       }
544       case GLType::INT_VEC2:
545       {
546         gl.Uniform2iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
547         break;
548       }
549       case GLType::INT_VEC3:
550       {
551         gl.Uniform3iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
552         break;
553       }
554       case GLType::INT_VEC4:
555       {
556         gl.Uniform4iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
557         break;
558       }
559       case GLType::BOOL:
560       {
561         // not supported by DALi
562         break;
563       }
564       case GLType::BOOL_VEC2:
565       {
566         // not supported by DALi
567         break;
568       }
569       case GLType::BOOL_VEC3:
570       {
571         // not supported by DALi
572         break;
573       }
574       case GLType::BOOL_VEC4:
575       {
576         // not supported by DALi
577         break;
578       }
579       case GLType::FLOAT:
580       {
581         gl.Uniform1fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
582         break;
583       }
584       case GLType::FLOAT_MAT2:
585       {
586         gl.UniformMatrix2fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
587         break;
588       }
589       case GLType::FLOAT_MAT3:
590       {
591         gl.UniformMatrix3fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
592         break;
593       }
594       case GLType::FLOAT_MAT4:
595       {
596         gl.UniformMatrix4fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
597         break;
598       }
599       case GLType::SAMPLER_2D:
600       {
601         break;
602       }
603       case GLType::SAMPLER_CUBE:
604       {
605         break;
606       }
607       default:
608       {
609       }
610     }
611   }
612 }
613
614 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
615 {
616   auto& renderPass   = *renderPassBegin.renderPass;
617   auto& renderTarget = *renderPassBegin.renderTarget;
618
619   const auto& targetInfo = renderTarget.GetCreateInfo();
620
621   auto& gl = *mImpl->mController.GetGL();
622
623   if(targetInfo.surface)
624   {
625     // Bind surface FB
626     BindFrameBuffer(GL_FRAMEBUFFER, 0);
627   }
628   else if(targetInfo.framebuffer)
629   {
630     // bind framebuffer and swap.
631     renderTarget.GetFramebuffer()->Bind();
632   }
633
634   // clear (ideally cache the setup)
635
636   // In GL we assume that the last attachment is depth/stencil (we may need
637   // to cache extra information inside GLES RenderTarget if we want to be
638   // more specific in case of MRT)
639
640   const auto& attachments = *renderPass.GetCreateInfo().attachments;
641   const auto& color0      = attachments[0];
642   GLuint      mask        = 0;
643   if(color0.loadOp == AttachmentLoadOp::CLEAR)
644   {
645     mask |= GL_COLOR_BUFFER_BIT;
646
647     // Set clear color
648     // Something goes wrong here if Alpha mask is GL_TRUE
649     ColorMask(true);
650
651     if(!mImpl->mGlStateCache.mClearColorSet ||
652        mImpl->mGlStateCache.mClearColor.r != renderPassBegin.clearValues[0].color.r ||
653        mImpl->mGlStateCache.mClearColor.g != renderPassBegin.clearValues[0].color.g ||
654        mImpl->mGlStateCache.mClearColor.b != renderPassBegin.clearValues[0].color.b ||
655        mImpl->mGlStateCache.mClearColor.a != renderPassBegin.clearValues[0].color.a)
656     {
657       gl.ClearColor(renderPassBegin.clearValues[0].color.r,
658                     renderPassBegin.clearValues[0].color.g,
659                     renderPassBegin.clearValues[0].color.b,
660                     renderPassBegin.clearValues[0].color.a);
661
662       mImpl->mGlStateCache.mClearColorSet = true;
663       mImpl->mGlStateCache.mClearColor    = Vector4(renderPassBegin.clearValues[0].color.r,
664                                                  renderPassBegin.clearValues[0].color.g,
665                                                  renderPassBegin.clearValues[0].color.b,
666                                                  renderPassBegin.clearValues[0].color.a);
667     }
668   }
669
670   // check for depth stencil
671   if(attachments.size() > 1)
672   {
673     const auto& depthStencil = attachments.back();
674     if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
675     {
676       if(!mImpl->mGlStateCache.mDepthMaskEnabled)
677       {
678         mImpl->mGlStateCache.mDepthMaskEnabled = true;
679         gl.DepthMask(true);
680       }
681       mask |= GL_DEPTH_BUFFER_BIT;
682     }
683     if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
684     {
685       if(mImpl->mGlStateCache.mStencilMask != 0xFF)
686       {
687         mImpl->mGlStateCache.mStencilMask = 0xFF;
688         gl.StencilMask(0xFF);
689       }
690       mask |= GL_STENCIL_BUFFER_BIT;
691     }
692   }
693
694   SetScissorTestEnabled(true);
695   gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
696   ClearBuffer(mask, true);
697   SetScissorTestEnabled(false);
698
699   mImpl->mCurrentRenderPass   = &renderPass;
700   mImpl->mCurrentRenderTarget = &renderTarget;
701 }
702
703 void Context::EndRenderPass()
704 {
705   if(mImpl->mCurrentRenderTarget)
706   {
707     if(mImpl->mCurrentRenderTarget->GetFramebuffer())
708     {
709       auto& gl = *mImpl->mController.GetGL();
710       gl.Flush();
711     }
712   }
713 }
714
715 void Context::ClearState()
716 {
717   mImpl->mCurrentTextureBindings.clear();
718 }
719
720 void Context::ColorMask(bool enabled)
721 {
722   if(enabled != mImpl->mGlStateCache.mColorMask)
723   {
724     mImpl->mGlStateCache.mColorMask = enabled;
725
726     auto& gl = *mImpl->mController.GetGL();
727     gl.ColorMask(enabled, enabled, enabled, enabled);
728   }
729 }
730
731 void Context::ClearStencilBuffer()
732 {
733   ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
734 }
735
736 void Context::ClearDepthBuffer()
737 {
738   ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
739 }
740
741 void Context::ClearBuffer(uint32_t mask, bool forceClear)
742 {
743   mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
744   if(mask > 0)
745   {
746     auto& gl = *mImpl->mController.GetGL();
747     gl.Clear(mask);
748   }
749 }
750
751 void Context::SetScissorTestEnabled(bool scissorEnabled)
752 {
753   if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
754   {
755     mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
756
757     auto& gl = *mImpl->mController.GetGL();
758     if(scissorEnabled)
759     {
760       gl.Enable(GL_SCISSOR_TEST);
761     }
762     else
763     {
764       gl.Disable(GL_SCISSOR_TEST);
765     }
766   }
767 }
768
769 void Context::SetStencilTestEnable(bool stencilEnable)
770 {
771   if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
772   {
773     mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
774
775     auto& gl = *mImpl->mController.GetGL();
776     if(stencilEnable)
777     {
778       gl.Enable(GL_STENCIL_TEST);
779     }
780     else
781     {
782       gl.Disable(GL_STENCIL_TEST);
783     }
784   }
785 }
786
787 void Context::StencilMask(uint32_t writeMask)
788 {
789   if(writeMask != mImpl->mGlStateCache.mStencilMask)
790   {
791     mImpl->mGlStateCache.mStencilMask = writeMask;
792
793     auto& gl = *mImpl->mController.GetGL();
794     gl.StencilMask(writeMask);
795   }
796 }
797
798 void Context::StencilFunc(Graphics::CompareOp compareOp,
799                           uint32_t            reference,
800                           uint32_t            compareMask)
801 {
802   if(compareOp != mImpl->mGlStateCache.mStencilFunc ||
803      reference != mImpl->mGlStateCache.mStencilFuncRef ||
804      compareMask != mImpl->mGlStateCache.mStencilFuncMask)
805   {
806     mImpl->mGlStateCache.mStencilFunc     = compareOp;
807     mImpl->mGlStateCache.mStencilFuncRef  = reference;
808     mImpl->mGlStateCache.mStencilFuncMask = compareMask;
809
810     auto& gl = *mImpl->mController.GetGL();
811     gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
812   }
813 }
814
815 void Context::StencilOp(Graphics::StencilOp failOp,
816                         Graphics::StencilOp depthFailOp,
817                         Graphics::StencilOp passOp)
818 {
819   if(failOp != mImpl->mGlStateCache.mStencilOpFail ||
820      depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail ||
821      passOp != mImpl->mGlStateCache.mStencilOpDepthPass)
822   {
823     mImpl->mGlStateCache.mStencilOpFail      = failOp;
824     mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp;
825     mImpl->mGlStateCache.mStencilOpDepthPass = passOp;
826
827     auto& gl = *mImpl->mController.GetGL();
828     gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
829   }
830 }
831
832 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
833 {
834   if(compareOp != mImpl->mGlStateCache.mDepthFunction)
835   {
836     mImpl->mGlStateCache.mDepthFunction = compareOp;
837     auto& gl                            = *mImpl->mController.GetGL();
838     gl.DepthFunc(GLCompareOp(compareOp).op);
839   }
840 }
841
842 void Context::SetDepthTestEnable(bool depthTestEnable)
843 {
844   if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
845   {
846     mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
847
848     auto& gl = *mImpl->mController.GetGL();
849     if(depthTestEnable)
850     {
851       gl.Enable(GL_DEPTH_TEST);
852     }
853     else
854     {
855       gl.Disable(GL_DEPTH_TEST);
856     }
857   }
858 }
859
860 void Context::SetDepthWriteEnable(bool depthWriteEnable)
861 {
862   if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
863   {
864     mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
865
866     auto& gl = *mImpl->mController.GetGL();
867     gl.DepthMask(depthWriteEnable);
868   }
869 }
870
871 void Context::ActiveTexture(uint32_t textureBindingIndex)
872 {
873   if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
874   {
875     mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
876
877     auto& gl = *mImpl->mController.GetGL();
878     gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
879   }
880 }
881
882 void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
883 {
884   uint32_t typeId = static_cast<uint32_t>(textureTypeId);
885   if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId)
886   {
887     mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId;
888
889     auto& gl = *mImpl->mController.GetGL();
890     gl.BindTexture(target, textureId);
891   }
892 }
893
894 void Context::GenerateMipmap(GLenum target)
895 {
896   auto& gl = *mImpl->mController.GetGL();
897   gl.GenerateMipmap(target);
898 }
899
900 void Context::BindBuffer(GLenum target, uint32_t bufferId)
901 {
902   if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId)
903   {
904     mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
905
906     auto& gl = *mImpl->mController.GetGL();
907     gl.BindBuffer(target, bufferId);
908   }
909 }
910
911 void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
912 {
913   mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
914                                                             mImpl->mGlStateCache.DepthBufferWriteEnabled(),
915                                                             mImpl->mGlStateCache.StencilBufferWriteEnabled());
916
917   auto& gl = *mImpl->mController.GetGL();
918   gl.DrawBuffers(count, buffers);
919 }
920
921 void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
922 {
923   mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
924
925   auto& gl = *mImpl->mController.GetGL();
926   gl.BindFramebuffer(target, bufferId);
927 }
928
929 void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers)
930 {
931   auto& gl = *mImpl->mController.GetGL();
932   gl.GenFramebuffers(count, framebuffers);
933
934   mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers);
935 }
936
937 void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
938 {
939   mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
940
941   auto& gl = *mImpl->mController.GetGL();
942   gl.DeleteFramebuffers(count, framebuffers);
943 }
944
945 GLStateCache& Context::GetGLStateCache()
946 {
947   return mImpl->mGlStateCache;
948 }
949
950 void Context::GlContextCreated()
951 {
952   if(!mImpl->mGlContextCreated)
953   {
954     mImpl->mGlContextCreated = true;
955
956     // Set the initial GL state
957     mImpl->InitializeGlState();
958   }
959 }
960
961 void Context::GlContextDestroyed()
962 {
963   mImpl->mGlContextCreated = false;
964 }
965
966 void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
967 {
968   // Since the pipeline is deleted, invalidate the cached pipeline.
969   if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
970   {
971     mImpl->mCurrentPipeline = nullptr;
972   }
973 }
974
975 } // namespace Dali::Graphics::GLES