be883bf71052a0d120ceb8eda8e32b4a5eab88f7
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / egl-graphics-controller.h
1 #ifndef DALI_EGL_GRAPHICS_CONTROLLER_H
2 #define DALI_EGL_GRAPHICS_CONTROLLER_H
3
4 /*
5  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 // EXTERNAL INCLUDES
21 #include <dali/graphics-api/graphics-controller.h>
22 #include <queue>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/graphics-sync-abstraction.h>
26 #include <dali/internal/graphics/common/graphics-interface.h>
27 #include <dali/internal/graphics/gles-impl/gles-context.h>
28 #include <dali/internal/graphics/gles-impl/gles-graphics-buffer.h>
29 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
30 #include <dali/internal/graphics/gles-impl/gles-graphics-framebuffer.h>
31 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.h>
32 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
33 #include <dali/internal/graphics/gles-impl/gles-graphics-reflection.h>
34 #include <dali/internal/graphics/gles-impl/gles-graphics-sampler.h>
35 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
36 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
37 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
38 #include <dali/internal/graphics/gles-impl/gles2-graphics-memory.h>
39
40 namespace Dali
41 {
42 namespace Integration
43 {
44 class GlAbstraction;
45 class GlContextHelperAbstraction;
46 } // namespace Integration
47
48 namespace Graphics
49 {
50 namespace GLES
51 {
52 class CommandBuffer;
53 class PipelineCache;
54 } // namespace GLES
55
56 /**
57  * EGL Implementation of the graphics controller.
58  *
59  * Temporarily holds the old GL abstractions whilst dali-core is migrated to the new API.
60  */
61 class EglGraphicsController : public Graphics::Controller
62 {
63 public:
64   /**
65    * @brief Deault constructor
66    */
67   EglGraphicsController() = default;
68
69   /**
70    * @brief Destructor
71    */
72   ~EglGraphicsController() override;
73
74   /**
75    * Initialize the GLES abstraction. This can be called from the main thread.
76    */
77   void InitializeGLES(Integration::GlAbstraction& glAbstraction);
78
79   /**
80    * Initialize with a reference to the GL abstractions.
81    *
82    * Note, this is now executed in the render thread, after core initialization
83    */
84   void Initialize(Integration::GraphicsSyncAbstraction&    syncImplementation,
85                   Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
86                   Internal::Adaptor::GraphicsInterface&    graphicsInterface);
87
88   Integration::GlAbstraction&               GetGlAbstraction() override;
89   Integration::GlContextHelperAbstraction&  GetGlContextHelperAbstraction() override;
90   Internal::Adaptor::EglSyncImplementation& GetEglSyncImplementation();
91
92   /**
93    * @copydoc Dali::Graphics::SubmitCommandBuffers()
94    */
95   void SubmitCommandBuffers(const SubmitInfo& submitInfo) override;
96
97   /**
98    * @copydoc Dali::Graphics::PresentRenderTarget()
99    */
100   void PresentRenderTarget(RenderTarget* renderTarget) override;
101
102   /**
103    * @copydoc Dali::Graphics::WaitIdle()
104    */
105   void WaitIdle() override
106   {
107   }
108
109   /**
110    * @copydoc Dali::Graphics::Pause()
111    */
112   void Pause() override
113   {
114   }
115
116   /**
117    * @copydoc Dali::Graphics::Resume()
118    */
119   void Resume() override
120   {
121   }
122
123   /**
124    * @copydoc Dali::Graphics::Shutdown()
125    */
126   void Shutdown() override
127   {
128     mIsShuttingDown = true;
129   }
130
131   /**
132    * @copydoc Dali::Graphics::Destroy()
133    */
134   void Destroy() override
135   {
136     // Final flush
137     Flush();
138
139     if(mContext)
140     {
141       mContext->GlContextDestroyed();
142     }
143
144     for(auto&& context : mSurfaceContexts)
145     {
146       if(context.second)
147       {
148         context.second->GlContextDestroyed();
149       }
150     }
151   }
152
153   /**
154    * @copydoc Dali::Graphics::UpdateTextures()
155    */
156   void UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
157                       const std::vector<TextureUpdateSourceInfo>& sourceList) override;
158
159   /**
160    * @copydoc Dali::Graphics::GenerateTextureMipmaps()
161    */
162   void GenerateTextureMipmaps(const Texture& texture) override;
163
164   /**
165    * @copydoc Dali::Graphics::EnableDepthStencilBuffer()
166    */
167   bool EnableDepthStencilBuffer(bool enableDepth, bool enableStencil) override
168   {
169     return {};
170   }
171
172   /**
173    * @copydoc Dali::Graphics::RunGarbageCollector()
174    */
175   void RunGarbageCollector(size_t numberOfDiscardedRenderers) override
176   {
177   }
178
179   /**
180    * @copydoc Dali::Graphics::DiscardUnusedResources()
181    */
182   void DiscardUnusedResources() override
183   {
184   }
185
186   /**
187    * @copydoc Dali::Graphics::IsDiscardQueueEmpty()
188    */
189   bool IsDiscardQueueEmpty() override
190   {
191     return {};
192   }
193
194   /**
195    * @copydoc Dali::Graphics::IsDrawOnResumeRequired()
196    */
197   bool IsDrawOnResumeRequired() override
198   {
199     return {};
200   }
201
202   /**
203    * @copydoc Dali::Graphics::CreateBuffer()
204    */
205   Graphics::UniquePtr<Buffer> CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer) override;
206
207   /**
208    * @copydoc Dali::Graphics::CreateCommandBuffer()
209    */
210   Graphics::UniquePtr<CommandBuffer> CreateCommandBuffer(const CommandBufferCreateInfo& commandBufferCreateInfo, Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer) override;
211
212   /**
213    * @copydoc Dali::Graphics::CreateRenderPass()
214    */
215   Graphics::UniquePtr<RenderPass> CreateRenderPass(const RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<RenderPass>&& oldRenderPass) override;
216
217   /**
218    * @copydoc Dali::Graphics::CreateTexture()
219    */
220   Graphics::UniquePtr<Texture> CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture) override;
221
222   /**
223    * @copydoc Dali::Graphics::CreateFramebuffer()
224    */
225   Graphics::UniquePtr<Framebuffer> CreateFramebuffer(const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer) override;
226
227   /**
228    * @copydoc Dali::Graphics::CreatePipeline()
229    */
230   Graphics::UniquePtr<Pipeline> CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Pipeline>&& oldPipeline) override;
231
232   /**
233    * @copydoc Dali::Graphics::CreateProgram()
234    */
235   Graphics::UniquePtr<Program> CreateProgram(const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram) override;
236
237   /**
238    * @copydoc Dali::Graphics::CreateShader()
239    */
240   Graphics::UniquePtr<Shader> CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader) override;
241
242   /**
243    * @copydoc Dali::Graphics::CreateSampler()
244    */
245   Graphics::UniquePtr<Sampler> CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler) override;
246
247   /**
248    * @copydoc Dali::Graphics::CreateRenderTarget()
249    */
250   Graphics::UniquePtr<RenderTarget> CreateRenderTarget(const RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<RenderTarget>&& oldRenderTarget) override;
251
252   /**
253    * @copydoc Dali::Graphics::CreateSyncObject()
254    */
255   Graphics::UniquePtr<SyncObject> CreateSyncObject(const SyncObjectCreateInfo&       syncObjectCreateInfo,
256                                                    Graphics::UniquePtr<SyncObject>&& oldSyncObject) override;
257
258   /**
259    * @copydoc Dali::Graphics::MapBufferRange()
260    */
261   Graphics::UniquePtr<Memory> MapBufferRange(const MapBufferInfo& mapInfo) override;
262
263   /**
264    * @copydoc Dali::Graphics::MapTextureRange()
265    */
266   Graphics::UniquePtr<Memory> MapTextureRange(const MapTextureInfo& mapInfo) override
267   {
268     return nullptr;
269   }
270
271   /**
272    * @copydoc Dali::Graphics::UnmapMemory()
273    */
274   void UnmapMemory(Graphics::UniquePtr<Memory> memory) override
275   {
276   }
277   /**
278    * @copydoc Dali::Graphics::GetTextureMemoryRequirements()
279    */
280   MemoryRequirements GetTextureMemoryRequirements(Texture& texture) const override
281   {
282     return {};
283   }
284
285   /**
286    * @copydoc Dali::Graphics::GetBufferMemoryRequirements()
287    */
288   MemoryRequirements GetBufferMemoryRequirements(Buffer& buffer) const override
289   {
290     return {};
291   }
292
293   /**
294    * @copydoc Dali::Graphics::GetTextureProperties()
295    */
296   const TextureProperties& GetTextureProperties(const Texture& texture) override
297   {
298     // for compiler not to moan
299     static TextureProperties dummy{};
300     return dummy;
301   }
302
303   /**
304    * @copydoc Dali::Graphics::Controller::GetPipelineReflection()
305    */
306
307   [[nodiscard]] const Reflection& GetProgramReflection(const Graphics::Program& program) override;
308
309   /**
310    * @copydoc Dali::Graphics::PipelineEquals()
311    */
312   [[nodiscard]] bool PipelineEquals(const Pipeline& pipeline0, const Pipeline& pipeline1) const override
313   {
314     return {};
315   }
316
317   [[nodiscard]] Integration::GlAbstraction* GetGL() const
318   {
319     if(mIsShuttingDown)
320     {
321       return nullptr;
322     }
323     return mGlAbstraction;
324   }
325
326   [[nodiscard]] Internal::Adaptor::GraphicsInterface* GetGraphicsInterface() const
327   {
328     return mGraphics;
329   }
330
331   // Internal
332   void AddTexture(GLES::Texture& texture);
333
334   /**
335    * @brief Adds buffer to the creation queue
336    * @param buffer
337    */
338   void AddBuffer(GLES::Buffer& buffer);
339
340   /**
341    * @brief Adds framebuffer to the creation queue
342    * @param buffer
343    */
344   void AddFramebuffer(GLES::Framebuffer& framebuffer);
345
346   /**
347    * @brief Pushes Bufer to the discard queue
348    *
349    * Function is called from the UniquePtr custom deleter.
350    *
351    * @param[in] texture Pointer to the texture
352    */
353   void DiscardResource(GLES::Texture* texture)
354   {
355     mDiscardTextureQueue.push(texture);
356   }
357
358   /**
359    * @brief Pushes Buffer to the discard queue
360    *
361    * Function is called from the UniquePtr custom deleter.
362    *
363    * @param[in] buffer Pointer to the buffer object
364    */
365   void DiscardResource(GLES::Buffer* buffer)
366   {
367     mDiscardBufferQueue.push(buffer);
368   }
369
370   /**
371    * @brief Pushes framebuffer to the discard queue
372    *
373    * Function is called from the UniquePtr custom deleter.
374    *
375    * @param[in] framebuffer Pointer to the framebuffer object
376    */
377   void DiscardResource(GLES::Framebuffer* framebuffer)
378   {
379     mDiscardFramebufferQueue.push(framebuffer);
380   }
381
382   /**
383    * @brief Pushes Program to the discard queue
384    *
385    * Function is called from the UniquePtr custom deleter.
386    *
387    * @param[in] program Pointer to the program
388    */
389   void DiscardResource(GLES::Program* program)
390   {
391     mDiscardProgramQueue.push(program);
392   }
393
394   /**
395    * @brief Pushes Shader to the discard queue
396    *
397    * Function is called from the UniquePtr custom deleter.
398    *
399    * @param[in] program Pointer to the Shader
400    */
401   void DiscardResource(GLES::Shader* shader)
402   {
403     mDiscardShaderQueue.push(shader);
404   }
405
406   /**
407    * @brief Pushes CommandBuffer to the discard queue
408    *
409    * Function is called from the UniquePtr custom deleter.
410    *
411    * @param[in] program Pointer to the CommandBuffer
412    */
413   void DiscardResource(GLES::CommandBuffer* commandBuffer)
414   {
415     mDiscardCommandBufferQueue.push(commandBuffer);
416   }
417
418   /**
419    * @brief Pushes Sampler to the discard queue
420    *
421    * Function is called from the UniquePtr custom deleter.
422    *
423    * @param[in] program Pointer to the Sampler
424    */
425   void DiscardResource(GLES::Sampler* sampler)
426   {
427     mDiscardSamplerQueue.push(sampler);
428   }
429
430   /**
431    * @brief Pushes Pipeline to the discard queue
432    *
433    * Function is called from the UniquePtr custom deleter.
434    *
435    * @param[in] program Pointer to the pipeline
436    */
437   void DiscardResource(GLES::Pipeline* pipeline)
438   {
439     mDiscardPipelineQueue.push(pipeline);
440   }
441
442   /**
443    * @brief Flushes all pending updates
444    *
445    * Function flushes all pending resource constructions,
446    * executes command buffers and empties discard queues.
447    */
448   void Flush()
449   {
450     mGraphics->ActivateResourceContext();
451
452     // Process creations
453     ProcessCreateQueues();
454
455     // Process updates
456     ProcessTextureUpdateQueue();
457
458     // Process texture mipmap generation requests
459     ProcessTextureMipmapGenerationQueue();
460
461     // Process main command queue
462     ProcessCommandQueues();
463
464     // Reset texture cache in the contexts while destroying textures
465     ResetTextureCache();
466
467     // Reset buffer cache in the contexts while destroying buffers
468     ResetBufferCache();
469
470     // Process discards
471     ProcessDiscardQueues();
472
473     // Flush pipeline cache to remove unused pipelines
474     if(mPipelineCache)
475     {
476       mPipelineCache->FlushCache();
477     }
478   }
479
480   // Test update to tick controller, usually it will run own thread
481   void ProcessDiscardQueues();
482
483   /**
484    * @brief Processes a create queue for type specified
485    *
486    * @param[in,out] queue Reference to the create queue
487    */
488   template<class T>
489   void ProcessCreateQueue(T& queue)
490   {
491     while(!queue.empty())
492     {
493       auto* object = queue.front();
494       queue.pop();
495
496       // Initialize texture
497       if(!object->InitializeResource())
498       {
499         // TODO: handle error
500       }
501     }
502   }
503
504   /**
505    * @brief Processes a discard queue for type specified
506    *
507    * @param[in,out] queue Reference to the discard queue
508    */
509   template<class U, class T>
510   void ProcessDiscardQueue(T& queue)
511   {
512     while(!queue.empty())
513     {
514       auto* object = const_cast<U*>(queue.front());
515
516       // Destroy
517       object->DestroyResource();
518
519       // Free
520       auto* clbk = object->GetCreateInfo().allocationCallbacks;
521       if(clbk)
522       {
523         // Call destructor
524         object->~U();
525
526         // Free memory
527         clbk->freeCallback(object, clbk->userData);
528       }
529       else
530       {
531         delete object;
532       }
533       queue.pop();
534     }
535   }
536
537   /**
538    * @brief Processes a discard queue for pipeline
539    *
540    * @param[in,out] queue Reference to the create queue
541    */
542   void ProcessDiscardQueue(std::queue<GLES::Pipeline*>& queue)
543   {
544     while(!queue.empty())
545     {
546       auto* object = const_cast<GLES::Pipeline*>(queue.front());
547
548       // Inform the contexts to invalidate the pipeline if cached
549       if(mContext)
550       {
551         mContext->InvalidateCachedPipeline(object);
552       }
553
554       for(auto&& context : mSurfaceContexts)
555       {
556         if(context.second)
557         {
558           context.second->InvalidateCachedPipeline(object);
559         }
560       }
561
562       // Destroy
563       object->DestroyResource();
564
565       // Free
566       auto* clbk = object->GetCreateInfo().allocationCallbacks;
567       if(clbk)
568       {
569         // Call destructor
570         using GLESPipeline = GLES::Pipeline;
571         object->~GLESPipeline();
572
573         // Free memory
574         clbk->freeCallback(object, clbk->userData);
575       }
576       else
577       {
578         delete object;
579       }
580       queue.pop();
581     }
582   }
583
584   /**
585    * @brief Processes all resource create queues
586    */
587   void ProcessCreateQueues();
588
589   /**
590    * @brief Process command queues and buffers
591    */
592   void ProcessCommandQueues();
593
594   /**
595    * @brief Executes all pending texture updates
596    */
597   void ProcessTextureUpdateQueue();
598
599   /**
600    * @brief Executes all pending texture mipmap generation
601    */
602   void ProcessTextureMipmapGenerationQueue();
603
604   /**
605    * @brief Returns program custom parameter
606    *
607    * This function can be used as a backdoor in order to retrieve
608    * certain data out of implementation
609    *
610    * @param[in] program Valid Program object
611    * @param parameterId Integer id of parameter
612    * @param outData Output data
613    * @return True if parameter retrieved
614    */
615   bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override;
616
617   /**
618    * @brief Returns pipeline cache object
619    *
620    * @return Valid pipeline cache object
621    */
622   [[nodiscard]] GLES::PipelineCache& GetPipelineCache() const;
623
624   /**
625    * @brief Returns runtime supported GLES version
626    *
627    * @return GLES version enum
628    */
629   GLES::GLESVersion GetGLESVersion() const
630   {
631     return mGLESVersion;
632   }
633
634   /**
635    * @brief Sets runtime supported GLES version
636    *
637    * @param[in] glesVersion The runtime supported GLES version
638    */
639   void SetGLESVersion(GLES::GLESVersion glesVersion)
640   {
641     mGLESVersion = glesVersion;
642   }
643
644   bool IsShuttingDown() const
645   {
646     return mIsShuttingDown;
647   }
648
649   /**
650    * @brief Reset texture cache in the contexts
651    */
652   void ResetTextureCache()
653   {
654     if(mContext)
655     {
656       mContext->GetGLStateCache().ResetTextureCache();
657     }
658
659     for(auto& context : mSurfaceContexts)
660     {
661       if(context.second)
662       {
663         context.second->GetGLStateCache().ResetTextureCache();
664       }
665     }
666   }
667
668   /**
669    * @brief Reset buffer cache in the contexts
670    */
671   void ResetBufferCache()
672   {
673     if(mContext)
674     {
675       mContext->GetGLStateCache().ResetBufferCache();
676     }
677
678     for(auto& context : mSurfaceContexts)
679     {
680       if(context.second)
681       {
682         context.second->GetGLStateCache().ResetBufferCache();
683       }
684     }
685   }
686
687   void ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer);
688
689   // Resolves presentation
690   void ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget);
691
692   /**
693    * Creates a GLES context for the given render surface
694    *
695    * @param[in] surface The surface whose GLES context to be created.
696    */
697   void CreateSurfaceContext(Dali::RenderSurfaceInterface* surface);
698
699   /**
700    * Deletes a GLES context
701    *
702    * @param[in] surface The surface whose GLES context to be deleted.
703    */
704   void DeleteSurfaceContext(Dali::RenderSurfaceInterface* surface);
705
706   /**
707    * Activate the resource context (shared surfaceless context)
708    */
709   void ActivateResourceContext();
710
711   /**
712    * Activate the surface context
713    *
714    * @param[in] surface The surface whose context to be switched to.
715    */
716   void ActivateSurfaceContext(Dali::RenderSurfaceInterface* surface);
717
718   /**
719    * @brief Returns the current context
720    *
721    * @return the current context
722    */
723   GLES::Context* GetCurrentContext() const
724   {
725     return mCurrentContext;
726   }
727
728 private:
729   Integration::GlAbstraction*              mGlAbstraction{nullptr};
730   Integration::GlContextHelperAbstraction* mGlContextHelperAbstraction{nullptr};
731
732   Internal::Adaptor::EglSyncImplementation* mEglSyncImplementation{nullptr};
733   Internal::Adaptor::GraphicsInterface*     mGraphics{nullptr}; // Pointer to owning structure via interface.
734
735   std::queue<GLES::Texture*> mCreateTextureQueue;  ///< Create queue for texture resource
736   std::queue<GLES::Texture*> mDiscardTextureQueue; ///< Discard queue for texture resource
737
738   std::queue<GLES::Buffer*> mCreateBufferQueue;  ///< Create queue for buffer resource
739   std::queue<GLES::Buffer*> mDiscardBufferQueue; ///< Discard queue for buffer resource
740
741   std::queue<GLES::Program*>             mDiscardProgramQueue;       ///< Discard queue for program resource
742   std::queue<GLES::Pipeline*>            mDiscardPipelineQueue;      ///< Discard queue of pipelines
743   std::queue<GLES::Shader*>              mDiscardShaderQueue;        ///< Discard queue of shaders
744   std::queue<GLES::Sampler*>             mDiscardSamplerQueue;       ///< Discard queue of samplers
745   std::queue<const GLES::CommandBuffer*> mDiscardCommandBufferQueue; ///< Discard queue of command buffers
746   std::queue<GLES::Framebuffer*>         mCreateFramebufferQueue;    ///< Create queue for framebuffer resource
747   std::queue<GLES::Framebuffer*>         mDiscardFramebufferQueue;   ///< Discard queue for framebuffer resource
748
749   std::queue<GLES::CommandBuffer*> mCommandQueue; ///< we may have more in the future
750
751   using TextureUpdateRequest = std::pair<TextureUpdateInfo, TextureUpdateSourceInfo>;
752   std::queue<TextureUpdateRequest> mTextureUpdateRequests;
753
754   std::queue<const GLES::Texture*> mTextureMipmapGenerationRequests; ///< Queue for texture mipmap generation requests
755
756   GLES::Context*                 mCurrentContext{nullptr}; ///< The current context
757   std::unique_ptr<GLES::Context> mContext{nullptr};        ///< Context object handling command buffers execution
758   using SurfaceContextPair = std::pair<Dali::RenderSurfaceInterface*, std::unique_ptr<GLES::Context>>;
759   std::vector<SurfaceContextPair> mSurfaceContexts; ///< Vector of surface context objects handling command buffers execution
760
761   std::unique_ptr<GLES::PipelineCache> mPipelineCache{nullptr}; ///< Internal pipeline cache
762
763   GLES::GLESVersion mGLESVersion{GLES::GLESVersion::GLES_20}; ///< Runtime supported GLES version
764   uint32_t          mTextureUploadTotalCPUMemoryUsed{0u};
765
766   bool mIsShuttingDown{false}; ///< Indicates whether the controller is shutting down
767
768   // todo: to be removed after renderpass
769   const Graphics::Framebuffer* currentFramebuffer{nullptr};
770 };
771
772 } // namespace Graphics
773
774 } // namespace Dali
775
776 #endif //DALI_EGL_GRAPHICS_CONTROLLER_H