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