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