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