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