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