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