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