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