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