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