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