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