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