Merge branch 'devel/graphics' into devel/master
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit / dali-toolkit-test-utils / test-graphics-command-buffer.h
1 #ifndef DALI_TEST_GRAPHICS_COMMAND_BUFFER_H
2 #define DALI_TEST_GRAPHICS_COMMAND_BUFFER_H
3
4 /*
5  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <dali/graphics-api/graphics-command-buffer-create-info.h>
21 #include <dali/graphics-api/graphics-command-buffer.h>
22 #include <dali/graphics-api/graphics-pipeline.h>
23 #include <dali/graphics-api/graphics-types.h>
24 #include <cstdint>
25 #include <vector>
26 #include "test-gl-abstraction.h"
27 #include "test-graphics-buffer.h"
28 #include "test-graphics-pipeline.h"
29 #include "test-trace-call-stack.h"
30
31 namespace Dali
32 {
33 class TestGraphicsTexture;
34 class TestGraphicsBuffer;
35 class TestGraphicsSampler;
36 class TestGraphicsPipeline;
37
38 enum class CommandType
39 {
40   FLUSH                 = 1 << 0,
41   BIND_TEXTURES         = 1 << 1,
42   BIND_SAMPLERS         = 1 << 2,
43   BIND_VERTEX_BUFFERS   = 1 << 3,
44   BIND_INDEX_BUFFER     = 1 << 4,
45   BIND_UNIFORM_BUFFER   = 1 << 5,
46   BIND_PIPELINE         = 1 << 6,
47   DRAW                  = 1 << 7,
48   DRAW_INDEXED          = 1 << 8,
49   DRAW_INDEXED_INDIRECT = 1 << 9,
50   SET_SCISSOR           = 1 << 10,
51   SET_SCISSOR_TEST      = 1 << 11,
52   SET_VIEWPORT          = 1 << 12,
53   SET_VIEWPORT_TEST     = 1 << 13
54 };
55
56 using CommandTypeMask = uint32_t;
57 template<typename T>
58 inline CommandTypeMask operator|(T flags, CommandType bit)
59 {
60   return static_cast<CommandTypeMask>(flags) | static_cast<CommandTypeMask>(bit);
61 }
62
63 /**
64  * @brief Descriptor of single buffer binding within
65  * command buffer.
66  */
67 struct VertexBufferBindingDescriptor
68 {
69   const TestGraphicsBuffer* buffer{nullptr};
70   uint32_t                  offset{0u};
71 };
72
73 /**
74  * @brief Descriptor of ix buffer binding within
75  * command buffer.
76  */
77 struct IndexBufferBindingDescriptor
78 {
79   const TestGraphicsBuffer* buffer{nullptr};
80   uint32_t                  offset{};
81   Graphics::Format          format{};
82 };
83
84 /**
85  * @brief Descriptor of uniform buffer binding within
86  * command buffer.
87  */
88 struct UniformBufferBindingDescriptor
89 {
90   const TestGraphicsBuffer* buffer{nullptr};
91   uint32_t                  binding{0u};
92   uint32_t                  offset{0u};
93   bool                      emulated; ///<true if UBO is emulated for old gfx API
94 };
95
96 /**
97  * @brief The descriptor of draw call
98  */
99 struct DrawCallDescriptor
100 {
101   /**
102    * @brief Enum specifying type of the draw call
103    */
104   enum class Type
105   {
106     DRAW,
107     DRAW_INDEXED,
108     DRAW_INDEXED_INDIRECT
109   };
110
111   Type type{}; ///< Type of the draw call
112
113   /**
114    * Union contains data for all types of draw calls.
115    */
116   union
117   {
118     /**
119      * @brief Vertex array draw
120      */
121     struct
122     {
123       uint32_t vertexCount;
124       uint32_t instanceCount;
125       uint32_t firstVertex;
126       uint32_t firstInstance;
127     } draw;
128
129     /**
130      * @brief Indexed draw
131      */
132     struct
133     {
134       uint32_t indexCount;
135       uint32_t instanceCount;
136       uint32_t firstIndex;
137       int32_t  vertexOffset;
138       uint32_t firstInstance;
139     } drawIndexed;
140
141     /**
142      * @brief Indexed draw indirect
143      */
144     struct
145     {
146       const TestGraphicsBuffer* buffer;
147       uint32_t                  offset;
148       uint32_t                  drawCount;
149       uint32_t                  stride;
150     } drawIndexedIndirect;
151   };
152 };
153
154 /**
155  * Command structure allocates memory to store a single command
156  */
157 struct Command
158 {
159   Command()
160   {
161   }
162
163   ~Command()
164   {
165   }
166
167   /**
168    * @brief Copy constructor
169    * @param[in] rhs Command
170    */
171   Command(const Command& rhs)
172   {
173     switch(rhs.type)
174     {
175       case CommandType::BIND_VERTEX_BUFFERS:
176       {
177         data.bindVertexBuffers = rhs.data.bindVertexBuffers;
178         break;
179       }
180       case CommandType::BIND_INDEX_BUFFER:
181       {
182         data.bindIndexBuffer = rhs.data.bindIndexBuffer;
183         break;
184       }
185       case CommandType::BIND_SAMPLERS:
186       {
187         data.bindSamplers = rhs.data.bindSamplers;
188         break;
189       }
190       case CommandType::BIND_TEXTURES:
191       {
192         data.bindTextures = rhs.data.bindTextures;
193         break;
194       }
195       case CommandType::BIND_PIPELINE:
196       {
197         data.bindPipeline = rhs.data.bindPipeline;
198         break;
199       }
200       case CommandType::BIND_UNIFORM_BUFFER:
201       {
202         data.bindUniformBuffers = rhs.data.bindUniformBuffers;
203         break;
204       }
205       case CommandType::DRAW:
206       {
207         data.draw.type = rhs.data.draw.type;
208         data.draw.draw = rhs.data.draw.draw;
209         break;
210       }
211       case CommandType::DRAW_INDEXED:
212       {
213         data.draw.type        = rhs.data.draw.type;
214         data.draw.drawIndexed = rhs.data.draw.drawIndexed;
215         break;
216       }
217       case CommandType::DRAW_INDEXED_INDIRECT:
218       {
219         data.draw.type                = rhs.data.draw.type;
220         data.draw.drawIndexedIndirect = rhs.data.draw.drawIndexedIndirect;
221         break;
222       }
223       case CommandType::FLUSH:
224       {
225         // Nothing to do
226         break;
227       }
228       case CommandType::SET_SCISSOR:
229       {
230         data.scissor.region = rhs.data.scissor.region;
231         break;
232       }
233       case CommandType::SET_SCISSOR_TEST:
234       {
235         data.scissorTest.enable = rhs.data.scissorTest.enable;
236         break;
237       }
238       case CommandType::SET_VIEWPORT:
239       {
240         data.viewport.region = rhs.data.viewport.region;
241         break;
242       }
243       case CommandType::SET_VIEWPORT_TEST:
244       {
245         data.viewportTest.enable = rhs.data.viewportTest.enable;
246         break;
247       }
248     }
249     type = rhs.type;
250   }
251
252   /**
253    * @brief move constructor
254    * @param[in] rhs Command
255    */
256   Command(Command&& rhs) noexcept
257   {
258     switch(rhs.type)
259     {
260       case CommandType::BIND_VERTEX_BUFFERS:
261       {
262         data.bindVertexBuffers = std::move(rhs.data.bindVertexBuffers);
263         break;
264       }
265       case CommandType::BIND_INDEX_BUFFER:
266       {
267         data.bindIndexBuffer = rhs.data.bindIndexBuffer;
268         break;
269       }
270       case CommandType::BIND_UNIFORM_BUFFER:
271       {
272         data.bindUniformBuffers = std::move(rhs.data.bindUniformBuffers);
273         break;
274       }
275       case CommandType::BIND_SAMPLERS:
276       {
277         data.bindSamplers = std::move(rhs.data.bindSamplers);
278         break;
279       }
280       case CommandType::BIND_TEXTURES:
281       {
282         data.bindTextures = std::move(rhs.data.bindTextures);
283         break;
284       }
285       case CommandType::BIND_PIPELINE:
286       {
287         data.bindPipeline = rhs.data.bindPipeline;
288         break;
289       }
290       case CommandType::DRAW:
291       {
292         data.draw.type = rhs.data.draw.type;
293         data.draw.draw = rhs.data.draw.draw;
294         break;
295       }
296       case CommandType::DRAW_INDEXED:
297       {
298         data.draw.type        = rhs.data.draw.type;
299         data.draw.drawIndexed = rhs.data.draw.drawIndexed;
300         break;
301       }
302       case CommandType::DRAW_INDEXED_INDIRECT:
303       {
304         data.draw.type                = rhs.data.draw.type;
305         data.draw.drawIndexedIndirect = rhs.data.draw.drawIndexedIndirect;
306         break;
307       }
308       case CommandType::FLUSH:
309       {
310         // Nothing to do
311         break;
312       }
313       case CommandType::SET_SCISSOR:
314       {
315         data.scissor.region = rhs.data.scissor.region;
316         break;
317       }
318       case CommandType::SET_SCISSOR_TEST:
319       {
320         data.scissorTest.enable = rhs.data.scissorTest.enable;
321         break;
322       }
323       case CommandType::SET_VIEWPORT:
324       {
325         data.viewport.region = rhs.data.viewport.region;
326         break;
327       }
328       case CommandType::SET_VIEWPORT_TEST:
329       {
330         data.viewportTest.enable = rhs.data.viewportTest.enable;
331         break;
332       }
333     }
334     type = rhs.type;
335   }
336
337   CommandType type{CommandType::FLUSH}; ///< Type of command
338
339   union CommandData
340   {
341     CommandData()
342     {
343     }
344
345     ~CommandData()
346     {
347     } // do nothing
348
349     struct
350     {
351       std::vector<Graphics::TextureBinding> textureBindings;
352     } bindTextures{};
353
354     // BindSampler command
355     struct
356     {
357       std::vector<Graphics::SamplerBinding> samplerBindings;
358     } bindSamplers;
359
360     struct
361     {
362       using Binding = VertexBufferBindingDescriptor;
363       std::vector<Binding> vertexBufferBindings;
364     } bindVertexBuffers;
365
366     struct : public IndexBufferBindingDescriptor
367     {
368     } bindIndexBuffer;
369
370     struct
371     {
372       std::vector<UniformBufferBindingDescriptor> uniformBufferBindings{};
373       UniformBufferBindingDescriptor              standaloneUniformsBufferBinding{};
374     } bindUniformBuffers;
375
376     struct
377     {
378       const TestGraphicsPipeline* pipeline{nullptr};
379     } bindPipeline;
380
381     struct : public DrawCallDescriptor
382     {
383     } draw;
384
385     struct
386     {
387       Graphics::Rect2D region;
388     } scissor;
389     struct
390     {
391       bool enable;
392     } scissorTest;
393     struct
394     {
395       Graphics::Viewport region;
396     } viewport;
397     struct
398     {
399       bool enable;
400     } viewportTest;
401   } data;
402 };
403
404 class TestGraphicsCommandBuffer : public Graphics::CommandBuffer
405 {
406 public:
407   TestGraphicsCommandBuffer(TraceCallStack& callstack, TestGlAbstraction& glAbstraction);
408   ~TestGraphicsCommandBuffer()
409   {
410   }
411
412   void BindVertexBuffers(uint32_t                             firstBinding,
413                          std::vector<const Graphics::Buffer*> buffers,
414                          std::vector<uint32_t>                offsets) override
415   {
416     mCommands.emplace_back();
417     mCommands.back().type = CommandType::BIND_VERTEX_BUFFERS;
418     auto& bindings        = mCommands.back().data.bindVertexBuffers.vertexBufferBindings;
419     if(bindings.size() < firstBinding + buffers.size())
420     {
421       bindings.resize(firstBinding + buffers.size());
422       auto index = firstBinding;
423       for(auto& buf : buffers)
424       {
425         bindings[index].buffer = static_cast<const TestGraphicsBuffer*>(buf);
426         bindings[index].offset = offsets[index - firstBinding];
427         index++;
428       }
429     }
430     mCallStack.PushCall("BindVertexBuffers", "");
431   }
432
433   void BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings) override
434   {
435     mCommands.emplace_back();
436     auto& cmd     = mCommands.back();
437     cmd.type      = CommandType::BIND_UNIFORM_BUFFER;
438     auto& bindCmd = cmd.data.bindUniformBuffers;
439     for(const auto& binding : bindings)
440     {
441       if(binding.buffer)
442       {
443         auto testBuffer = static_cast<const TestGraphicsBuffer*>(binding.buffer);
444         if(testBuffer->IsCPUAllocated()) // standalone uniforms
445         {
446           bindCmd.standaloneUniformsBufferBinding.buffer   = testBuffer;
447           bindCmd.standaloneUniformsBufferBinding.offset   = binding.offset;
448           bindCmd.standaloneUniformsBufferBinding.binding  = binding.binding;
449           bindCmd.standaloneUniformsBufferBinding.emulated = true;
450         }
451         else // Bind regular UBO
452         {
453           // resize binding slots
454           if(binding.binding >= bindCmd.uniformBufferBindings.size())
455           {
456             bindCmd.uniformBufferBindings.resize(binding.binding + 1);
457           }
458           auto& slot    = bindCmd.uniformBufferBindings[binding.binding];
459           slot.buffer   = testBuffer;
460           slot.offset   = binding.offset;
461           slot.binding  = binding.binding;
462           slot.emulated = false;
463         }
464       }
465     }
466     mCallStack.PushCall("BindUniformBuffers", "");
467   }
468
469   void BindPipeline(const Graphics::Pipeline& pipeline) override
470   {
471     mCommands.emplace_back();
472     mCommands.back().type                       = CommandType::BIND_PIPELINE;
473     mCommands.back().data.bindPipeline.pipeline = static_cast<const TestGraphicsPipeline*>(&pipeline);
474     mCallStack.PushCall("BindPipeline", "");
475   }
476
477   void BindTextures(std::vector<Graphics::TextureBinding>& textureBindings) override
478   {
479     mCommands.emplace_back();
480     mCommands.back().type                              = CommandType::BIND_TEXTURES;
481     mCommands.back().data.bindTextures.textureBindings = std::move(textureBindings);
482     mCallStack.PushCall("BindTextures", "");
483   }
484
485   void BindSamplers(std::vector<Graphics::SamplerBinding>& samplerBindings) override
486   {
487     mCommands.emplace_back();
488     mCommands.back().data.bindSamplers.samplerBindings = std::move(samplerBindings);
489     mCallStack.PushCall("BindSamplers", "");
490   }
491
492   void BindPushConstants(void*    data,
493                          uint32_t size,
494                          uint32_t binding) override
495   {
496     mCallStack.PushCall("BindPushConstants", "");
497   }
498
499   void BindIndexBuffer(const Graphics::Buffer& buffer,
500                        uint32_t                offset,
501                        Graphics::Format        format) override
502   {
503     mCommands.emplace_back();
504     mCommands.back().type                        = CommandType::BIND_INDEX_BUFFER;
505     mCommands.back().data.bindIndexBuffer.buffer = static_cast<const TestGraphicsBuffer*>(&buffer);
506     mCommands.back().data.bindIndexBuffer.offset = offset;
507     mCommands.back().data.bindIndexBuffer.format = format;
508     mCallStack.PushCall("BindIndexBuffer", "");
509   }
510
511   void BeginRenderPass(
512     Graphics::RenderPass&             renderPass,
513     Graphics::RenderTarget&           renderTarget,
514     Graphics::Extent2D                renderArea,
515     std::vector<Graphics::ClearValue> clearValues) override
516   {
517     mCallStack.PushCall("BeginRenderPass", "");
518   }
519
520   /**
521    * @brief Ends current render pass
522    *
523    * This command must be issued in order to finalize the render pass.
524    * It's up to the implementation whether anything has to be done but
525    * the Controller may use end RP marker in order to resolve resource
526    * dependencies (for example, to know when target texture is ready
527    * before passing it to another render pass).
528    */
529   void EndRenderPass() override
530   {
531     mCallStack.PushCall("EndRenderPass", "");
532   }
533
534   void Draw(
535     uint32_t vertexCount,
536     uint32_t instanceCount,
537     uint32_t firstVertex,
538     uint32_t firstInstance) override
539   {
540     mCommands.emplace_back();
541     mCommands.back().type  = CommandType::DRAW;
542     auto& cmd              = mCommands.back().data.draw;
543     cmd.type               = DrawCallDescriptor::Type::DRAW;
544     cmd.draw.vertexCount   = vertexCount;
545     cmd.draw.instanceCount = instanceCount;
546     cmd.draw.firstInstance = firstInstance;
547     cmd.draw.firstVertex   = firstVertex;
548     mCallStack.PushCall("Draw", "");
549   }
550
551   void DrawIndexed(
552     uint32_t indexCount,
553     uint32_t instanceCount,
554     uint32_t firstIndex,
555     int32_t  vertexOffset,
556     uint32_t firstInstance) override
557   {
558     mCommands.emplace_back();
559     mCommands.back().type         = CommandType::DRAW_INDEXED;
560     auto& cmd                     = mCommands.back().data.draw;
561     cmd.type                      = DrawCallDescriptor::Type::DRAW_INDEXED;
562     cmd.drawIndexed.firstIndex    = firstIndex;
563     cmd.drawIndexed.firstInstance = firstInstance;
564     cmd.drawIndexed.indexCount    = indexCount;
565     cmd.drawIndexed.vertexOffset  = vertexOffset;
566     cmd.drawIndexed.instanceCount = instanceCount;
567     mCallStack.PushCall("DrawIndexed", "");
568   }
569
570   void DrawIndexedIndirect(
571     Graphics::Buffer& buffer,
572     uint32_t          offset,
573     uint32_t          drawCount,
574     uint32_t          stride) override
575   {
576     mCommands.emplace_back();
577     mCommands.back().type             = CommandType::DRAW_INDEXED_INDIRECT;
578     auto& cmd                         = mCommands.back().data.draw;
579     cmd.type                          = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
580     cmd.drawIndexedIndirect.buffer    = static_cast<const TestGraphicsBuffer*>(&buffer);
581     cmd.drawIndexedIndirect.offset    = offset;
582     cmd.drawIndexedIndirect.drawCount = drawCount;
583     cmd.drawIndexedIndirect.stride    = stride;
584     mCallStack.PushCall("DrawIndexedIndirect", "");
585   }
586
587   void Reset() override
588   {
589     mCommands.clear();
590     mCallStack.PushCall("Reset", "");
591   }
592
593   void SetScissor(Graphics::Rect2D value) override
594   {
595     TraceCallStack::NamedParams params;
596     params["x"] << value.x;
597     params["y"] << value.y;
598     params["width"] << value.width;
599     params["height"] << value.height;
600     mCallStack.PushCall("SetScissor", params.str(), params);
601
602     mCommands.emplace_back();
603     mCommands.back().type                = CommandType::SET_SCISSOR;
604     mCommands.back().data.scissor.region = value;
605   }
606
607   void SetScissorTestEnable(bool value) override
608   {
609     TraceCallStack::NamedParams params;
610     params["value"] << (value ? "T" : "F");
611     mCallStack.PushCall("SetScissorTestEnable", params.str(), params);
612
613     mCommands.emplace_back();
614     mCommands.back().type                    = CommandType::SET_SCISSOR_TEST;
615     mCommands.back().data.scissorTest.enable = value;
616   }
617
618   void SetViewport(Graphics::Viewport value) override
619   {
620     TraceCallStack::NamedParams params;
621     params["x"] << value.x;
622     params["y"] << value.y;
623     params["width"] << value.width;
624     params["height"] << value.height;
625     params["minDepth"] << value.minDepth;
626     params["maxDepth"] << value.maxDepth;
627     mCallStack.PushCall("SetViewport", params.str(), params);
628
629     mCommands.emplace_back();
630     mCommands.back().type                 = CommandType::SET_VIEWPORT;
631     mCommands.back().data.viewport.region = value;
632   }
633
634   void SetViewportEnable(bool value) override
635   {
636     TraceCallStack::NamedParams params;
637     params["value"] << (value ? "T" : "F");
638     mCallStack.PushCall("SetViewportEnable", params.str(), params);
639
640     mCommands.emplace_back();
641     mCommands.back().type                     = CommandType::SET_VIEWPORT_TEST;
642     mCommands.back().data.viewportTest.enable = value;
643   }
644
645   [[nodiscard]] const std::vector<Command>& GetCommands() const
646   {
647     return mCommands;
648   }
649
650   /**
651    * Returns number of draw commands
652    * @return
653    */
654   int GetDrawCallsCount();
655
656   /**
657    * Retrieves state resolve for selected draw call
658    * @param drawCommandIndex
659    */
660   void GetStateForDrawCall(int drawCallIndex);
661
662   /**
663    * Retrieves commands of specified type
664    */
665   std::vector<Command*> GetCommandsByType(CommandTypeMask mask);
666
667 private:
668   TraceCallStack&    mCallStack;
669   TestGlAbstraction& mGlAbstraction;
670
671   std::vector<Command> mCommands;
672 };
673
674 } // namespace Dali
675
676 #endif //DALI_TEST_GRAPHICS_COMMAND_BUFFER_H