[dali_2.3.20] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit / dali-toolkit-test-utils / test-graphics-controller.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "test-graphics-controller.h"
18
19 #include <dali/graphics-api/graphics-types.h>
20 #include "test-graphics-buffer.h"
21 #include "test-graphics-command-buffer.h"
22 #include "test-graphics-framebuffer.h"
23 #include "test-graphics-reflection.h"
24 #include "test-graphics-render-pass.h"
25 #include "test-graphics-render-target.h"
26 #include "test-graphics-sampler.h"
27 #include "test-graphics-shader.h"
28 #include "test-graphics-sync-object.h"
29 #include "test-graphics-texture.h"
30
31 #include <dali/integration-api/gl-defines.h>
32 #include <any>
33 #include <cstdio>
34 #include <iostream>
35 #include <memory>
36 #include <sstream>
37
38 namespace Dali
39 {
40 namespace
41 {
42 template<class T>
43 struct TestGraphicsDeleter
44 {
45   TestGraphicsDeleter() = default;
46   void operator()(T* object)
47   {
48     // Discard resource
49     object->DiscardResource();
50   }
51 };
52
53 } //namespace
54
55 std::ostream& operator<<(std::ostream& o, const Graphics::BufferCreateInfo& bufferCreateInfo)
56 {
57   return o << "usage:" << std::hex << bufferCreateInfo.usage << ", size:" << std::dec << bufferCreateInfo.size;
58 }
59
60 std::ostream& operator<<(std::ostream& o, const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo)
61 {
62   return o << "level:" << (commandBufferCreateInfo.level == Graphics::CommandBufferLevel::PRIMARY ? "PRIMARY" : "SECONDARY")
63            << ", fixedCapacity:" << std::dec << commandBufferCreateInfo.fixedCapacity;
64 }
65
66 std::ostream& operator<<(std::ostream& o, const Graphics::TextureType& textureType)
67 {
68   switch(textureType)
69   {
70     case Graphics::TextureType::TEXTURE_2D:
71       o << "TEXTURE_2D";
72       break;
73     case Graphics::TextureType::TEXTURE_3D:
74       o << "TEXTURE_3D";
75       break;
76     case Graphics::TextureType::TEXTURE_CUBEMAP:
77       o << "TEXTURE_CUBEMAP";
78       break;
79   }
80   return o;
81 }
82
83 std::ostream& operator<<(std::ostream& o, const Graphics::Extent2D extent)
84 {
85   o << "width:" << extent.width << ", height:" << extent.height;
86   return o;
87 }
88
89 std::ostream& operator<<(std::ostream& o, const Graphics::TextureCreateInfo& createInfo)
90 {
91   o << "textureType:" << createInfo.textureType
92     << " size:" << createInfo.size
93     << " format:" << static_cast<uint32_t>(createInfo.format)
94     << " mipMapFlag:" << createInfo.mipMapFlag
95     << " layout:" << (createInfo.layout == Graphics::TextureLayout::LINEAR ? "LINEAR" : "OPTIMAL")
96     << " usageFlags:" << std::hex << createInfo.usageFlags
97     << " data:" << std::hex << createInfo.data
98     << " dataSize:" << std::dec << createInfo.dataSize
99     << " nativeImagePtr:" << std::hex << createInfo.nativeImagePtr.Get();
100   return o;
101 }
102
103 std::ostream& operator<<(std::ostream& o, Graphics::SamplerAddressMode addressMode)
104 {
105   switch(addressMode)
106   {
107     case Graphics::SamplerAddressMode::REPEAT:
108       o << "REPEAT";
109       break;
110     case Graphics::SamplerAddressMode::MIRRORED_REPEAT:
111       o << "MIRRORED_REPEAT";
112       break;
113     case Graphics::SamplerAddressMode::CLAMP_TO_EDGE:
114       o << "CLAMP_TO_EDGE";
115       break;
116     case Graphics::SamplerAddressMode::CLAMP_TO_BORDER:
117       o << "CLAMP_TO_BORDER";
118       break;
119     case Graphics::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE:
120       o << "MIRROR_CLAMP_TO_EDGE";
121       break;
122   }
123   return o;
124 }
125
126 std::ostream& operator<<(std::ostream& o, Graphics::SamplerFilter filterMode)
127 {
128   switch(filterMode)
129   {
130     case Graphics::SamplerFilter::LINEAR:
131       o << "LINEAR";
132       break;
133     case Graphics::SamplerFilter::NEAREST:
134       o << "NEAREST";
135       break;
136   }
137   return o;
138 }
139
140 std::ostream& operator<<(std::ostream& o, Graphics::SamplerMipmapMode mipmapMode)
141 {
142   switch(mipmapMode)
143   {
144     case Graphics::SamplerMipmapMode::NONE:
145       o << "NONE";
146       break;
147     case Graphics::SamplerMipmapMode::LINEAR:
148       o << "LINEAR";
149       break;
150     case Graphics::SamplerMipmapMode::NEAREST:
151       o << "NEAREST";
152       break;
153   }
154   return o;
155 }
156
157 std::ostream& operator<<(std::ostream& o, const Graphics::SamplerCreateInfo& createInfo)
158 {
159   o << "minFilter:" << createInfo.minFilter
160     << " magFilter:" << createInfo.magFilter
161     << " wrapModeU:" << createInfo.addressModeU
162     << " wrapModeV:" << createInfo.addressModeV
163     << " wrapModeW:" << createInfo.addressModeW
164     << " mipMapMode:" << createInfo.mipMapMode;
165   return o;
166 }
167
168 std::ostream& operator<<(std::ostream& o, const Graphics::ColorAttachment& colorAttachment)
169 {
170   o << "attachmentId:" << colorAttachment.attachmentId
171     << " layerId:" << colorAttachment.layerId
172     << " levelId:" << colorAttachment.levelId
173     << " texture:" << colorAttachment.texture;
174   return o;
175 }
176
177 std::ostream& operator<<(std::ostream& o, const Graphics::DepthStencilAttachment& depthStencilAttachment)
178 {
179   o << "depthTexture:" << depthStencilAttachment.depthTexture
180     << "depthLevel:" << depthStencilAttachment.depthLevel
181     << "stencilTexture:" << depthStencilAttachment.stencilTexture
182     << "stencilLevel:" << depthStencilAttachment.stencilLevel;
183   return o;
184 }
185
186 std::ostream& operator<<(std::ostream& o, const Graphics::FramebufferCreateInfo& createInfo)
187 {
188   o << "colorAttachments:";
189   for(auto i = 0u; i < createInfo.colorAttachments.size(); ++i)
190   {
191     o << "[" << i << "]=" << createInfo.colorAttachments[i] << "  ";
192   }
193   o << "depthStencilAttachment:" << createInfo.depthStencilAttachment;
194   o << "size: " << createInfo.size;
195   return o;
196 }
197
198 int GetNumComponents(Graphics::VertexInputFormat vertexFormat)
199 {
200   switch(vertexFormat)
201   {
202     case Graphics::VertexInputFormat::UNDEFINED:
203     case Graphics::VertexInputFormat::FLOAT:
204     case Graphics::VertexInputFormat::INTEGER:
205       return 1;
206     case Graphics::VertexInputFormat::IVECTOR2:
207     case Graphics::VertexInputFormat::FVECTOR2:
208       return 2;
209     case Graphics::VertexInputFormat::IVECTOR3:
210     case Graphics::VertexInputFormat::FVECTOR3:
211       return 3;
212     case Graphics::VertexInputFormat::FVECTOR4:
213     case Graphics::VertexInputFormat::IVECTOR4:
214       return 4;
215   }
216   return 1;
217 }
218
219 GLint GetSize(Graphics::VertexInputFormat vertexFormat)
220 {
221   switch(vertexFormat)
222   {
223     case Graphics::VertexInputFormat::UNDEFINED:
224       return 1u;
225     case Graphics::VertexInputFormat::INTEGER:
226     case Graphics::VertexInputFormat::IVECTOR2:
227     case Graphics::VertexInputFormat::IVECTOR3:
228     case Graphics::VertexInputFormat::IVECTOR4:
229       return 2u;
230     case Graphics::VertexInputFormat::FLOAT:
231     case Graphics::VertexInputFormat::FVECTOR2:
232     case Graphics::VertexInputFormat::FVECTOR3:
233     case Graphics::VertexInputFormat::FVECTOR4:
234       return 4u;
235   }
236   return 1u;
237 }
238
239 GLint GetGlType(Graphics::VertexInputFormat vertexFormat)
240 {
241   switch(vertexFormat)
242   {
243     case Graphics::VertexInputFormat::UNDEFINED:
244       return GL_BYTE;
245     case Graphics::VertexInputFormat::INTEGER:
246     case Graphics::VertexInputFormat::IVECTOR2:
247     case Graphics::VertexInputFormat::IVECTOR3:
248     case Graphics::VertexInputFormat::IVECTOR4:
249       return GL_SHORT;
250     case Graphics::VertexInputFormat::FLOAT:
251     case Graphics::VertexInputFormat::FVECTOR2:
252     case Graphics::VertexInputFormat::FVECTOR3:
253     case Graphics::VertexInputFormat::FVECTOR4:
254       return GL_FLOAT;
255   }
256   return GL_BYTE;
257 }
258
259 GLenum GetTopology(Graphics::PrimitiveTopology topology)
260 {
261   switch(topology)
262   {
263     case Graphics::PrimitiveTopology::POINT_LIST:
264       return GL_POINTS;
265
266     case Graphics::PrimitiveTopology::LINE_LIST:
267       return GL_LINES;
268
269     case Graphics::PrimitiveTopology::LINE_LOOP:
270       return GL_LINE_LOOP;
271
272     case Graphics::PrimitiveTopology::LINE_STRIP:
273       return GL_LINE_STRIP;
274
275     case Graphics::PrimitiveTopology::TRIANGLE_LIST:
276       return GL_TRIANGLES;
277
278     case Graphics::PrimitiveTopology::TRIANGLE_STRIP:
279       return GL_TRIANGLE_STRIP;
280
281     case Graphics::PrimitiveTopology::TRIANGLE_FAN:
282       return GL_TRIANGLE_FAN;
283   }
284   return GL_TRIANGLES;
285 }
286
287 GLenum GetCullFace(Graphics::CullMode cullMode)
288 {
289   switch(cullMode)
290   {
291     case Graphics::CullMode::NONE:
292       return GL_NONE;
293     case Graphics::CullMode::FRONT:
294       return GL_FRONT;
295     case Graphics::CullMode::BACK:
296       return GL_BACK;
297     case Graphics::CullMode::FRONT_AND_BACK:
298       return GL_FRONT_AND_BACK;
299   }
300   return GL_NONE;
301 }
302
303 GLenum GetFrontFace(Graphics::FrontFace frontFace)
304 {
305   if(frontFace == Graphics::FrontFace::CLOCKWISE)
306   {
307     return GL_CW;
308   }
309   return GL_CCW;
310 }
311
312 GLenum GetBlendFactor(Graphics::BlendFactor blendFactor)
313 {
314   GLenum glFactor = GL_ZERO;
315
316   switch(blendFactor)
317   {
318     case Graphics::BlendFactor::ZERO:
319       glFactor = GL_ZERO;
320       break;
321     case Graphics::BlendFactor::ONE:
322       glFactor = GL_ONE;
323       break;
324     case Graphics::BlendFactor::SRC_COLOR:
325       glFactor = GL_SRC_COLOR;
326       break;
327     case Graphics::BlendFactor::ONE_MINUS_SRC_COLOR:
328       glFactor = GL_ONE_MINUS_SRC_COLOR;
329       break;
330     case Graphics::BlendFactor::DST_COLOR:
331       glFactor = GL_DST_COLOR;
332       break;
333     case Graphics::BlendFactor::ONE_MINUS_DST_COLOR:
334       glFactor = GL_ONE_MINUS_DST_COLOR;
335       break;
336     case Graphics::BlendFactor::SRC_ALPHA:
337       glFactor = GL_SRC_ALPHA;
338       break;
339     case Graphics::BlendFactor::ONE_MINUS_SRC_ALPHA:
340       glFactor = GL_ONE_MINUS_SRC_ALPHA;
341       break;
342     case Graphics::BlendFactor::DST_ALPHA:
343       glFactor = GL_DST_ALPHA;
344       break;
345     case Graphics::BlendFactor::ONE_MINUS_DST_ALPHA:
346       glFactor = GL_ONE_MINUS_DST_ALPHA;
347       break;
348     case Graphics::BlendFactor::CONSTANT_COLOR:
349       glFactor = GL_CONSTANT_COLOR;
350       break;
351     case Graphics::BlendFactor::ONE_MINUS_CONSTANT_COLOR:
352       glFactor = GL_ONE_MINUS_CONSTANT_COLOR;
353       break;
354     case Graphics::BlendFactor::CONSTANT_ALPHA:
355       glFactor = GL_CONSTANT_ALPHA;
356       break;
357     case Graphics::BlendFactor::ONE_MINUS_CONSTANT_ALPHA:
358       glFactor = GL_ONE_MINUS_CONSTANT_ALPHA;
359       break;
360     case Graphics::BlendFactor::SRC_ALPHA_SATURATE:
361       glFactor = GL_SRC_ALPHA_SATURATE;
362       break;
363       // GLES doesn't appear to have dual source blending.
364     case Graphics::BlendFactor::SRC1_COLOR:
365       glFactor = GL_SRC_COLOR;
366       break;
367     case Graphics::BlendFactor::ONE_MINUS_SRC1_COLOR:
368       glFactor = GL_ONE_MINUS_SRC_COLOR;
369       break;
370     case Graphics::BlendFactor::SRC1_ALPHA:
371       glFactor = GL_SRC_ALPHA;
372       break;
373     case Graphics::BlendFactor::ONE_MINUS_SRC1_ALPHA:
374       glFactor = GL_ONE_MINUS_SRC_ALPHA;
375       break;
376   }
377   return glFactor;
378 }
379
380 GLenum GetBlendOp(Graphics::BlendOp blendOp)
381 {
382   GLenum op = GL_FUNC_ADD;
383   switch(blendOp)
384   {
385     case Graphics::BlendOp::ADD:
386       op = GL_FUNC_ADD;
387       break;
388     case Graphics::BlendOp::SUBTRACT:
389       op = GL_FUNC_SUBTRACT;
390       break;
391     case Graphics::BlendOp::REVERSE_SUBTRACT:
392       op = GL_FUNC_REVERSE_SUBTRACT;
393       break;
394     case Graphics::BlendOp::MIN:
395       op = GL_MIN;
396       break;
397     case Graphics::BlendOp::MAX:
398       op = GL_MAX;
399       break;
400     case Graphics::BlendOp::MULTIPLY:
401     {
402       op = GL_MULTIPLY;
403       break;
404     }
405     case Graphics::BlendOp::SCREEN:
406     {
407       op = GL_SCREEN;
408       break;
409     }
410     case Graphics::BlendOp::OVERLAY:
411     {
412       op = GL_OVERLAY;
413       break;
414     }
415     case Graphics::BlendOp::DARKEN:
416     {
417       op = GL_DARKEN;
418       break;
419     }
420     case Graphics::BlendOp::LIGHTEN:
421     {
422       op = GL_LIGHTEN;
423       break;
424     }
425     case Graphics::BlendOp::COLOR_DODGE:
426     {
427       op = GL_COLORDODGE;
428       break;
429     }
430     case Graphics::BlendOp::COLOR_BURN:
431     {
432       op = GL_COLORBURN;
433       break;
434     }
435     case Graphics::BlendOp::HARD_LIGHT:
436     {
437       op = GL_HARDLIGHT;
438       break;
439     }
440     case Graphics::BlendOp::SOFT_LIGHT:
441     {
442       op = GL_SOFTLIGHT;
443       break;
444     }
445     case Graphics::BlendOp::DIFFERENCE:
446     {
447       op = GL_DIFFERENCE;
448       break;
449     }
450     case Graphics::BlendOp::EXCLUSION:
451     {
452       op = GL_EXCLUSION;
453       break;
454     }
455     case Graphics::BlendOp::HUE:
456     {
457       op = GL_HSL_HUE;
458       break;
459     }
460     case Graphics::BlendOp::SATURATION:
461     {
462       op = GL_HSL_SATURATION;
463       break;
464     }
465     case Graphics::BlendOp::COLOR:
466     {
467       op = GL_HSL_COLOR;
468       break;
469     }
470     case Graphics::BlendOp::LUMINOSITY:
471     {
472       op = GL_HSL_LUMINOSITY;
473       break;
474     }
475   }
476   return op;
477 }
478
479 struct GLCompareOp
480 {
481   constexpr explicit GLCompareOp(Graphics::CompareOp compareOp)
482   {
483     switch(compareOp)
484     {
485       case Graphics::CompareOp::NEVER:
486         op = GL_NEVER;
487         break;
488       case Graphics::CompareOp::LESS:
489         op = GL_LESS;
490         break;
491       case Graphics::CompareOp::EQUAL:
492         op = GL_EQUAL;
493         break;
494       case Graphics::CompareOp::LESS_OR_EQUAL:
495         op = GL_LEQUAL;
496         break;
497       case Graphics::CompareOp::GREATER:
498         op = GL_GREATER;
499         break;
500       case Graphics::CompareOp::NOT_EQUAL:
501         op = GL_NOTEQUAL;
502         break;
503       case Graphics::CompareOp::GREATER_OR_EQUAL:
504         op = GL_GEQUAL;
505         break;
506       case Graphics::CompareOp::ALWAYS:
507         op = GL_ALWAYS;
508         break;
509     }
510   }
511   GLenum op{GL_LESS};
512 };
513
514 struct GLStencilOp
515 {
516   constexpr explicit GLStencilOp(Graphics::StencilOp stencilOp)
517   {
518     switch(stencilOp)
519     {
520       case Graphics::StencilOp::KEEP:
521         op = GL_KEEP;
522         break;
523       case Graphics::StencilOp::ZERO:
524         op = GL_ZERO;
525         break;
526       case Graphics::StencilOp::REPLACE:
527         op = GL_REPLACE;
528         break;
529       case Graphics::StencilOp::INCREMENT_AND_CLAMP:
530         op = GL_INCR;
531         break;
532       case Graphics::StencilOp::DECREMENT_AND_CLAMP:
533         op = GL_DECR;
534         break;
535       case Graphics::StencilOp::INVERT:
536         op = GL_INVERT;
537         break;
538       case Graphics::StencilOp::INCREMENT_AND_WRAP:
539         op = GL_INCR_WRAP;
540         break;
541       case Graphics::StencilOp::DECREMENT_AND_WRAP:
542         op = GL_DECR_WRAP;
543         break;
544     }
545   }
546   GLenum op{GL_KEEP};
547 };
548
549 class TestGraphicsMemory : public Graphics::Memory
550 {
551 public:
552   TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize)
553   : mCallStack(callStack),
554     mBuffer(buffer),
555     mMappedOffset(mappedOffset),
556     mMappedSize(mappedSize),
557     mLockedOffset(0u),
558     mLockedSize(0u)
559   {
560   }
561
562   void* LockRegion(uint32_t offset, uint32_t size) override
563   {
564     std::ostringstream o;
565     o << offset << ", " << size;
566     mCallStack.PushCall("Memory::LockRegion", o.str());
567
568     if(offset > mMappedOffset + mMappedSize ||
569        size + offset > mMappedOffset + mMappedSize)
570     {
571       fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds");
572       mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing
573     }
574     mLockedOffset = offset;
575     mLockedSize   = size;
576     return &mBuffer.memory[mMappedOffset + offset];
577   }
578
579   void Unlock(bool flush) override
580   {
581     mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush"));
582     if(flush)
583     {
584       Flush();
585     }
586   }
587
588   void Flush() override
589   {
590     mCallStack.PushCall("Memory::Flush", "");
591     mBuffer.Bind();
592     mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize);
593     mBuffer.Unbind();
594   }
595
596   TraceCallStack&     mCallStack;
597   TestGraphicsBuffer& mBuffer;
598   uint32_t            mMappedOffset;
599   uint32_t            mMappedSize;
600   uint32_t            mLockedOffset;
601   uint32_t            mLockedSize;
602 };
603
604 TestGraphicsController::TestGraphicsController()
605 : mCallStack(false, "TestGraphicsController."),
606   mCommandBufferCallStack(false, "TestCommandBuffer."),
607   mFrameBufferCallStack(false, "TestFrameBuffer.")
608 {
609   mCallStack.Enable(true);
610   mCommandBufferCallStack.Enable(true);
611   auto& trace = mGl.GetTextureTrace();
612   trace.Enable(true);
613   trace.EnableLogging(false);
614 }
615
616 void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo)
617 {
618   TraceCallStack::NamedParams namedParams;
619   namedParams["submitInfo"] << "cmdBuffer[" << submitInfo.cmdBuffer.size()
620                             << "], flags:" << std::hex << submitInfo.flags;
621
622   mCallStack.PushCall("SubmitCommandBuffers", "", namedParams);
623
624   mSubmitStack.emplace_back(submitInfo);
625
626   for(auto& graphicsCommandBuffer : submitInfo.cmdBuffer)
627   {
628     auto commandBuffer = Uncast<TestGraphicsCommandBuffer>(graphicsCommandBuffer);
629     ProcessCommandBuffer(*commandBuffer);
630   }
631 }
632
633 void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& commandBuffer)
634 {
635   bool                     scissorEnabled = false;
636   TestGraphicsFramebuffer* currentFramebuffer{nullptr};
637   TestGraphicsPipeline*    currentPipeline{nullptr};
638
639   for(auto& cmd : commandBuffer.GetCommands())
640   {
641     // process command
642     switch(cmd.type)
643     {
644       case CommandType::FLUSH:
645       {
646         // Nothing to do here
647         break;
648       }
649       case CommandType::BIND_TEXTURES:
650       {
651         for(auto& binding : cmd.data.bindTextures.textureBindings)
652         {
653           if(binding.texture)
654           {
655             auto texture = Uncast<TestGraphicsTexture>(binding.texture);
656             texture->Bind(binding.binding);
657
658             if(binding.sampler)
659             {
660               auto sampler = Uncast<TestGraphicsSampler>(binding.sampler);
661               if(sampler)
662               {
663                 sampler->Apply(texture->GetTarget());
664               }
665             }
666
667             texture->Prepare(); // Ensure native texture is ready
668           }
669         }
670         break;
671       }
672       case CommandType::BIND_VERTEX_BUFFERS:
673       {
674         for(auto& binding : cmd.data.bindVertexBuffers.vertexBufferBindings)
675         {
676           auto graphicsBuffer = binding.buffer;
677           auto vertexBuffer   = Uncast<TestGraphicsBuffer>(graphicsBuffer);
678           vertexBuffer->Bind();
679         }
680         break;
681       }
682       case CommandType::BIND_INDEX_BUFFER:
683       {
684         auto& indexBufferBinding = cmd.data.bindIndexBuffer;
685         if(indexBufferBinding.buffer)
686         {
687           auto buffer = Uncast<TestGraphicsBuffer>(indexBufferBinding.buffer);
688           buffer->Bind();
689         }
690         break;
691       }
692       case CommandType::BIND_UNIFORM_BUFFER:
693       {
694         if(currentPipeline)
695         {
696           auto& bindings = cmd.data.bindUniformBuffers;
697           auto  buffer   = bindings.standaloneUniformsBufferBinding;
698
699           // based on reflection, issue gl calls
700           buffer.buffer->BindAsUniformBuffer(static_cast<const TestGraphicsProgram*>(currentPipeline->programState.program), bindings.standaloneUniformsBufferBinding);
701         }
702         break;
703       }
704       case CommandType::BIND_SAMPLERS:
705       {
706         break;
707       }
708       case CommandType::BIND_PIPELINE:
709       {
710         currentPipeline = Uncast<TestGraphicsPipeline>(cmd.data.bindPipeline.pipeline);
711         BindPipeline(currentPipeline);
712         break;
713       }
714       case CommandType::DRAW_NATIVE:
715       {
716         auto info = &cmd.data.draw.drawNative.drawNativeInfo;
717
718         if(info->glesNativeInfo.eglSharedContextStoragePointer)
719         {
720           auto* anyContext = reinterpret_cast<std::any*>(info->glesNativeInfo.eglSharedContextStoragePointer);
721           *anyContext      = reinterpret_cast<void*>(0x12345678u);
722         }
723
724         CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
725         break;
726       }
727       case CommandType::DRAW:
728       {
729         if(currentPipeline)
730         {
731           if(cmd.data.draw.draw.instanceCount == 0)
732           {
733             mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology),
734                            cmd.data.draw.draw.firstVertex,
735                            cmd.data.draw.draw.vertexCount);
736           }
737           else
738           {
739             mGl.DrawArraysInstanced(GetTopology(currentPipeline->inputAssemblyState.topology),
740                                     cmd.data.draw.draw.firstVertex,
741                                     cmd.data.draw.draw.vertexCount,
742                                     cmd.data.draw.draw.instanceCount);
743           }
744         }
745         break;
746       }
747       case CommandType::DRAW_INDEXED:
748       {
749         if(currentPipeline)
750         {
751           if(cmd.data.draw.draw.instanceCount == 0)
752           {
753             mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
754                              static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
755                              GL_UNSIGNED_SHORT,
756                              reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
757           }
758           else
759           {
760             mGl.DrawElementsInstanced(GetTopology(currentPipeline->inputAssemblyState.topology),
761                                       static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
762                                       GL_UNSIGNED_SHORT,
763                                       reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex),
764                                       cmd.data.draw.drawIndexed.instanceCount);
765           }
766         }
767         break;
768       }
769       case CommandType::DRAW_INDEXED_INDIRECT:
770       {
771         if(currentPipeline)
772         {
773           mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
774                            static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
775                            GL_UNSIGNED_SHORT,
776                            reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
777         }
778         break;
779       }
780       case CommandType::SET_SCISSOR:
781       {
782         if(scissorEnabled)
783         {
784           auto& rect = cmd.data.scissor.region;
785           mGl.Scissor(rect.x, rect.y, rect.width, rect.height);
786         }
787         break;
788       }
789       case CommandType::SET_SCISSOR_TEST:
790       {
791         if(cmd.data.scissorTest.enable)
792         {
793           mGl.Enable(GL_SCISSOR_TEST);
794           scissorEnabled = true;
795         }
796         else
797         {
798           mGl.Disable(GL_SCISSOR_TEST);
799           scissorEnabled = false;
800         }
801         break;
802       }
803       case CommandType::SET_VIEWPORT_TEST:
804       {
805         break;
806       }
807       case CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
808       {
809         auto& rect = cmd.data.viewport.region;
810         mGl.Viewport(rect.x, rect.y, rect.width, rect.height);
811         break;
812       }
813
814       case CommandType::SET_COLOR_MASK:
815       {
816         // Set all channels to the same mask
817         const bool mask = cmd.data.colorMask.enabled;
818         mGl.ColorMask(mask, mask, mask, mask);
819         break;
820       }
821       case CommandType::CLEAR_STENCIL_BUFFER:
822       {
823         mGl.Clear(GL_STENCIL_BUFFER_BIT);
824         break;
825       }
826       case CommandType::CLEAR_DEPTH_BUFFER:
827       {
828         mGl.Clear(GL_DEPTH_BUFFER_BIT);
829         break;
830       }
831
832       case CommandType::SET_STENCIL_TEST_ENABLE:
833       {
834         if(cmd.data.stencilTest.enabled)
835         {
836           mGl.Enable(GL_STENCIL_TEST);
837         }
838         else
839         {
840           mGl.Disable(GL_STENCIL_TEST);
841         }
842         break;
843       }
844
845       case CommandType::SET_STENCIL_FUNC:
846       {
847         mGl.StencilFunc(GLCompareOp(cmd.data.stencilFunc.compareOp).op,
848                         cmd.data.stencilFunc.reference,
849                         cmd.data.stencilFunc.compareMask);
850         break;
851       }
852
853       case CommandType::SET_STENCIL_WRITE_MASK:
854       {
855         mGl.StencilMask(cmd.data.stencilWriteMask.mask);
856         break;
857       }
858       case CommandType::SET_STENCIL_OP:
859       {
860         mGl.StencilOp(GLStencilOp(cmd.data.stencilOp.failOp).op,
861                       GLStencilOp(cmd.data.stencilOp.depthFailOp).op,
862                       GLStencilOp(cmd.data.stencilOp.passOp).op);
863         break;
864       }
865
866       case CommandType::SET_DEPTH_COMPARE_OP:
867       {
868         mGl.DepthFunc(GLCompareOp(cmd.data.depth.compareOp).op);
869         break;
870       }
871       case CommandType::SET_DEPTH_TEST_ENABLE:
872       {
873         if(cmd.data.depth.testEnabled)
874         {
875           mGl.Enable(GL_DEPTH_TEST);
876         }
877         else
878         {
879           mGl.Disable(GL_DEPTH_TEST);
880         }
881         break;
882       }
883       case CommandType::SET_DEPTH_WRITE_ENABLE:
884       {
885         mGl.DepthMask(cmd.data.depth.writeEnabled);
886         break;
887       }
888
889       case CommandType::EXECUTE_COMMAND_BUFFERS:
890       {
891         // Process secondary command buffers
892         for(auto& buf : cmd.data.executeCommandBuffers.buffers)
893         {
894           ProcessCommandBuffer(*Uncast<TestGraphicsCommandBuffer>(buf));
895         }
896         break;
897       }
898       case CommandType::BEGIN_RENDER_PASS:
899       {
900         auto renderTarget = Uncast<TestGraphicsRenderTarget>(cmd.data.beginRenderPass.renderTarget);
901
902         if(renderTarget)
903         {
904           auto fb = renderTarget->mCreateInfo.framebuffer;
905           if(fb)
906           {
907             if(currentFramebuffer != fb)
908             {
909               currentFramebuffer = Uncast<TestGraphicsFramebuffer>(fb);
910               currentFramebuffer->Bind();
911             }
912           }
913           else
914           {
915             mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
916           }
917         }
918         else
919         {
920           mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
921         }
922
923         auto& clearValues = cmd.data.beginRenderPass.clearValues;
924         if(clearValues.size() > 0)
925         {
926           const auto renderPass = static_cast<TestGraphicsRenderPass*>(cmd.data.beginRenderPass.renderPass);
927           if(renderPass)
928           {
929             const auto& color0 = renderPass->attachments[0];
930             GLuint      mask   = 0;
931             if(color0.loadOp == Graphics::AttachmentLoadOp::CLEAR)
932             {
933               mask |= GL_COLOR_BUFFER_BIT;
934
935               // Set clear color (todo: cache it!)
936               // Something goes wrong here if Alpha mask is GL_TRUE
937               mGl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
938               mGl.ClearColor(clearValues[0].color.r,
939                              clearValues[0].color.g,
940                              clearValues[0].color.b,
941                              clearValues[0].color.a);
942             }
943
944             // check for depth stencil
945             if(renderPass->attachments.size() > 1)
946             {
947               const auto& depthStencil = renderPass->attachments.back();
948               if(depthStencil.loadOp == Graphics::AttachmentLoadOp::CLEAR)
949               {
950                 mGl.DepthMask(true);
951                 uint32_t depthClearColor = 0u;
952                 if(clearValues.size() == renderPass->attachments.size())
953                 {
954                   depthClearColor = clearValues.back().depthStencil.depth;
955                 }
956                 mGl.ClearDepthf(depthClearColor);
957                 mask |= GL_DEPTH_BUFFER_BIT;
958               }
959               if(depthStencil.stencilLoadOp == Graphics::AttachmentLoadOp::CLEAR)
960               {
961                 uint32_t stencilClearColor = 0u;
962                 if(clearValues.size() == renderPass->attachments.size())
963                 {
964                   stencilClearColor = clearValues.back().depthStencil.stencil;
965                 }
966                 mGl.ClearStencil(stencilClearColor);
967                 mGl.StencilMask(0xFF); // Clear all the bitplanes (assume 8)
968                 mask |= GL_STENCIL_BUFFER_BIT;
969               }
970             }
971
972             if(mask != 0)
973             {
974               // Test scissor area and RT size
975               const auto& area = cmd.data.beginRenderPass.renderArea;
976               if(area.x == 0 &&
977                  area.y == 0 &&
978                  renderTarget &&
979                  area.width == renderTarget->mCreateInfo.extent.width &&
980                  area.height == renderTarget->mCreateInfo.extent.height)
981               {
982                 mGl.Disable(GL_SCISSOR_TEST);
983                 mGl.Clear(mask);
984               }
985               else
986               {
987                 mGl.Enable(GL_SCISSOR_TEST);
988                 mGl.Scissor(cmd.data.beginRenderPass.renderArea.x, cmd.data.beginRenderPass.renderArea.y, cmd.data.beginRenderPass.renderArea.width, cmd.data.beginRenderPass.renderArea.height);
989                 mGl.Clear(mask);
990                 mGl.Disable(GL_SCISSOR_TEST);
991               }
992             }
993           }
994           else
995           {
996             DALI_ASSERT_DEBUG(0 && "BeginRenderPass has no render pass");
997           }
998         }
999         break;
1000       }
1001       case CommandType::END_RENDER_PASS:
1002       {
1003         if(cmd.data.endRenderPass.syncObject != nullptr)
1004         {
1005           auto syncObject = Uncast<TestGraphicsSyncObject>(cmd.data.endRenderPass.syncObject);
1006           syncObject->InitializeResource(); // create the sync object.
1007         }
1008         break;
1009       }
1010     }
1011   }
1012 }
1013
1014 void TestGraphicsController::BindPipeline(TestGraphicsPipeline* pipeline)
1015 {
1016   auto& vi = pipeline->vertexInputState;
1017   for(auto& attribute : vi.attributes)
1018   {
1019     mGl.EnableVertexAttribArray(attribute.location);
1020     uint32_t attributeOffset = attribute.offset;
1021     GLsizei  stride          = vi.bufferBindings[attribute.binding].stride;
1022
1023     auto rate = vi.bufferBindings[attribute.binding].inputRate;
1024
1025     mGl.VertexAttribPointer(attribute.location,
1026                             GetNumComponents(attribute.format),
1027                             GetGlType(attribute.format),
1028                             GL_FALSE, // Not normalized
1029                             stride,
1030                             reinterpret_cast<void*>(attributeOffset));
1031     if(rate == Graphics::VertexInputRate::PER_VERTEX)
1032     {
1033       mGl.VertexAttribDivisor(attribute.location, 0);
1034     }
1035     else if(rate == Graphics::VertexInputRate::PER_INSTANCE)
1036     {
1037       mGl.VertexAttribDivisor(attribute.location, 1);
1038     }
1039   }
1040
1041   // Cull face setup
1042   auto& rasterizationState = pipeline->rasterizationState;
1043   if(rasterizationState.cullMode == Graphics::CullMode::NONE)
1044   {
1045     mGl.Disable(GL_CULL_FACE);
1046   }
1047   else
1048   {
1049     mGl.Enable(GL_CULL_FACE);
1050     mGl.CullFace(GetCullFace(rasterizationState.cullMode));
1051   }
1052
1053   mGl.FrontFace(GetFrontFace(rasterizationState.frontFace));
1054
1055   // Blending setup
1056   auto& colorBlendState = pipeline->colorBlendState;
1057   if(colorBlendState.blendEnable)
1058   {
1059     mGl.Enable(GL_BLEND);
1060
1061     mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor),
1062                           GetBlendFactor(colorBlendState.dstColorBlendFactor),
1063                           GetBlendFactor(colorBlendState.srcAlphaBlendFactor),
1064                           GetBlendFactor(colorBlendState.dstAlphaBlendFactor));
1065     if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp)
1066     {
1067       mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp));
1068     }
1069     else
1070     {
1071       mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp));
1072     }
1073     mGl.BlendColor(colorBlendState.blendConstants[0],
1074                    colorBlendState.blendConstants[1],
1075                    colorBlendState.blendConstants[2],
1076                    colorBlendState.blendConstants[3]);
1077   }
1078   else
1079   {
1080     mGl.Disable(GL_BLEND);
1081   }
1082
1083   auto* program = static_cast<const TestGraphicsProgram*>(pipeline->programState.program);
1084   mGl.UseProgram(program->mImpl->mId);
1085 }
1086
1087 /**
1088  * @brief Presents render target
1089  * @param renderTarget render target to present
1090  */
1091 void TestGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget)
1092 {
1093   auto*                       rt = static_cast<const TestGraphicsRenderTarget*>(renderTarget);
1094   TraceCallStack::NamedParams namedParams;
1095   namedParams["renderTarget"] << std::hex << renderTarget;
1096   namedParams["surface"] << std::hex << rt->mCreateInfo.surface;
1097   mCallStack.PushCall("PresentRenderTarget", namedParams.str(), namedParams);
1098 }
1099
1100 /**
1101  * @brief Waits until the GPU is idle
1102  */
1103 void TestGraphicsController::WaitIdle()
1104 {
1105   mCallStack.PushCall("WaitIdle", "");
1106 }
1107
1108 /**
1109  * @brief Lifecycle pause event
1110  */
1111 void TestGraphicsController::Pause()
1112 {
1113   mCallStack.PushCall("Pause", "");
1114 }
1115
1116 /**
1117  * @brief Lifecycle resume event
1118  */
1119 void TestGraphicsController::Resume()
1120 {
1121   mCallStack.PushCall("Resume", "");
1122 }
1123
1124 void TestGraphicsController::Shutdown()
1125 {
1126   mCallStack.PushCall("Shutdown", "");
1127 }
1128
1129 void TestGraphicsController::Destroy()
1130 {
1131   mCallStack.PushCall("Destroy", "");
1132 }
1133
1134 void TestGraphicsController::UpdateTextures(const std::vector<Graphics::TextureUpdateInfo>&       updateInfoList,
1135                                             const std::vector<Graphics::TextureUpdateSourceInfo>& sourceList)
1136 {
1137   TraceCallStack::NamedParams namedParams;
1138   namedParams["updateInfoList"] << "[" << updateInfoList.size() << "]:";
1139   namedParams["sourceList"] << "[" << sourceList.size() << "]:";
1140
1141   mCallStack.PushCall("UpdateTextures", "", namedParams);
1142
1143   // Call either TexImage2D or TexSubImage2D
1144   for(unsigned int i = 0; i < updateInfoList.size(); ++i)
1145   {
1146     auto& updateInfo = updateInfoList[i];
1147     auto& source     = sourceList[i];
1148
1149     auto texture = static_cast<TestGraphicsTexture*>(updateInfo.dstTexture);
1150     texture->Bind(0); // Use first texture unit during resource update
1151     texture->Update(updateInfo, source);
1152   }
1153 }
1154
1155 void TestGraphicsController::GenerateTextureMipmaps(const Graphics::Texture& texture)
1156 {
1157   mCallStack.PushCall("GenerateTextureMipmaps", "");
1158
1159   auto gfxTexture = Uncast<TestGraphicsTexture>(&texture);
1160   mGl.BindTexture(gfxTexture->GetTarget(), 0);
1161   mGl.GenerateMipmap(gfxTexture->GetTarget());
1162 }
1163
1164 bool TestGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool enableStencil)
1165 {
1166   TraceCallStack::NamedParams namedParams;
1167   namedParams["enableDepth"] << (enableDepth ? "T" : "F");
1168   namedParams["enableStencil"] << (enableStencil ? "T" : "F");
1169   mCallStack.PushCall("EnableDepthStencilBuffer", "", namedParams);
1170   return false;
1171 }
1172
1173 void TestGraphicsController::RunGarbageCollector(size_t numberOfDiscardedRenderers)
1174 {
1175   TraceCallStack::NamedParams namedParams;
1176   namedParams["numberOfDiscardedRenderers"] << numberOfDiscardedRenderers;
1177   mCallStack.PushCall("RunGarbageCollector", "", namedParams);
1178 }
1179
1180 void TestGraphicsController::DiscardUnusedResources()
1181 {
1182   mCallStack.PushCall("DiscardUnusedResources", "");
1183 }
1184
1185 bool TestGraphicsController::IsDiscardQueueEmpty()
1186 {
1187   mCallStack.PushCall("IsDiscardQueueEmpty", "");
1188   return isDiscardQueueEmptyResult;
1189 }
1190
1191 /**
1192  * @brief Test if the graphics subsystem has resumed & should force a draw
1193  *
1194  * @return true if the graphics subsystem requires a re-draw
1195  */
1196 bool TestGraphicsController::IsDrawOnResumeRequired()
1197 {
1198   mCallStack.PushCall("IsDrawOnResumeRequired", "");
1199   return isDrawOnResumeRequiredResult;
1200 }
1201
1202 Graphics::UniquePtr<Graphics::Buffer> TestGraphicsController::CreateBuffer(const Graphics::BufferCreateInfo& createInfo, Graphics::UniquePtr<Graphics::Buffer>&& oldBuffer)
1203 {
1204   TraceCallStack::NamedParams namedParams;
1205   namedParams["usage"] << "0x" << std::hex << createInfo.usage;
1206   namedParams["propertiesFlags"] << createInfo.propertiesFlags;
1207   namedParams["size"] << createInfo.size;
1208   mCallStack.PushCall("CreateBuffer", namedParams.str(), namedParams);
1209
1210   auto ptr = Graphics::MakeUnique<TestGraphicsBuffer, TestGraphicsDeleter<TestGraphicsBuffer>>(createInfo, *this, mGl, mCallStack);
1211   mAllocatedBuffers.push_back(ptr.get());
1212   return ptr;
1213 }
1214
1215 void TestGraphicsController::DiscardBuffer(TestGraphicsBuffer* buffer)
1216 {
1217   auto iter = std::find(mAllocatedBuffers.begin(), mAllocatedBuffers.end(), buffer);
1218   if(iter != mAllocatedBuffers.end())
1219   {
1220     mAllocatedBuffers.erase(iter);
1221   }
1222   delete buffer;
1223 }
1224
1225 Graphics::UniquePtr<Graphics::CommandBuffer> TestGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, Graphics::UniquePtr<Graphics::CommandBuffer>&& oldCommandBuffer)
1226 {
1227   std::ostringstream oss;
1228   oss << "commandBufferCreateInfo:" << commandBufferCreateInfo;
1229   mCallStack.PushCall("CreateCommandBuffer", oss.str());
1230   return Graphics::MakeUnique<TestGraphicsCommandBuffer>(mCommandBufferCallStack, mGl);
1231 }
1232
1233 Graphics::UniquePtr<Graphics::RenderPass> TestGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<Graphics::RenderPass>&& oldRenderPass)
1234 {
1235   mCallStack.PushCall("CreateRenderPass", "");
1236   return Graphics::MakeUnique<TestGraphicsRenderPass>(mGl, renderPassCreateInfo);
1237 }
1238
1239 Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::CreateTexture(const Graphics::TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Graphics::Texture>&& oldTexture)
1240 {
1241   TraceCallStack::NamedParams namedParams;
1242   namedParams["textureCreateInfo"] << textureCreateInfo;
1243   mCallStack.PushCall("CreateTexture", namedParams.str(), namedParams);
1244
1245   return Graphics::MakeUnique<TestGraphicsTexture>(mGl, textureCreateInfo);
1246 }
1247
1248 Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebuffer(
1249   const Graphics::FramebufferCreateInfo&       createInfo,
1250   Graphics::UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
1251 {
1252   TraceCallStack::NamedParams namedParams;
1253   namedParams["framebufferCreateInfo"] << createInfo;
1254   mCallStack.PushCall("Controller::CreateFramebuffer", namedParams.str(), namedParams);
1255
1256   return Graphics::MakeUnique<TestGraphicsFramebuffer>(mFrameBufferCallStack, mGl, createInfo);
1257 }
1258
1259 Graphics::UniquePtr<Graphics::Pipeline> TestGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
1260 {
1261   mCallStack.PushCall("CreatePipeline", "");
1262   return std::make_unique<TestGraphicsPipeline>(mGl, pipelineCreateInfo);
1263 }
1264
1265 Graphics::UniquePtr<Graphics::Program> TestGraphicsController::CreateProgram(const Graphics::ProgramCreateInfo& programCreateInfo, Graphics::UniquePtr<Graphics::Program>&& oldProgram)
1266 {
1267   mCallStack.PushCall("CreateProgram", "");
1268
1269   for(auto cacheEntry : mProgramCache)
1270   {
1271     bool found = true;
1272     for(auto& shader : *(programCreateInfo.shaderState))
1273     {
1274       auto                 graphicsShader = Uncast<TestGraphicsShader>(shader.shader);
1275       std::vector<uint8_t> source;
1276       source.resize(graphicsShader->mCreateInfo.sourceSize);
1277       memcpy(&source[0], graphicsShader->mCreateInfo.sourceData, graphicsShader->mCreateInfo.sourceSize);
1278
1279       if(!std::equal(source.begin(), source.end(), cacheEntry.shaders[shader.pipelineStage].begin(), cacheEntry.shaders[shader.pipelineStage].end()))
1280       {
1281         found = false;
1282         break;
1283       }
1284     }
1285     if(found)
1286     {
1287       return Graphics::MakeUnique<TestGraphicsProgram>(cacheEntry.programImpl);
1288     }
1289   }
1290
1291   mProgramCache.emplace_back();
1292   mProgramCache.back().programImpl = new TestGraphicsProgramImpl(*this, mGl, programCreateInfo, mVertexFormats, mCustomUniforms, mCustomUniformBlocks);
1293
1294   for(auto& shader : *(programCreateInfo.shaderState))
1295   {
1296     auto graphicsShader = Uncast<TestGraphicsShader>(shader.shader);
1297     mProgramCache.back().shaders[shader.pipelineStage].resize(graphicsShader->mCreateInfo.sourceSize);
1298     memcpy(&mProgramCache.back().shaders[shader.pipelineStage][0], graphicsShader->mCreateInfo.sourceData, graphicsShader->mCreateInfo.sourceSize);
1299   }
1300   return Graphics::MakeUnique<TestGraphicsProgram>(mProgramCache.back().programImpl);
1301 }
1302
1303 Graphics::UniquePtr<Graphics::Shader> TestGraphicsController::CreateShader(const Graphics::ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Graphics::Shader>&& oldShader)
1304 {
1305   mCallStack.PushCall("CreateShader", "");
1306   return Graphics::MakeUnique<TestGraphicsShader>(mGl, shaderCreateInfo);
1307 }
1308
1309 Graphics::UniquePtr<Graphics::Sampler> TestGraphicsController::CreateSampler(const Graphics::SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Graphics::Sampler>&& oldSampler)
1310 {
1311   TraceCallStack::NamedParams namedParams;
1312   namedParams["samplerCreateInfo"] << samplerCreateInfo;
1313   mCallStack.PushCall("CreateSampler", namedParams.str(), namedParams);
1314
1315   return Graphics::MakeUnique<TestGraphicsSampler>(mGl, samplerCreateInfo);
1316 }
1317
1318 Graphics::UniquePtr<Graphics::RenderTarget> TestGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
1319 {
1320   TraceCallStack::NamedParams namedParams;
1321   namedParams["surface"] << std::hex << renderTargetCreateInfo.surface;
1322   mCallStack.PushCall("CreateRenderTarget", namedParams.str(), namedParams);
1323
1324   return Graphics::MakeUnique<TestGraphicsRenderTarget>(mGl, renderTargetCreateInfo);
1325 }
1326
1327 Graphics::UniquePtr<Graphics::SyncObject> TestGraphicsController::CreateSyncObject(
1328   const Graphics::SyncObjectCreateInfo&       syncObjectCreateInfo,
1329   Graphics::UniquePtr<Graphics::SyncObject>&& oldSyncObject)
1330 {
1331   mCallStack.PushCall("CreateSyncObject", "");
1332   return Graphics::MakeUnique<TestGraphicsSyncObject>(mGraphicsSyncImpl, syncObjectCreateInfo);
1333 }
1334
1335 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapBufferRange(const Graphics::MapBufferInfo& mapInfo)
1336 {
1337   mCallStack.PushCall("MapBufferRange", "");
1338
1339   auto buffer = static_cast<TestGraphicsBuffer*>(mapInfo.buffer);
1340   buffer->memory.resize(mapInfo.offset + mapInfo.size); // For initial testing, allow writes past capacity
1341
1342   return std::make_unique<TestGraphicsMemory>(mCallStack, *buffer, mapInfo.offset, mapInfo.size);
1343 }
1344
1345 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapTextureRange(const Graphics::MapTextureInfo& mapInfo)
1346 {
1347   mCallStack.PushCall("MapTextureRange", "");
1348   return nullptr;
1349 }
1350
1351 void TestGraphicsController::UnmapMemory(Graphics::UniquePtr<Graphics::Memory> memory)
1352 {
1353   mCallStack.PushCall("UnmapMemory", "");
1354 }
1355
1356 Graphics::MemoryRequirements TestGraphicsController::GetTextureMemoryRequirements(Graphics::Texture& texture) const
1357 {
1358   mCallStack.PushCall("GetTextureMemoryRequirements", "");
1359   return Graphics::MemoryRequirements{};
1360 }
1361
1362 Graphics::MemoryRequirements TestGraphicsController::GetBufferMemoryRequirements(Graphics::Buffer& buffer) const
1363 {
1364   static GLint uniformAlign{0};
1365
1366   Graphics::MemoryRequirements reqs{};
1367   mCallStack.PushCall("GetBufferMemoryRequirements", "");
1368
1369   auto gfxBuffer = Uncast<TestGraphicsBuffer>(&buffer);
1370   if(gfxBuffer->mCreateInfo.usage & (0 | Graphics::BufferUsage::UNIFORM_BUFFER))
1371   {
1372     if(!uniformAlign)
1373     {
1374       // Throw off the shackles of constness
1375       auto& gl = *const_cast<TestGlAbstraction*>(&mGl);
1376       gl.GetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniformAlign);
1377     }
1378     reqs.size      = gfxBuffer->mCreateInfo.size;
1379     reqs.alignment = uint32_t(uniformAlign);
1380   }
1381   return reqs;
1382 }
1383
1384 Graphics::TextureProperties TestGraphicsController::GetTextureProperties(const Graphics::Texture& texture)
1385 {
1386   static Graphics::TextureProperties textureProperties{};
1387   mCallStack.PushCall("GetTextureProperties", "");
1388
1389   return textureProperties;
1390 }
1391
1392 const Graphics::Reflection& TestGraphicsController::GetProgramReflection(const Graphics::Program& program)
1393 {
1394   mCallStack.PushCall("GetProgramReflection", "");
1395
1396   return static_cast<const TestGraphicsProgram*>(&program)->GetReflection();
1397 }
1398
1399 bool TestGraphicsController::PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const
1400 {
1401   mCallStack.PushCall("PipelineEquals", "");
1402   return false;
1403 }
1404
1405 bool TestGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
1406 {
1407   mCallStack.PushCall("GetProgramParameter", "");
1408   auto graphicsProgram = Uncast<TestGraphicsProgram>(&program);
1409   return graphicsProgram->GetParameter(parameterId, outData);
1410 }
1411
1412 Graphics::Texture* TestGraphicsController::CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo)
1413 {
1414   Graphics::Texture*                     ret = nullptr;
1415   Graphics::UniquePtr<Graphics::Texture> texture;
1416   TraceCallStack::NamedParams            namedParams;
1417   namedParams["resourceId"] << resourceId;
1418
1419   auto iter = mTextureUploadBindMapper.find(resourceId);
1420   DALI_ASSERT_ALWAYS(iter == mTextureUploadBindMapper.end());
1421
1422   // Create new graphics texture.
1423   texture = CreateTexture(createInfo, std::move(texture));
1424   ret     = texture.get();
1425
1426   mTextureUploadBindMapper.insert(std::make_pair(resourceId, std::move(texture)));
1427
1428   mCallStack.PushCall("CreateTextureByResourceId", "", namedParams);
1429   return ret;
1430 }
1431
1432 void TestGraphicsController::DiscardTextureFromResourceId(uint32_t resourceId)
1433 {
1434   TraceCallStack::NamedParams namedParams;
1435   namedParams["resourceId"] << resourceId;
1436
1437   mTextureUploadBindMapper.erase(resourceId);
1438
1439   mCallStack.PushCall("DiscardTextureFromResourceId", "", namedParams);
1440 }
1441
1442 Graphics::Texture* TestGraphicsController::GetTextureFromResourceId(uint32_t resourceId)
1443 {
1444   TraceCallStack::NamedParams namedParams;
1445   namedParams["resourceId"] << resourceId;
1446
1447   Graphics::Texture* ret = nullptr;
1448
1449   auto iter = mTextureUploadBindMapper.find(resourceId);
1450   if(iter != mTextureUploadBindMapper.end())
1451   {
1452     ret = iter->second.get();
1453   }
1454
1455   mCallStack.PushCall("GetTextureFromResourceId", "", namedParams);
1456
1457   return ret;
1458 }
1459
1460 Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId)
1461 {
1462   TraceCallStack::NamedParams namedParams;
1463   namedParams["resourceId"] << resourceId;
1464
1465   Graphics::UniquePtr<Graphics::Texture> texture;
1466
1467   auto iter = mTextureUploadBindMapper.find(resourceId);
1468   if(iter != mTextureUploadBindMapper.end())
1469   {
1470     texture = std::move(iter->second);
1471     mTextureUploadBindMapper.erase(iter);
1472   }
1473
1474   mCallStack.PushCall("ReleaseTextureFromResourceId", "", namedParams);
1475
1476   return texture;
1477 }
1478
1479 } // namespace Dali