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