Implementing Framebuffer object
[platform/core/uifw/dali-core.git] / automated-tests / src / dali / dali-test-suite-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-sampler.h"
24 #include "test-graphics-shader.h"
25 #include "test-graphics-texture.h"
26
27 #include <dali/integration-api/gl-defines.h>
28 #include <cstdio>
29 #include <iostream>
30 #include <sstream>
31
32 namespace Dali
33 {
34 std::ostream& operator<<(std::ostream& o, const Graphics::BufferCreateInfo& bufferCreateInfo)
35 {
36   return o << "usage:" << std::hex << bufferCreateInfo.usage << ", size:" << std::dec << bufferCreateInfo.size;
37 }
38
39 std::ostream& operator<<(std::ostream& o, const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo)
40 {
41   return o << "level:" << (commandBufferCreateInfo.level == Graphics::CommandBufferLevel::PRIMARY ? "PRIMARY" : "SECONDARY")
42            << ", fixedCapacity:" << std::dec << commandBufferCreateInfo.fixedCapacity;
43 }
44
45 std::ostream& operator<<(std::ostream& o, const Graphics::TextureType& textureType)
46 {
47   switch(textureType)
48   {
49     case Graphics::TextureType::TEXTURE_2D:
50       o << "TEXTURE_2D";
51       break;
52     case Graphics::TextureType::TEXTURE_3D:
53       o << "TEXTURE_3D";
54       break;
55     case Graphics::TextureType::TEXTURE_CUBEMAP:
56       o << "TEXTURE_CUBEMAP";
57       break;
58   }
59   return o;
60 }
61
62 std::ostream& operator<<(std::ostream& o, const Graphics::Extent2D extent)
63 {
64   o << "width:" << extent.width << ", height:" << extent.height;
65   return o;
66 }
67
68 std::ostream& operator<<(std::ostream& o, const Graphics::TextureCreateInfo& createInfo)
69 {
70   o << "textureType:" << createInfo.textureType
71     << " size:" << createInfo.size
72     << " format:" << static_cast<uint32_t>(createInfo.format)
73     << " mipMapFlag:" << createInfo.mipMapFlag
74     << " layout:" << (createInfo.layout == Graphics::TextureLayout::LINEAR ? "LINEAR" : "OPTIMAL")
75     << " usageFlags:" << std::hex << createInfo.usageFlags
76     << " data:" << std::hex << createInfo.data
77     << " dataSize:" << std::dec << createInfo.dataSize
78     << " nativeImagePtr:" << std::hex << createInfo.nativeImagePtr;
79   return o;
80 }
81
82 std::ostream& operator<<(std::ostream& o, Graphics::SamplerAddressMode addressMode)
83 {
84   switch(addressMode)
85   {
86     case Graphics::SamplerAddressMode::REPEAT:
87       o << "REPEAT";
88       break;
89     case Graphics::SamplerAddressMode::MIRRORED_REPEAT:
90       o << "MIRRORED_REPEAT";
91       break;
92     case Graphics::SamplerAddressMode::CLAMP_TO_EDGE:
93       o << "CLAMP_TO_EDGE";
94       break;
95     case Graphics::SamplerAddressMode::CLAMP_TO_BORDER:
96       o << "CLAMP_TO_BORDER";
97       break;
98     case Graphics::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE:
99       o << "MIRROR_CLAMP_TO_EDGE";
100       break;
101   }
102   return o;
103 }
104
105 std::ostream& operator<<(std::ostream& o, Graphics::SamplerFilter filterMode)
106 {
107   switch(filterMode)
108   {
109     case Graphics::SamplerFilter::LINEAR:
110       o << "LINEAR";
111       break;
112     case Graphics::SamplerFilter::NEAREST:
113       o << "NEAREST";
114       break;
115   }
116   return o;
117 }
118
119 std::ostream& operator<<(std::ostream& o, Graphics::SamplerMipmapMode mipmapMode)
120 {
121   switch(mipmapMode)
122   {
123     case Graphics::SamplerMipmapMode::NONE:
124       o << "NONE";
125       break;
126     case Graphics::SamplerMipmapMode::LINEAR:
127       o << "LINEAR";
128       break;
129     case Graphics::SamplerMipmapMode::NEAREST:
130       o << "NEAREST";
131       break;
132   }
133   return o;
134 }
135
136 std::ostream& operator<<(std::ostream& o, const Graphics::SamplerCreateInfo& createInfo)
137 {
138   o << "minFilter:" << createInfo.minFilter
139     << " magFilter:" << createInfo.magFilter
140     << " wrapModeU:" << createInfo.addressModeU
141     << " wrapModeV:" << createInfo.addressModeV
142     << " wrapModeW:" << createInfo.addressModeW
143     << " mipMapMode:" << createInfo.mipMapMode;
144   return o;
145 }
146
147 std::ostream& operator<<(std::ostream& o, const Graphics::ColorAttachment& colorAttachment)
148 {
149   o << "attachmentId:" << colorAttachment.attachmentId
150     << " layerId:" << colorAttachment.layerId
151     << " levelId:" << colorAttachment.levelId
152     << " texture:" << colorAttachment.texture;
153   return o;
154 }
155
156 std::ostream& operator<<(std::ostream& o, const Graphics::DepthStencilAttachment& depthStencilAttachment)
157 {
158   o << "depthTexture:" << depthStencilAttachment.depthTexture
159     << "depthLevel:" << depthStencilAttachment.depthLevel
160     << "stencilTexture:" << depthStencilAttachment.stencilTexture
161     << "stencilLevel:" << depthStencilAttachment.stencilLevel;
162   return o;
163 }
164
165 std::ostream& operator<<(std::ostream& o, const Graphics::FramebufferCreateInfo& createInfo)
166 {
167   o << "colorAttachments:";
168   for(auto i = 0u; i < createInfo.colorAttachments.size(); ++i)
169   {
170     o << "[" << i << "]=" << createInfo.colorAttachments[i] << "  ";
171   }
172   o << "depthStencilAttachment:" << createInfo.depthStencilAttachment;
173   o << "size: " << createInfo.size;
174   return o;
175 }
176
177
178 int GetNumComponents(Graphics::VertexInputFormat vertexFormat)
179 {
180   switch(vertexFormat)
181   {
182     case Graphics::VertexInputFormat::UNDEFINED:
183     case Graphics::VertexInputFormat::FLOAT:
184     case Graphics::VertexInputFormat::INTEGER:
185       return 1;
186     case Graphics::VertexInputFormat::IVECTOR2:
187     case Graphics::VertexInputFormat::FVECTOR2:
188       return 2;
189     case Graphics::VertexInputFormat::IVECTOR3:
190     case Graphics::VertexInputFormat::FVECTOR3:
191       return 3;
192     case Graphics::VertexInputFormat::FVECTOR4:
193     case Graphics::VertexInputFormat::IVECTOR4:
194       return 4;
195   }
196   return 1;
197 }
198
199 GLint GetSize(Graphics::VertexInputFormat vertexFormat)
200 {
201   switch(vertexFormat)
202   {
203     case Graphics::VertexInputFormat::UNDEFINED:
204       return 1u;
205     case Graphics::VertexInputFormat::INTEGER:
206     case Graphics::VertexInputFormat::IVECTOR2:
207     case Graphics::VertexInputFormat::IVECTOR3:
208     case Graphics::VertexInputFormat::IVECTOR4:
209       return 2u;
210     case Graphics::VertexInputFormat::FLOAT:
211     case Graphics::VertexInputFormat::FVECTOR2:
212     case Graphics::VertexInputFormat::FVECTOR3:
213     case Graphics::VertexInputFormat::FVECTOR4:
214       return 4u;
215   }
216   return 1u;
217 }
218
219 GLint GetGlType(Graphics::VertexInputFormat vertexFormat)
220 {
221   switch(vertexFormat)
222   {
223     case Graphics::VertexInputFormat::UNDEFINED:
224       return GL_BYTE;
225     case Graphics::VertexInputFormat::INTEGER:
226     case Graphics::VertexInputFormat::IVECTOR2:
227     case Graphics::VertexInputFormat::IVECTOR3:
228     case Graphics::VertexInputFormat::IVECTOR4:
229       return GL_SHORT;
230     case Graphics::VertexInputFormat::FLOAT:
231     case Graphics::VertexInputFormat::FVECTOR2:
232     case Graphics::VertexInputFormat::FVECTOR3:
233     case Graphics::VertexInputFormat::FVECTOR4:
234       return GL_FLOAT;
235   }
236   return GL_BYTE;
237 }
238
239 GLenum GetTopology(Graphics::PrimitiveTopology topology)
240 {
241   switch(topology)
242   {
243     case Graphics::PrimitiveTopology::POINT_LIST:
244       return GL_POINTS;
245
246     case Graphics::PrimitiveTopology::LINE_LIST:
247       return GL_LINES;
248
249     case Graphics::PrimitiveTopology::LINE_LOOP:
250       return GL_LINE_LOOP;
251
252     case Graphics::PrimitiveTopology::LINE_STRIP:
253       return GL_LINE_STRIP;
254
255     case Graphics::PrimitiveTopology::TRIANGLE_LIST:
256       return GL_TRIANGLES;
257
258     case Graphics::PrimitiveTopology::TRIANGLE_STRIP:
259       return GL_TRIANGLE_STRIP;
260
261     case Graphics::PrimitiveTopology::TRIANGLE_FAN:
262       return GL_TRIANGLE_FAN;
263   }
264   return GL_TRIANGLES;
265 }
266
267 GLenum GetCullFace(Graphics::CullMode cullMode)
268 {
269   switch(cullMode)
270   {
271     case Graphics::CullMode::NONE:
272       return GL_NONE;
273     case Graphics::CullMode::FRONT:
274       return GL_FRONT;
275     case Graphics::CullMode::BACK:
276       return GL_BACK;
277     case Graphics::CullMode::FRONT_AND_BACK:
278       return GL_FRONT_AND_BACK;
279   }
280   return GL_NONE;
281 }
282
283 GLenum GetFrontFace(Graphics::FrontFace frontFace)
284 {
285   if(frontFace == Graphics::FrontFace::CLOCKWISE)
286   {
287     return GL_CW;
288   }
289   return GL_CCW;
290 }
291
292 GLenum GetBlendFactor(Graphics::BlendFactor blendFactor)
293 {
294   GLenum glFactor = GL_ZERO;
295
296   switch(blendFactor)
297   {
298     case Graphics::BlendFactor::ZERO:
299       glFactor = GL_ZERO;
300       break;
301     case Graphics::BlendFactor::ONE:
302       glFactor = GL_ONE;
303       break;
304     case Graphics::BlendFactor::SRC_COLOR:
305       glFactor = GL_SRC_COLOR;
306       break;
307     case Graphics::BlendFactor::ONE_MINUS_SRC_COLOR:
308       glFactor = GL_ONE_MINUS_SRC_COLOR;
309       break;
310     case Graphics::BlendFactor::DST_COLOR:
311       glFactor = GL_DST_COLOR;
312       break;
313     case Graphics::BlendFactor::ONE_MINUS_DST_COLOR:
314       glFactor = GL_ONE_MINUS_DST_COLOR;
315       break;
316     case Graphics::BlendFactor::SRC_ALPHA:
317       glFactor = GL_SRC_ALPHA;
318       break;
319     case Graphics::BlendFactor::ONE_MINUS_SRC_ALPHA:
320       glFactor = GL_ONE_MINUS_SRC_ALPHA;
321       break;
322     case Graphics::BlendFactor::DST_ALPHA:
323       glFactor = GL_DST_ALPHA;
324       break;
325     case Graphics::BlendFactor::ONE_MINUS_DST_ALPHA:
326       glFactor = GL_ONE_MINUS_DST_ALPHA;
327       break;
328     case Graphics::BlendFactor::CONSTANT_COLOR:
329       glFactor = GL_CONSTANT_COLOR;
330       break;
331     case Graphics::BlendFactor::ONE_MINUS_CONSTANT_COLOR:
332       glFactor = GL_ONE_MINUS_CONSTANT_COLOR;
333       break;
334     case Graphics::BlendFactor::CONSTANT_ALPHA:
335       glFactor = GL_CONSTANT_ALPHA;
336       break;
337     case Graphics::BlendFactor::ONE_MINUS_CONSTANT_ALPHA:
338       glFactor = GL_ONE_MINUS_CONSTANT_ALPHA;
339       break;
340     case Graphics::BlendFactor::SRC_ALPHA_SATURATE:
341       glFactor = GL_SRC_ALPHA_SATURATE;
342       break;
343       // GLES doesn't appear to have dual source blending.
344     case Graphics::BlendFactor::SRC1_COLOR:
345       glFactor = GL_SRC_COLOR;
346       break;
347     case Graphics::BlendFactor::ONE_MINUS_SRC1_COLOR:
348       glFactor = GL_ONE_MINUS_SRC_COLOR;
349       break;
350     case Graphics::BlendFactor::SRC1_ALPHA:
351       glFactor = GL_SRC_ALPHA;
352       break;
353     case Graphics::BlendFactor::ONE_MINUS_SRC1_ALPHA:
354       glFactor = GL_ONE_MINUS_SRC_ALPHA;
355       break;
356   }
357   return glFactor;
358 }
359
360 GLenum GetBlendOp(Graphics::BlendOp blendOp)
361 {
362   GLenum op = GL_FUNC_ADD;
363   switch(blendOp)
364   {
365     case Graphics::BlendOp::ADD:
366       op = GL_FUNC_ADD;
367       break;
368     case Graphics::BlendOp::SUBTRACT:
369       op = GL_FUNC_SUBTRACT;
370       break;
371     case Graphics::BlendOp::REVERSE_SUBTRACT:
372       op = GL_FUNC_REVERSE_SUBTRACT;
373       break;
374     case Graphics::BlendOp::MIN:
375       op = GL_MIN;
376       break;
377     case Graphics::BlendOp::MAX:
378       op = GL_MAX;
379       break;
380
381       // @todo Add advanced blend equations
382   }
383   return op;
384 }
385
386
387 class TestGraphicsMemory : public Graphics::Memory
388 {
389 public:
390   TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize)
391   : mCallStack(callStack),
392     mBuffer(buffer),
393     mMappedOffset(mappedOffset),
394     mMappedSize(mappedSize),
395     mLockedOffset(0u),
396     mLockedSize(0u)
397   {
398   }
399
400   void* LockRegion(uint32_t offset, uint32_t size) override
401   {
402     std::ostringstream o;
403     o << offset << ", " << size;
404     mCallStack.PushCall("Memory::LockRegion", o.str());
405
406     if(offset > mMappedOffset + mMappedSize ||
407        size + offset > mMappedOffset + mMappedSize)
408     {
409       fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds");
410       mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing
411     }
412     mLockedOffset = offset;
413     mLockedSize   = size;
414     return &mBuffer.memory[mMappedOffset + offset];
415   }
416
417   void Unlock(bool flush) override
418   {
419     mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush"));
420     if(flush)
421     {
422       Flush();
423     }
424   }
425
426   void Flush() override
427   {
428     mCallStack.PushCall("Memory::Flush", "");
429     mBuffer.Bind();
430     mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize);
431     mBuffer.Unbind();
432   }
433
434   TraceCallStack&     mCallStack;
435   TestGraphicsBuffer& mBuffer;
436   uint32_t            mMappedOffset;
437   uint32_t            mMappedSize;
438   uint32_t            mLockedOffset;
439   uint32_t            mLockedSize;
440 };
441
442 TestGraphicsController::TestGraphicsController()
443 : mCallStack(true, "TestGraphicsController."),
444   mCommandBufferCallStack(true, "TestCommandBuffer."),
445   mFrameBufferCallStack(true, "TestFrameBuffer.")
446 {
447   mCallStack.Enable(true);
448   mCommandBufferCallStack.Enable(true);
449   auto& trace = mGl.GetTextureTrace();
450   trace.Enable(true);
451   trace.EnableLogging(true);
452 }
453
454
455 void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo)
456 {
457   TraceCallStack::NamedParams namedParams;
458   namedParams["submitInfo"] << "cmdBuffer[" << submitInfo.cmdBuffer.size()
459                             << "], flags:" << std::hex << submitInfo.flags;
460
461   mCallStack.PushCall("SubmitCommandBuffers", "", namedParams);
462
463   mSubmitStack.emplace_back(submitInfo);
464
465   for(auto& graphicsCommandBuffer : submitInfo.cmdBuffer)
466   {
467     auto commandBuffer = Uncast<TestGraphicsCommandBuffer>(graphicsCommandBuffer);
468
469     // Change framebuffer
470     auto bindPipelineCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_PIPELINE);
471     if(!bindPipelineCmds.empty())
472     {
473       auto pipeline    = bindPipelineCmds[0]->data.bindPipeline.pipeline;
474       auto framebuffer = pipeline->framebufferState.framebuffer;
475       if(framebuffer)
476       {
477         auto graphicsFramebuffer = Uncast<TestGraphicsFramebuffer>(framebuffer);
478         graphicsFramebuffer->Bind();
479       }
480       else
481       {
482         mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
483       }
484     }
485
486     auto value = commandBuffer->GetCommandsByType(0 | CommandType::BIND_TEXTURES);
487     if(!value.empty())
488     {
489       // must be fixed
490       for(auto& binding : value[0]->data.bindTextures.textureBindings)
491       {
492         if(binding.texture)
493         {
494           auto texture = Uncast<TestGraphicsTexture>(binding.texture);
495
496           texture->Bind(binding.binding);
497
498           if(binding.sampler)
499           {
500             auto sampler = Uncast<TestGraphicsSampler>(binding.sampler);
501             if(sampler)
502             {
503               sampler->Apply(texture->GetTarget());
504             }
505           }
506
507           texture->Prepare(); // Ensure native texture is ready
508         }
509       }
510     }
511
512     // IndexBuffer binding,
513     auto bindIndexBufferCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_INDEX_BUFFER);
514     if(!bindIndexBufferCmds.empty())
515     {
516       auto& indexBufferBinding = bindIndexBufferCmds[0]->data.bindIndexBuffer;
517       if(indexBufferBinding.buffer)
518       {
519         auto buffer = Uncast<TestGraphicsBuffer>(indexBufferBinding.buffer);
520         buffer->Bind();
521       }
522     }
523
524     // VertexBuffer binding,
525     auto bindVertexBufferCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_VERTEX_BUFFERS);
526     if(!bindVertexBufferCmds.empty())
527     {
528       for(auto& binding : bindVertexBufferCmds[0]->data.bindVertexBuffers.vertexBufferBindings)
529       {
530         auto graphicsBuffer = binding.buffer;
531         auto vertexBuffer   = Uncast<TestGraphicsBuffer>(graphicsBuffer);
532         vertexBuffer->Bind();
533       }
534     }
535
536     bool scissorEnabled = false;
537
538     auto scissorTestList = commandBuffer->GetCommandsByType(0 | CommandType::SET_SCISSOR_TEST);
539     if(!scissorTestList.empty())
540     {
541       if(scissorTestList[0]->data.scissorTest.enable)
542       {
543         mGl.Enable(GL_SCISSOR_TEST);
544         scissorEnabled = true;
545       }
546       else
547       {
548         mGl.Disable(GL_SCISSOR_TEST);
549       }
550     }
551
552     auto scissorList = commandBuffer->GetCommandsByType(0 | CommandType::SET_SCISSOR);
553     if(!scissorList.empty() && scissorEnabled)
554     {
555       auto& rect = scissorList[0]->data.scissor.region;
556       mGl.Scissor(rect.x, rect.y, rect.width, rect.height);
557     }
558
559     auto viewportList = commandBuffer->GetCommandsByType(0 | CommandType::SET_VIEWPORT);
560     if(!viewportList.empty())
561     {
562       mGl.Viewport(viewportList[0]->data.viewport.region.x, viewportList[0]->data.viewport.region.y, viewportList[0]->data.viewport.region.width, viewportList[0]->data.viewport.region.height);
563     }
564
565     // ignore viewport enable
566
567     // Pipeline attribute setup
568     if(!bindPipelineCmds.empty())
569     {
570       auto  pipeline = bindPipelineCmds[0]->data.bindPipeline.pipeline;
571       auto& vi       = pipeline->vertexInputState;
572       for(auto& attribute : vi.attributes)
573       {
574         mGl.EnableVertexAttribArray(attribute.location);
575         uint32_t attributeOffset = attribute.offset;
576         GLsizei  stride          = vi.bufferBindings[attribute.binding].stride;
577
578         mGl.VertexAttribPointer(attribute.location,
579                                 GetNumComponents(attribute.format),
580                                 GetGlType(attribute.format),
581                                 GL_FALSE, // Not normalized
582                                 stride,
583                                 reinterpret_cast<void*>(attributeOffset));
584       }
585
586       // Cull face setup
587       auto& rasterizationState = pipeline->rasterizationState;
588       if(rasterizationState.cullMode == Graphics::CullMode::NONE)
589       {
590         mGl.Disable(GL_CULL_FACE);
591       }
592       else
593       {
594         mGl.Enable(GL_CULL_FACE);
595         mGl.CullFace(GetCullFace(rasterizationState.cullMode));
596       }
597
598       mGl.FrontFace(GetFrontFace(rasterizationState.frontFace));
599       // We don't modify glPolygonMode in our context/abstraction from GL_FILL (the GL default),
600       // so it isn't present in the API (and won't have any tests!)
601
602       // Blending setup
603       auto& colorBlendState = pipeline->colorBlendState;
604       if(colorBlendState.blendEnable)
605       {
606         mGl.Enable(GL_BLEND);
607
608         mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor),
609                               GetBlendFactor(colorBlendState.dstColorBlendFactor),
610                               GetBlendFactor(colorBlendState.srcAlphaBlendFactor),
611                               GetBlendFactor(colorBlendState.dstAlphaBlendFactor));
612         if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp)
613         {
614           mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp));
615         }
616         else
617         {
618           mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp));
619         }
620         mGl.BlendColor(colorBlendState.blendConstants[0],
621                        colorBlendState.blendConstants[1],
622                        colorBlendState.blendConstants[2],
623                        colorBlendState.blendConstants[3]);
624       }
625       else
626       {
627         mGl.Disable(GL_BLEND);
628       }
629
630       // draw call
631       auto topology = pipeline->inputAssemblyState.topology;
632
633       // UniformBuffer binding (once we know pipeline)
634       auto bindUniformBuffersCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_UNIFORM_BUFFER);
635       if(!bindUniformBuffersCmds.empty())
636       {
637         auto buffer = bindUniformBuffersCmds[0]->data.bindUniformBuffers.standaloneUniformsBufferBinding;
638
639         // based on reflection, issue gl calls
640         buffer.buffer->BindAsUniformBuffer(static_cast<const TestGraphicsProgram*>(pipeline->programState.program));
641       }
642
643       auto drawCmds = commandBuffer->GetCommandsByType(0 |
644                                                        CommandType::DRAW |
645                                                        CommandType::DRAW_INDEXED_INDIRECT |
646                                                        CommandType::DRAW_INDEXED);
647
648       if(!drawCmds.empty())
649       {
650         if(drawCmds[0]->data.draw.type == DrawCallDescriptor::Type::DRAW_INDEXED)
651         {
652           mGl.DrawElements(GetTopology(topology),
653                            static_cast<GLsizei>(drawCmds[0]->data.draw.drawIndexed.indexCount),
654                            GL_UNSIGNED_SHORT,
655                            reinterpret_cast<void*>(drawCmds[0]->data.draw.drawIndexed.firstIndex));
656         }
657         else
658         {
659           mGl.DrawArrays(GetTopology(topology), 0, drawCmds[0]->data.draw.draw.vertexCount);
660         }
661       }
662       // attribute clear
663       for(auto& attribute : vi.attributes)
664       {
665         mGl.DisableVertexAttribArray(attribute.location);
666       }
667     }
668   }
669 }
670
671 /**
672  * @brief Presents render target
673  * @param renderTarget render target to present
674  */
675 void TestGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget)
676 {
677   TraceCallStack::NamedParams namedParams;
678   namedParams["renderTarget"] << std::hex << renderTarget;
679   mCallStack.PushCall("PresentRenderTarget", "", namedParams);
680 }
681
682 /**
683  * @brief Waits until the GPU is idle
684  */
685 void TestGraphicsController::WaitIdle()
686 {
687   mCallStack.PushCall("WaitIdle", "");
688 }
689
690 /**
691  * @brief Lifecycle pause event
692  */
693 void TestGraphicsController::Pause()
694 {
695   mCallStack.PushCall("Pause", "");
696 }
697
698 /**
699  * @brief Lifecycle resume event
700  */
701 void TestGraphicsController::Resume()
702 {
703   mCallStack.PushCall("Resume", "");
704 }
705
706 void TestGraphicsController::Shutdown()
707 {
708   mCallStack.PushCall("Shutdown", "");
709 }
710
711 void TestGraphicsController::Destroy()
712 {
713   mCallStack.PushCall("Destroy", "");
714 }
715
716 void TestGraphicsController::UpdateTextures(const std::vector<Graphics::TextureUpdateInfo>&       updateInfoList,
717                                             const std::vector<Graphics::TextureUpdateSourceInfo>& sourceList)
718 {
719   TraceCallStack::NamedParams namedParams;
720   namedParams["updateInfoList"] << "[" << updateInfoList.size() << "]:";
721   namedParams["sourceList"] << "[" << sourceList.size() << "]:";
722
723   mCallStack.PushCall("UpdateTextures", "", namedParams);
724
725   // Call either TexImage2D or TexSubImage2D
726   for(unsigned int i = 0; i < updateInfoList.size(); ++i)
727   {
728     auto& updateInfo = updateInfoList[i];
729     auto& source     = sourceList[i];
730
731     auto texture = static_cast<TestGraphicsTexture*>(updateInfo.dstTexture);
732     texture->Bind(0); // Use first texture unit during resource update
733     texture->Update(updateInfo, source);
734   }
735 }
736
737 bool TestGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool enableStencil)
738 {
739   TraceCallStack::NamedParams namedParams;
740   namedParams["enableDepth"] << (enableDepth ? "T" : "F");
741   namedParams["enableStencil"] << (enableStencil ? "T" : "F");
742   mCallStack.PushCall("EnableDepthStencilBuffer", "", namedParams);
743   return false;
744 }
745
746 void TestGraphicsController::RunGarbageCollector(size_t numberOfDiscardedRenderers)
747 {
748   TraceCallStack::NamedParams namedParams;
749   namedParams["numberOfDiscardedRenderers"] << numberOfDiscardedRenderers;
750   mCallStack.PushCall("RunGarbageCollector", "", namedParams);
751 }
752
753 void TestGraphicsController::DiscardUnusedResources()
754 {
755   mCallStack.PushCall("DiscardUnusedResources", "");
756 }
757
758 bool TestGraphicsController::IsDiscardQueueEmpty()
759 {
760   mCallStack.PushCall("IsDiscardQueueEmpty", "");
761   return isDiscardQueueEmptyResult;
762 }
763
764 /**
765  * @brief Test if the graphics subsystem has resumed & should force a draw
766  *
767  * @return true if the graphics subsystem requires a re-draw
768  */
769 bool TestGraphicsController::IsDrawOnResumeRequired()
770 {
771   mCallStack.PushCall("IsDrawOnResumeRequired", "");
772   return isDrawOnResumeRequiredResult;
773 }
774
775 Graphics::UniquePtr<Graphics::Buffer> TestGraphicsController::CreateBuffer(const Graphics::BufferCreateInfo& createInfo, Graphics::UniquePtr<Graphics::Buffer>&& oldBuffer)
776 {
777   std::ostringstream oss;
778   oss << "bufferCreateInfo:" << createInfo;
779   mCallStack.PushCall("CreateBuffer", oss.str());
780   return Graphics::MakeUnique<TestGraphicsBuffer>(mCallStack, mGl, createInfo.size, createInfo.usage);
781 }
782
783 Graphics::UniquePtr<Graphics::CommandBuffer> TestGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, Graphics::UniquePtr<Graphics::CommandBuffer>&& oldCommandBuffer)
784 {
785   std::ostringstream oss;
786   oss << "commandBufferCreateInfo:" << commandBufferCreateInfo;
787   mCallStack.PushCall("CreateCommandBuffer", oss.str());
788   return Graphics::MakeUnique<TestGraphicsCommandBuffer>(mCommandBufferCallStack, mGl);
789 }
790
791 Graphics::UniquePtr<Graphics::RenderPass> TestGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<Graphics::RenderPass>&& oldRenderPass)
792 {
793   mCallStack.PushCall("CreateRenderPass", "");
794   return nullptr;
795 }
796
797 Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::CreateTexture(const Graphics::TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Graphics::Texture>&& oldTexture)
798 {
799   TraceCallStack::NamedParams namedParams;
800   namedParams["textureCreateInfo"] << textureCreateInfo;
801   mCallStack.PushCall("CreateTexture", namedParams.str(), namedParams);
802
803   return Graphics::MakeUnique<TestGraphicsTexture>(mGl, textureCreateInfo);
804 }
805
806 Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebuffer(
807   const Graphics::FramebufferCreateInfo&       createInfo,
808   Graphics::UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
809 {
810   TraceCallStack::NamedParams namedParams;
811   namedParams["framebufferCreateInfo"] << createInfo;
812   mCallStack.PushCall("Controller::CreateFramebuffer", namedParams.str(), namedParams);
813
814   return Graphics::MakeUnique<TestGraphicsFramebuffer>(mFrameBufferCallStack, mGl, createInfo);
815 }
816
817 Graphics::UniquePtr<Graphics::Pipeline> TestGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
818 {
819   mCallStack.PushCall("CreatePipeline", "");
820   return std::make_unique<TestGraphicsPipeline>(mGl, pipelineCreateInfo);
821 }
822
823 Graphics::UniquePtr<Graphics::Program> TestGraphicsController::CreateProgram(const Graphics::ProgramCreateInfo& programCreateInfo, Graphics::UniquePtr<Graphics::Program>&& oldProgram)
824 {
825   mCallStack.PushCall("CreateProgram", "");
826
827   for(auto cacheEntry : mProgramCache)
828   {
829     bool found = true;
830     for(auto& shader : *(programCreateInfo.shaderState))
831     {
832       auto                 graphicsShader = Uncast<TestGraphicsShader>(shader.shader);
833       std::vector<uint8_t> source;
834       source.resize(graphicsShader->mCreateInfo.sourceSize);
835       memcpy(&source[0], graphicsShader->mCreateInfo.sourceData, graphicsShader->mCreateInfo.sourceSize);
836
837       if(!std::equal(source.begin(), source.end(), cacheEntry.shaders[shader.pipelineStage].begin()))
838       {
839         found = false;
840         break;
841       }
842     }
843     if(found)
844     {
845       return Graphics::MakeUnique<TestGraphicsProgram>(cacheEntry.programImpl);
846     }
847   }
848
849   mProgramCache.emplace_back();
850   mProgramCache.back().programImpl = new TestGraphicsProgramImpl(mGl, programCreateInfo, mVertexFormats, mCustomUniforms);
851   for(auto& shader : *(programCreateInfo.shaderState))
852   {
853     auto graphicsShader = Uncast<TestGraphicsShader>(shader.shader);
854     mProgramCache.back().shaders[shader.pipelineStage].resize(graphicsShader->mCreateInfo.sourceSize);
855     memcpy(&mProgramCache.back().shaders[shader.pipelineStage][0], graphicsShader->mCreateInfo.sourceData, graphicsShader->mCreateInfo.sourceSize);
856   }
857   return Graphics::MakeUnique<TestGraphicsProgram>(mProgramCache.back().programImpl);
858 }
859
860 Graphics::UniquePtr<Graphics::Shader> TestGraphicsController::CreateShader(const Graphics::ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Graphics::Shader>&& oldShader)
861 {
862   mCallStack.PushCall("CreateShader", "");
863   return Graphics::MakeUnique<TestGraphicsShader>(mGl, shaderCreateInfo);
864 }
865
866 Graphics::UniquePtr<Graphics::Sampler> TestGraphicsController::CreateSampler(const Graphics::SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Graphics::Sampler>&& oldSampler)
867 {
868   TraceCallStack::NamedParams namedParams;
869   namedParams["samplerCreateInfo"] << samplerCreateInfo;
870   mCallStack.PushCall("CreateSampler", namedParams.str(), namedParams);
871
872   return Graphics::MakeUnique<TestGraphicsSampler>(mGl, samplerCreateInfo);
873 }
874
875 Graphics::UniquePtr<Graphics::RenderTarget> TestGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
876 {
877   mCallStack.PushCall("CreateRenderTarget", "");
878   return nullptr;
879 }
880
881 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapBufferRange(const Graphics::MapBufferInfo& mapInfo)
882 {
883   mCallStack.PushCall("MapBufferRange", "");
884
885   auto buffer = static_cast<TestGraphicsBuffer*>(mapInfo.buffer);
886   buffer->memory.resize(mapInfo.offset + mapInfo.size); // For initial testing, allow writes past capacity
887
888   return std::make_unique<TestGraphicsMemory>(mCallStack, *buffer, mapInfo.offset, mapInfo.size);
889 }
890
891 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapTextureRange(const Graphics::MapTextureInfo& mapInfo)
892 {
893   mCallStack.PushCall("MapTextureRange", "");
894   return nullptr;
895 }
896
897 void TestGraphicsController::UnmapMemory(Graphics::UniquePtr<Graphics::Memory> memory)
898 {
899   mCallStack.PushCall("UnmapMemory", "");
900 }
901
902 Graphics::MemoryRequirements TestGraphicsController::GetTextureMemoryRequirements(Graphics::Texture& texture) const
903 {
904   mCallStack.PushCall("GetTextureMemoryRequirements", "");
905   return Graphics::MemoryRequirements{};
906 }
907
908 Graphics::MemoryRequirements TestGraphicsController::GetBufferMemoryRequirements(Graphics::Buffer& buffer) const
909 {
910   mCallStack.PushCall("GetBufferMemoryRequirements", "");
911   return Graphics::MemoryRequirements{};
912 }
913
914 const Graphics::TextureProperties& TestGraphicsController::GetTextureProperties(const Graphics::Texture& texture)
915 {
916   static Graphics::TextureProperties textureProperties{};
917   mCallStack.PushCall("GetTextureProperties", "");
918
919   return textureProperties;
920 }
921
922 const Graphics::Reflection& TestGraphicsController::GetProgramReflection(const Graphics::Program& program)
923 {
924   mCallStack.PushCall("GetProgramReflection", "");
925
926   return static_cast<const TestGraphicsProgram*>(&program)->GetReflection();
927 }
928
929 bool TestGraphicsController::PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const
930 {
931   mCallStack.PushCall("PipelineEquals", "");
932   return false;
933 }
934
935 bool TestGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
936 {
937   mCallStack.PushCall("GetProgramParameter", "");
938   auto graphicsProgram = Uncast<TestGraphicsProgram>(&program);
939   return graphicsProgram->GetParameter(parameterId, outData);
940 }
941
942 } // namespace Dali