Updated test harness
[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
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
383       // @todo Add advanced blend equations
384   }
385   return op;
386 }
387
388
389 class TestGraphicsMemory : public Graphics::Memory
390 {
391 public:
392   TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize)
393   : mCallStack(callStack),
394     mBuffer(buffer),
395     mMappedOffset(mappedOffset),
396     mMappedSize(mappedSize),
397     mLockedOffset(0u),
398     mLockedSize(0u)
399   {
400   }
401
402   void* LockRegion(uint32_t offset, uint32_t size) override
403   {
404     std::ostringstream o;
405     o << offset << ", " << size;
406     mCallStack.PushCall("Memory::LockRegion", o.str());
407
408     if(offset > mMappedOffset + mMappedSize ||
409        size + offset > mMappedOffset + mMappedSize)
410     {
411       fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds");
412       mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing
413     }
414     mLockedOffset = offset;
415     mLockedSize   = size;
416     return &mBuffer.memory[mMappedOffset + offset];
417   }
418
419   void Unlock(bool flush) override
420   {
421     mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush"));
422     if(flush)
423     {
424       Flush();
425     }
426   }
427
428   void Flush() override
429   {
430     mCallStack.PushCall("Memory::Flush", "");
431     mBuffer.Bind();
432     mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize);
433     mBuffer.Unbind();
434   }
435
436   TraceCallStack&     mCallStack;
437   TestGraphicsBuffer& mBuffer;
438   uint32_t            mMappedOffset;
439   uint32_t            mMappedSize;
440   uint32_t            mLockedOffset;
441   uint32_t            mLockedSize;
442 };
443
444 TestGraphicsController::TestGraphicsController()
445 : mCallStack(true, "TestGraphicsController."),
446   mCommandBufferCallStack(true, "TestCommandBuffer."),
447   mFrameBufferCallStack(true, "TestFrameBuffer.")
448 {
449   mCallStack.Enable(true);
450   mCommandBufferCallStack.Enable(true);
451   auto& trace = mGl.GetTextureTrace();
452   trace.Enable(true);
453   trace.EnableLogging(true);
454 }
455
456
457 void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo)
458 {
459   TraceCallStack::NamedParams namedParams;
460   namedParams["submitInfo"] << "cmdBuffer[" << submitInfo.cmdBuffer.size()
461                             << "], flags:" << std::hex << submitInfo.flags;
462
463   mCallStack.PushCall("SubmitCommandBuffers", "", namedParams);
464
465   mSubmitStack.emplace_back(submitInfo);
466
467   for(auto& graphicsCommandBuffer : submitInfo.cmdBuffer)
468   {
469     auto commandBuffer = Uncast<TestGraphicsCommandBuffer>(graphicsCommandBuffer);
470     ProcessCommandBuffer(*commandBuffer);
471   }
472 }
473
474 void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& commandBuffer)
475 {
476   bool                     scissorEnabled = false;
477   TestGraphicsFramebuffer* currentFramebuffer{nullptr};
478   TestGraphicsPipeline*    currentPipeline{nullptr};
479
480   for(auto& cmd : commandBuffer.GetCommands())
481   {
482     // process command
483     switch(cmd.type)
484     {
485       case CommandType::FLUSH:
486       {
487         // Nothing to do here
488         break;
489       }
490       case CommandType::BIND_TEXTURES:
491       {
492         for(auto& binding : cmd.data.bindTextures.textureBindings)
493         {
494           if(binding.texture)
495           {
496             auto texture = Uncast<TestGraphicsTexture>(binding.texture);
497             texture->Bind(binding.binding);
498
499             if(binding.sampler)
500             {
501               auto sampler = Uncast<TestGraphicsSampler>(binding.sampler);
502               if(sampler)
503               {
504                 sampler->Apply(texture->GetTarget());
505               }
506             }
507
508             texture->Prepare(); // Ensure native texture is ready
509           }
510         }
511         break;
512       }
513       case CommandType::BIND_VERTEX_BUFFERS:
514       {
515         for(auto& binding : cmd.data.bindVertexBuffers.vertexBufferBindings)
516         {
517           auto graphicsBuffer = binding.buffer;
518           auto vertexBuffer   = Uncast<TestGraphicsBuffer>(graphicsBuffer);
519           vertexBuffer->Bind();
520         }
521         break;
522       }
523       case CommandType::BIND_INDEX_BUFFER:
524       {
525         auto& indexBufferBinding = cmd.data.bindIndexBuffer;
526         if(indexBufferBinding.buffer)
527         {
528           auto buffer = Uncast<TestGraphicsBuffer>(indexBufferBinding.buffer);
529           buffer->Bind();
530         }
531         break;
532       }
533       case CommandType::BIND_UNIFORM_BUFFER:
534       {
535         auto& bindings = cmd.data.bindUniformBuffers;
536         auto  buffer   = bindings.standaloneUniformsBufferBinding;
537
538         // based on reflection, issue gl calls
539         buffer.buffer->BindAsUniformBuffer(static_cast<const TestGraphicsProgram*>(currentPipeline->programState.program));
540         break;
541       }
542       case CommandType::BIND_SAMPLERS:
543       {
544         break;
545       }
546       case CommandType::BIND_PIPELINE:
547       {
548         currentPipeline = Uncast<TestGraphicsPipeline>(cmd.data.bindPipeline.pipeline);
549
550         // Bind framebuffer if different. @todo Move to RenderPass
551         auto framebuffer = currentPipeline->framebufferState.framebuffer;
552         if(framebuffer && framebuffer != currentFramebuffer)
553         {
554           auto graphicsFramebuffer = Uncast<TestGraphicsFramebuffer>(framebuffer);
555           graphicsFramebuffer->Bind();
556         }
557         else
558         {
559           if(currentFramebuffer)
560             currentFramebuffer->Bind();
561           else
562             mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
563         }
564         BindPipeline(currentPipeline);
565         break;
566       }
567       case CommandType::DRAW:
568       {
569         mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology),
570                        0,
571                        cmd.data.draw.draw.vertexCount);
572         break;
573       }
574       case CommandType::DRAW_INDEXED:
575       {
576         mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
577                          static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
578                          GL_UNSIGNED_SHORT,
579                          reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
580         break;
581       }
582       case CommandType::DRAW_INDEXED_INDIRECT:
583       {
584         mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
585                          static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
586                          GL_UNSIGNED_SHORT,
587                          reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
588         break;
589       }
590       case CommandType::SET_SCISSOR:
591       {
592         if(scissorEnabled)
593         {
594           auto& rect = cmd.data.scissor.region;
595           mGl.Scissor(rect.x, rect.y, rect.width, rect.height);
596         }
597         break;
598       }
599       case CommandType::SET_SCISSOR_TEST:
600       {
601         if(cmd.data.scissorTest.enable)
602         {
603           mGl.Enable(GL_SCISSOR_TEST);
604           scissorEnabled = true;
605         }
606         else
607         {
608           mGl.Disable(GL_SCISSOR_TEST);
609           scissorEnabled = false;
610         }
611         break;
612       }
613       case CommandType::SET_VIEWPORT_TEST:
614       {
615         break;
616       }
617       case CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
618       {
619         auto& rect = cmd.data.viewport.region;
620         mGl.Viewport(rect.x, rect.y, rect.width, rect.height);
621         break;
622       }
623       case CommandType::EXECUTE_COMMAND_BUFFERS:
624       {
625         // Process secondary command buffers
626         for(auto& buf : cmd.data.executeCommandBuffers.buffers)
627         {
628           ProcessCommandBuffer(*static_cast<TestGraphicsCommandBuffer*>(buf));
629         }
630         break;
631       }
632       case CommandType::BEGIN_RENDER_PASS:
633       {
634         auto renderTarget = Uncast<TestGraphicsRenderTarget>(cmd.data.beginRenderPass.renderTarget);
635
636         if(renderTarget)
637         {
638           auto fb = renderTarget->mCreateInfo.framebuffer;
639           if(fb)
640           {
641             if(currentFramebuffer != fb)
642             {
643               currentFramebuffer = Uncast<TestGraphicsFramebuffer>(fb);
644               currentFramebuffer->Bind();
645             }
646           }
647           else
648           {
649             mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
650           }
651         }
652         else
653         {
654           mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
655         }
656
657         auto& clearValues = cmd.data.beginRenderPass.clearValues;
658         if(clearValues.size() > 0)
659         {
660           const auto renderPass = static_cast<TestGraphicsRenderPass*>(cmd.data.beginRenderPass.renderPass);
661           if(renderPass)
662           {
663             const auto& color0 = renderPass->attachments[0];
664             GLuint      mask   = 0;
665             if(color0.loadOp == Graphics::AttachmentLoadOp::CLEAR)
666             {
667               mask |= GL_COLOR_BUFFER_BIT;
668
669               // Set clear color (todo: cache it!)
670               // Something goes wrong here if Alpha mask is GL_TRUE
671               mGl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
672               mGl.ClearColor(clearValues[0].color.r,
673                              clearValues[0].color.g,
674                              clearValues[0].color.b,
675                              clearValues[0].color.a);
676             }
677
678             // check for depth stencil
679             if(renderPass->attachments.size() > 1)
680             {
681               const auto& depthStencil = renderPass->attachments.back();
682               if(depthStencil.loadOp == Graphics::AttachmentLoadOp::CLEAR)
683               {
684                 mask |= GL_DEPTH_BUFFER_BIT;
685               }
686               if(depthStencil.stencilLoadOp == Graphics::AttachmentLoadOp::CLEAR)
687               {
688                 mask |= GL_STENCIL_BUFFER_BIT;
689               }
690             }
691
692             if(mask != 0)
693             {
694               // Test scissor area and RT size
695               const auto& area = cmd.data.beginRenderPass.renderArea;
696               if( area.x == 0 &&
697               area.y == 0 &&
698               area.width == renderTarget->mCreateInfo.extent.width &&
699               area.height == renderTarget->mCreateInfo.extent.height )
700               {
701                 mGl.Disable(GL_SCISSOR_TEST);
702                 mGl.Clear(mask);
703               }
704               else
705               {
706                 mGl.Enable(GL_SCISSOR_TEST);
707                 mGl.Scissor(cmd.data.beginRenderPass.renderArea.x, cmd.data.beginRenderPass.renderArea.y,
708                             cmd.data.beginRenderPass.renderArea.width, cmd.data.beginRenderPass.renderArea.height);
709                 mGl.Clear(mask);
710                 mGl.Disable(GL_SCISSOR_TEST);
711               }
712             }
713           }
714           else
715           {
716             DALI_ASSERT_DEBUG(0 && "BeginRenderPass has no render pass");
717           }
718         }
719         break;
720       }
721       case CommandType::END_RENDER_PASS:
722       {
723         break;
724       }
725     }
726   }
727 }
728
729 void TestGraphicsController::BindPipeline(TestGraphicsPipeline* pipeline)
730 {
731   auto& vi = pipeline->vertexInputState;
732   for(auto& attribute : vi.attributes)
733   {
734     mGl.EnableVertexAttribArray(attribute.location);
735     uint32_t attributeOffset = attribute.offset;
736     GLsizei  stride          = vi.bufferBindings[attribute.binding].stride;
737
738     mGl.VertexAttribPointer(attribute.location,
739                             GetNumComponents(attribute.format),
740                             GetGlType(attribute.format),
741                             GL_FALSE, // Not normalized
742                             stride,
743                             reinterpret_cast<void*>(attributeOffset));
744   }
745
746   // Cull face setup
747   auto& rasterizationState = pipeline->rasterizationState;
748   if(rasterizationState.cullMode == Graphics::CullMode::NONE)
749   {
750     mGl.Disable(GL_CULL_FACE);
751   }
752   else
753   {
754     mGl.Enable(GL_CULL_FACE);
755     mGl.CullFace(GetCullFace(rasterizationState.cullMode));
756   }
757
758   mGl.FrontFace(GetFrontFace(rasterizationState.frontFace));
759
760   // Blending setup
761   auto& colorBlendState = pipeline->colorBlendState;
762   if(colorBlendState.blendEnable)
763   {
764     mGl.Enable(GL_BLEND);
765
766     mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor),
767                           GetBlendFactor(colorBlendState.dstColorBlendFactor),
768                           GetBlendFactor(colorBlendState.srcAlphaBlendFactor),
769                           GetBlendFactor(colorBlendState.dstAlphaBlendFactor));
770     if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp)
771     {
772       mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp));
773     }
774     else
775     {
776       mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp));
777     }
778     mGl.BlendColor(colorBlendState.blendConstants[0],
779                    colorBlendState.blendConstants[1],
780                    colorBlendState.blendConstants[2],
781                    colorBlendState.blendConstants[3]);
782   }
783   else
784   {
785     mGl.Disable(GL_BLEND);
786   }
787 }
788
789 /**
790  * @brief Presents render target
791  * @param renderTarget render target to present
792  */
793 void TestGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget)
794 {
795   TraceCallStack::NamedParams namedParams;
796   namedParams["renderTarget"] << std::hex << renderTarget;
797   mCallStack.PushCall("PresentRenderTarget", "", namedParams);
798 }
799
800 /**
801  * @brief Waits until the GPU is idle
802  */
803 void TestGraphicsController::WaitIdle()
804 {
805   mCallStack.PushCall("WaitIdle", "");
806 }
807
808 /**
809  * @brief Lifecycle pause event
810  */
811 void TestGraphicsController::Pause()
812 {
813   mCallStack.PushCall("Pause", "");
814 }
815
816 /**
817  * @brief Lifecycle resume event
818  */
819 void TestGraphicsController::Resume()
820 {
821   mCallStack.PushCall("Resume", "");
822 }
823
824 void TestGraphicsController::Shutdown()
825 {
826   mCallStack.PushCall("Shutdown", "");
827 }
828
829 void TestGraphicsController::Destroy()
830 {
831   mCallStack.PushCall("Destroy", "");
832 }
833
834 void TestGraphicsController::UpdateTextures(const std::vector<Graphics::TextureUpdateInfo>&       updateInfoList,
835                                             const std::vector<Graphics::TextureUpdateSourceInfo>& sourceList)
836 {
837   TraceCallStack::NamedParams namedParams;
838   namedParams["updateInfoList"] << "[" << updateInfoList.size() << "]:";
839   namedParams["sourceList"] << "[" << sourceList.size() << "]:";
840
841   mCallStack.PushCall("UpdateTextures", "", namedParams);
842
843   // Call either TexImage2D or TexSubImage2D
844   for(unsigned int i = 0; i < updateInfoList.size(); ++i)
845   {
846     auto& updateInfo = updateInfoList[i];
847     auto& source     = sourceList[i];
848
849     auto texture = static_cast<TestGraphicsTexture*>(updateInfo.dstTexture);
850     texture->Bind(0); // Use first texture unit during resource update
851     texture->Update(updateInfo, source);
852   }
853 }
854
855 bool TestGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool enableStencil)
856 {
857   TraceCallStack::NamedParams namedParams;
858   namedParams["enableDepth"] << (enableDepth ? "T" : "F");
859   namedParams["enableStencil"] << (enableStencil ? "T" : "F");
860   mCallStack.PushCall("EnableDepthStencilBuffer", "", namedParams);
861   return false;
862 }
863
864 void TestGraphicsController::RunGarbageCollector(size_t numberOfDiscardedRenderers)
865 {
866   TraceCallStack::NamedParams namedParams;
867   namedParams["numberOfDiscardedRenderers"] << numberOfDiscardedRenderers;
868   mCallStack.PushCall("RunGarbageCollector", "", namedParams);
869 }
870
871 void TestGraphicsController::DiscardUnusedResources()
872 {
873   mCallStack.PushCall("DiscardUnusedResources", "");
874 }
875
876 bool TestGraphicsController::IsDiscardQueueEmpty()
877 {
878   mCallStack.PushCall("IsDiscardQueueEmpty", "");
879   return isDiscardQueueEmptyResult;
880 }
881
882 /**
883  * @brief Test if the graphics subsystem has resumed & should force a draw
884  *
885  * @return true if the graphics subsystem requires a re-draw
886  */
887 bool TestGraphicsController::IsDrawOnResumeRequired()
888 {
889   mCallStack.PushCall("IsDrawOnResumeRequired", "");
890   return isDrawOnResumeRequiredResult;
891 }
892
893 Graphics::UniquePtr<Graphics::Buffer> TestGraphicsController::CreateBuffer(const Graphics::BufferCreateInfo& createInfo, Graphics::UniquePtr<Graphics::Buffer>&& oldBuffer)
894 {
895   std::ostringstream oss;
896   oss << "bufferCreateInfo:" << createInfo;
897   mCallStack.PushCall("CreateBuffer", oss.str());
898   return Graphics::MakeUnique<TestGraphicsBuffer>(mCallStack, mGl, createInfo.size, createInfo.usage);
899 }
900
901 Graphics::UniquePtr<Graphics::CommandBuffer> TestGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, Graphics::UniquePtr<Graphics::CommandBuffer>&& oldCommandBuffer)
902 {
903   std::ostringstream oss;
904   oss << "commandBufferCreateInfo:" << commandBufferCreateInfo;
905   mCallStack.PushCall("CreateCommandBuffer", oss.str());
906   return Graphics::MakeUnique<TestGraphicsCommandBuffer>(mCommandBufferCallStack, mGl);
907 }
908
909 Graphics::UniquePtr<Graphics::RenderPass> TestGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<Graphics::RenderPass>&& oldRenderPass)
910 {
911   mCallStack.PushCall("CreateRenderPass", "");
912   return Graphics::MakeUnique<TestGraphicsRenderPass>(mGl, renderPassCreateInfo);
913 }
914
915 Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::CreateTexture(const Graphics::TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Graphics::Texture>&& oldTexture)
916 {
917   TraceCallStack::NamedParams namedParams;
918   namedParams["textureCreateInfo"] << textureCreateInfo;
919   mCallStack.PushCall("CreateTexture", namedParams.str(), namedParams);
920
921   return Graphics::MakeUnique<TestGraphicsTexture>(mGl, textureCreateInfo);
922 }
923
924 Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebuffer(
925   const Graphics::FramebufferCreateInfo&       createInfo,
926   Graphics::UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
927 {
928   TraceCallStack::NamedParams namedParams;
929   namedParams["framebufferCreateInfo"] << createInfo;
930   mCallStack.PushCall("Controller::CreateFramebuffer", namedParams.str(), namedParams);
931
932   return Graphics::MakeUnique<TestGraphicsFramebuffer>(mFrameBufferCallStack, mGl, createInfo);
933 }
934
935 Graphics::UniquePtr<Graphics::Pipeline> TestGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
936 {
937   mCallStack.PushCall("CreatePipeline", "");
938   return std::make_unique<TestGraphicsPipeline>(mGl, pipelineCreateInfo);
939 }
940
941 Graphics::UniquePtr<Graphics::Program> TestGraphicsController::CreateProgram(const Graphics::ProgramCreateInfo& programCreateInfo, Graphics::UniquePtr<Graphics::Program>&& oldProgram)
942 {
943   mCallStack.PushCall("CreateProgram", "");
944
945   for(auto cacheEntry : mProgramCache)
946   {
947     bool found = true;
948     for(auto& shader : *(programCreateInfo.shaderState))
949     {
950       auto                 graphicsShader = Uncast<TestGraphicsShader>(shader.shader);
951       std::vector<uint8_t> source;
952       source.resize(graphicsShader->mCreateInfo.sourceSize);
953       memcpy(&source[0], graphicsShader->mCreateInfo.sourceData, graphicsShader->mCreateInfo.sourceSize);
954
955       if(!std::equal(source.begin(), source.end(), cacheEntry.shaders[shader.pipelineStage].begin()))
956       {
957         found = false;
958         break;
959       }
960     }
961     if(found)
962     {
963       return Graphics::MakeUnique<TestGraphicsProgram>(cacheEntry.programImpl);
964     }
965   }
966
967   mProgramCache.emplace_back();
968   mProgramCache.back().programImpl = new TestGraphicsProgramImpl(mGl, programCreateInfo, mVertexFormats, mCustomUniforms);
969   for(auto& shader : *(programCreateInfo.shaderState))
970   {
971     auto graphicsShader = Uncast<TestGraphicsShader>(shader.shader);
972     mProgramCache.back().shaders[shader.pipelineStage].resize(graphicsShader->mCreateInfo.sourceSize);
973     memcpy(&mProgramCache.back().shaders[shader.pipelineStage][0], graphicsShader->mCreateInfo.sourceData, graphicsShader->mCreateInfo.sourceSize);
974   }
975   return Graphics::MakeUnique<TestGraphicsProgram>(mProgramCache.back().programImpl);
976 }
977
978 Graphics::UniquePtr<Graphics::Shader> TestGraphicsController::CreateShader(const Graphics::ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Graphics::Shader>&& oldShader)
979 {
980   mCallStack.PushCall("CreateShader", "");
981   return Graphics::MakeUnique<TestGraphicsShader>(mGl, shaderCreateInfo);
982 }
983
984 Graphics::UniquePtr<Graphics::Sampler> TestGraphicsController::CreateSampler(const Graphics::SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Graphics::Sampler>&& oldSampler)
985 {
986   TraceCallStack::NamedParams namedParams;
987   namedParams["samplerCreateInfo"] << samplerCreateInfo;
988   mCallStack.PushCall("CreateSampler", namedParams.str(), namedParams);
989
990   return Graphics::MakeUnique<TestGraphicsSampler>(mGl, samplerCreateInfo);
991 }
992
993 Graphics::UniquePtr<Graphics::RenderTarget> TestGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
994 {
995   mCallStack.PushCall("CreateRenderTarget", "");
996   return Graphics::MakeUnique<TestGraphicsRenderTarget>(mGl, renderTargetCreateInfo);
997 }
998
999 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapBufferRange(const Graphics::MapBufferInfo& mapInfo)
1000 {
1001   mCallStack.PushCall("MapBufferRange", "");
1002
1003   auto buffer = static_cast<TestGraphicsBuffer*>(mapInfo.buffer);
1004   buffer->memory.resize(mapInfo.offset + mapInfo.size); // For initial testing, allow writes past capacity
1005
1006   return std::make_unique<TestGraphicsMemory>(mCallStack, *buffer, mapInfo.offset, mapInfo.size);
1007 }
1008
1009 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapTextureRange(const Graphics::MapTextureInfo& mapInfo)
1010 {
1011   mCallStack.PushCall("MapTextureRange", "");
1012   return nullptr;
1013 }
1014
1015 void TestGraphicsController::UnmapMemory(Graphics::UniquePtr<Graphics::Memory> memory)
1016 {
1017   mCallStack.PushCall("UnmapMemory", "");
1018 }
1019
1020 Graphics::MemoryRequirements TestGraphicsController::GetTextureMemoryRequirements(Graphics::Texture& texture) const
1021 {
1022   mCallStack.PushCall("GetTextureMemoryRequirements", "");
1023   return Graphics::MemoryRequirements{};
1024 }
1025
1026 Graphics::MemoryRequirements TestGraphicsController::GetBufferMemoryRequirements(Graphics::Buffer& buffer) const
1027 {
1028   mCallStack.PushCall("GetBufferMemoryRequirements", "");
1029   return Graphics::MemoryRequirements{};
1030 }
1031
1032 const Graphics::TextureProperties& TestGraphicsController::GetTextureProperties(const Graphics::Texture& texture)
1033 {
1034   static Graphics::TextureProperties textureProperties{};
1035   mCallStack.PushCall("GetTextureProperties", "");
1036
1037   return textureProperties;
1038 }
1039
1040 const Graphics::Reflection& TestGraphicsController::GetProgramReflection(const Graphics::Program& program)
1041 {
1042   mCallStack.PushCall("GetProgramReflection", "");
1043
1044   return static_cast<const TestGraphicsProgram*>(&program)->GetReflection();
1045 }
1046
1047 bool TestGraphicsController::PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const
1048 {
1049   mCallStack.PushCall("PipelineEquals", "");
1050   return false;
1051 }
1052
1053 bool TestGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
1054 {
1055   mCallStack.PushCall("GetProgramParameter", "");
1056   auto graphicsProgram = Uncast<TestGraphicsProgram>(&program);
1057   return graphicsProgram->GetParameter(parameterId, outData);
1058 }
1059
1060 } // namespace Dali