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