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