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