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