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