Merge branch 'devel/master' into devel/graphics
[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         bindVertexBuffers = rhs.bindVertexBuffers;
178         break;
179       }
180       case CommandType::BIND_INDEX_BUFFER:
181       {
182         bindIndexBuffer = rhs.bindIndexBuffer;
183         break;
184       }
185       case CommandType::BIND_SAMPLERS:
186       {
187         bindSamplers = rhs.bindSamplers;
188         break;
189       }
190       case CommandType::BIND_TEXTURES:
191       {
192         bindTextures = rhs.bindTextures;
193         break;
194       }
195       case CommandType::BIND_PIPELINE:
196       {
197         bindPipeline = rhs.bindPipeline;
198         break;
199       }
200       case CommandType::BIND_UNIFORM_BUFFER:
201       {
202         bindUniformBuffers = rhs.bindUniformBuffers;
203         break;
204       }
205       case CommandType::DRAW:
206       {
207         draw.type = rhs.draw.type;
208         draw.draw = rhs.draw.draw;
209         break;
210       }
211       case CommandType::DRAW_INDEXED:
212       {
213         draw.type        = rhs.draw.type;
214         draw.drawIndexed = rhs.draw.drawIndexed;
215         break;
216       }
217       case CommandType::DRAW_INDEXED_INDIRECT:
218       {
219         draw.type                = rhs.draw.type;
220         draw.drawIndexedIndirect = rhs.draw.drawIndexedIndirect;
221         break;
222       }
223       case CommandType::FLUSH:
224       {
225         // Nothing to do
226         break;
227       }
228       case CommandType::SET_SCISSOR:
229       {
230         scissor.region = rhs.scissor.region;
231         break;
232       }
233       case CommandType::SET_SCISSOR_TEST:
234       {
235         scissorTest.enable = rhs.scissorTest.enable;
236         break;
237       }
238       case CommandType::SET_VIEWPORT:
239       {
240         viewport.region = rhs.viewport.region;
241         break;
242       }
243       case CommandType::SET_VIEWPORT_TEST:
244       {
245         viewportTest.enable = rhs.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         bindVertexBuffers = std::move(rhs.bindVertexBuffers);
263         break;
264       }
265       case CommandType::BIND_INDEX_BUFFER:
266       {
267         bindIndexBuffer = rhs.bindIndexBuffer;
268         break;
269       }
270       case CommandType::BIND_UNIFORM_BUFFER:
271       {
272         bindUniformBuffers = std::move(rhs.bindUniformBuffers);
273         break;
274       }
275       case CommandType::BIND_SAMPLERS:
276       {
277         bindSamplers = std::move(rhs.bindSamplers);
278         break;
279       }
280       case CommandType::BIND_TEXTURES:
281       {
282         bindTextures = std::move(rhs.bindTextures);
283         break;
284       }
285       case CommandType::BIND_PIPELINE:
286       {
287         bindPipeline = rhs.bindPipeline;
288         break;
289       }
290       case CommandType::DRAW:
291       {
292         draw.type = rhs.draw.type;
293         draw.draw = rhs.draw.draw;
294         break;
295       }
296       case CommandType::DRAW_INDEXED:
297       {
298         draw.type        = rhs.draw.type;
299         draw.drawIndexed = rhs.draw.drawIndexed;
300         break;
301       }
302       case CommandType::DRAW_INDEXED_INDIRECT:
303       {
304         draw.type                = rhs.draw.type;
305         draw.drawIndexedIndirect = rhs.draw.drawIndexedIndirect;
306         break;
307       }
308       case CommandType::FLUSH:
309       {
310         // Nothing to do
311         break;
312       }
313       case CommandType::SET_SCISSOR:
314       {
315         scissor.region = rhs.scissor.region;
316         break;
317       }
318       case CommandType::SET_SCISSOR_TEST:
319       {
320         scissorTest.enable = rhs.scissorTest.enable;
321         break;
322       }
323       case CommandType::SET_VIEWPORT:
324       {
325         viewport.region = rhs.viewport.region;
326         break;
327       }
328       case CommandType::SET_VIEWPORT_TEST:
329       {
330         viewportTest.enable = rhs.viewportTest.enable;
331         break;
332       }
333     }
334     type = rhs.type;
335   }
336
337   CommandType type{CommandType::FLUSH}; ///< Type of command
338
339   union
340   {
341     struct
342     {
343       std::vector<Graphics::TextureBinding> textureBindings;
344     } bindTextures{};
345
346     // BindSampler command
347     struct
348     {
349       std::vector<Graphics::SamplerBinding> samplerBindings;
350     } bindSamplers;
351
352     struct
353     {
354       using Binding = VertexBufferBindingDescriptor;
355       std::vector<Binding> vertexBufferBindings;
356     } bindVertexBuffers;
357
358     struct : public IndexBufferBindingDescriptor
359     {
360     } bindIndexBuffer;
361
362     struct
363     {
364       std::vector<UniformBufferBindingDescriptor> uniformBufferBindings{};
365       UniformBufferBindingDescriptor              standaloneUniformsBufferBinding{};
366     } bindUniformBuffers;
367
368     struct
369     {
370       const TestGraphicsPipeline* pipeline{nullptr};
371     } bindPipeline;
372
373     struct : public DrawCallDescriptor
374     {
375     } draw;
376
377     struct
378     {
379       Graphics::Rect2D region;
380     } scissor;
381     struct
382     {
383       bool enable;
384     } scissorTest;
385     struct
386     {
387       Graphics::Viewport region;
388     } viewport;
389     struct
390     {
391       bool enable;
392     } viewportTest;
393   };
394 };
395
396 class TestGraphicsCommandBuffer : public Graphics::CommandBuffer
397 {
398 public:
399   TestGraphicsCommandBuffer(TraceCallStack& callstack, TestGlAbstraction& glAbstraction);
400   ~TestGraphicsCommandBuffer()
401   {
402   }
403
404   void BindVertexBuffers(uint32_t                             firstBinding,
405                          std::vector<const Graphics::Buffer*> buffers,
406                          std::vector<uint32_t>                offsets) override
407   {
408     mCommands.emplace_back();
409     mCommands.back().type = CommandType::BIND_VERTEX_BUFFERS;
410     auto& bindings        = mCommands.back().bindVertexBuffers.vertexBufferBindings;
411     if(bindings.size() < firstBinding + buffers.size())
412     {
413       bindings.resize(firstBinding + buffers.size());
414       auto index = firstBinding;
415       for(auto& buf : buffers)
416       {
417         bindings[index].buffer = static_cast<const TestGraphicsBuffer*>(buf);
418         bindings[index].offset = offsets[index - firstBinding];
419         index++;
420       }
421     }
422     mCallStack.PushCall("BindVertexBuffers", "");
423   }
424
425   void BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings) override
426   {
427     mCommands.emplace_back();
428     auto& cmd     = mCommands.back();
429     cmd.type      = CommandType::BIND_UNIFORM_BUFFER;
430     auto& bindCmd = cmd.bindUniformBuffers;
431     for(const auto& binding : bindings)
432     {
433       if(binding.buffer)
434       {
435         auto testBuffer = static_cast<const TestGraphicsBuffer*>(binding.buffer);
436         if(testBuffer->IsCPUAllocated()) // standalone uniforms
437         {
438           bindCmd.standaloneUniformsBufferBinding.buffer   = testBuffer;
439           bindCmd.standaloneUniformsBufferBinding.offset   = binding.offset;
440           bindCmd.standaloneUniformsBufferBinding.binding  = binding.binding;
441           bindCmd.standaloneUniformsBufferBinding.emulated = true;
442         }
443         else // Bind regular UBO
444         {
445           // resize binding slots
446           if(binding.binding >= bindCmd.uniformBufferBindings.size())
447           {
448             bindCmd.uniformBufferBindings.resize(binding.binding + 1);
449           }
450           auto& slot    = bindCmd.uniformBufferBindings[binding.binding];
451           slot.buffer   = testBuffer;
452           slot.offset   = binding.offset;
453           slot.binding  = binding.binding;
454           slot.emulated = false;
455         }
456       }
457     }
458     mCallStack.PushCall("BindUniformBuffers", "");
459   }
460
461   void BindPipeline(const Graphics::Pipeline& pipeline) override
462   {
463     mCommands.emplace_back();
464     mCommands.back().type                  = CommandType::BIND_PIPELINE;
465     mCommands.back().bindPipeline.pipeline = static_cast<const TestGraphicsPipeline*>(&pipeline);
466     mCallStack.PushCall("BindPipeline", "");
467   }
468
469   void BindTextures(std::vector<Graphics::TextureBinding>& textureBindings) override
470   {
471     mCommands.emplace_back();
472     mCommands.back().type                         = CommandType::BIND_TEXTURES;
473     mCommands.back().bindTextures.textureBindings = std::move(textureBindings);
474     mCallStack.PushCall("BindTextures", "");
475   }
476
477   void BindSamplers(std::vector<Graphics::SamplerBinding>& samplerBindings) override
478   {
479     mCommands.emplace_back();
480     mCommands.back().bindSamplers.samplerBindings = std::move(samplerBindings);
481     mCallStack.PushCall("BindSamplers", "");
482   }
483
484   void BindPushConstants(void*    data,
485                          uint32_t size,
486                          uint32_t binding) override
487   {
488     mCallStack.PushCall("BindPushConstants", "");
489   }
490
491   void BindIndexBuffer(const Graphics::Buffer& buffer,
492                        uint32_t                offset,
493                        Graphics::Format        format) override
494   {
495     mCommands.emplace_back();
496     mCommands.back().type                   = CommandType::BIND_INDEX_BUFFER;
497     mCommands.back().bindIndexBuffer.buffer = static_cast<const TestGraphicsBuffer*>(&buffer);
498     mCommands.back().bindIndexBuffer.offset = offset;
499     mCommands.back().bindIndexBuffer.format = format;
500     mCallStack.PushCall("BindIndexBuffer", "");
501   }
502
503   void BeginRenderPass(
504     Graphics::RenderPass&             renderPass,
505     Graphics::RenderTarget&           renderTarget,
506     Graphics::Extent2D                renderArea,
507     std::vector<Graphics::ClearValue> clearValues) override
508   {
509     mCallStack.PushCall("BeginRenderPass", "");
510   }
511
512   /**
513    * @brief Ends current render pass
514    *
515    * This command must be issued in order to finalize the render pass.
516    * It's up to the implementation whether anything has to be done but
517    * the Controller may use end RP marker in order to resolve resource
518    * dependencies (for example, to know when target texture is ready
519    * before passing it to another render pass).
520    */
521   void EndRenderPass() override
522   {
523     mCallStack.PushCall("EndRenderPass", "");
524   }
525
526   void Draw(
527     uint32_t vertexCount,
528     uint32_t instanceCount,
529     uint32_t firstVertex,
530     uint32_t firstInstance) override
531   {
532     mCommands.emplace_back();
533     mCommands.back().type  = CommandType::DRAW;
534     auto& cmd              = mCommands.back().draw;
535     cmd.type               = DrawCallDescriptor::Type::DRAW;
536     cmd.draw.vertexCount   = vertexCount;
537     cmd.draw.instanceCount = instanceCount;
538     cmd.draw.firstInstance = firstInstance;
539     cmd.draw.firstVertex   = firstVertex;
540     mCallStack.PushCall("Draw", "");
541   }
542
543   void DrawIndexed(
544     uint32_t indexCount,
545     uint32_t instanceCount,
546     uint32_t firstIndex,
547     int32_t  vertexOffset,
548     uint32_t firstInstance) override
549   {
550     mCommands.emplace_back();
551     mCommands.back().type         = CommandType::DRAW_INDEXED;
552     auto& cmd                     = mCommands.back().draw;
553     cmd.type                      = DrawCallDescriptor::Type::DRAW_INDEXED;
554     cmd.drawIndexed.firstIndex    = firstIndex;
555     cmd.drawIndexed.firstInstance = firstInstance;
556     cmd.drawIndexed.indexCount    = indexCount;
557     cmd.drawIndexed.vertexOffset  = vertexOffset;
558     cmd.drawIndexed.instanceCount = instanceCount;
559     mCallStack.PushCall("DrawIndexed", "");
560   }
561
562   void DrawIndexedIndirect(
563     Graphics::Buffer& buffer,
564     uint32_t          offset,
565     uint32_t          drawCount,
566     uint32_t          stride) override
567   {
568     mCommands.emplace_back();
569     mCommands.back().type             = CommandType::DRAW_INDEXED_INDIRECT;
570     auto& cmd                         = mCommands.back().draw;
571     cmd.type                          = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
572     cmd.drawIndexedIndirect.buffer    = static_cast<const TestGraphicsBuffer*>(&buffer);
573     cmd.drawIndexedIndirect.offset    = offset;
574     cmd.drawIndexedIndirect.drawCount = drawCount;
575     cmd.drawIndexedIndirect.stride    = stride;
576     mCallStack.PushCall("DrawIndexedIndirect", "");
577   }
578
579   void Reset() override
580   {
581     mCommands.clear();
582     mCallStack.PushCall("Reset", "");
583   }
584
585   void SetScissor(Graphics::Rect2D value) override
586   {
587     TraceCallStack::NamedParams params;
588     params["x"] << value.x;
589     params["y"] << value.y;
590     params["width"] << value.width;
591     params["height"] << value.height;
592     mCallStack.PushCall("SetScissor", params.str(), params);
593
594     mCommands.emplace_back();
595     mCommands.back().type           = CommandType::SET_SCISSOR;
596     mCommands.back().scissor.region = value;
597   }
598
599   void SetScissorTestEnable(bool value) override
600   {
601     TraceCallStack::NamedParams params;
602     params["value"] << (value ? "T" : "F");
603     mCallStack.PushCall("SetScissorTestEnable", params.str(), params);
604
605     mCommands.emplace_back();
606     mCommands.back().type               = CommandType::SET_SCISSOR_TEST;
607     mCommands.back().scissorTest.enable = value;
608   }
609
610   void SetViewport(Graphics::Viewport value) override
611   {
612     TraceCallStack::NamedParams params;
613     params["x"] << value.x;
614     params["y"] << value.y;
615     params["width"] << value.width;
616     params["height"] << value.height;
617     params["minDepth"] << value.minDepth;
618     params["maxDepth"] << value.maxDepth;
619     mCallStack.PushCall("SetViewport", params.str(), params);
620
621     mCommands.emplace_back();
622     mCommands.back().type            = CommandType::SET_VIEWPORT;
623     mCommands.back().viewport.region = value;
624   }
625
626   void SetViewportEnable(bool value) override
627   {
628     TraceCallStack::NamedParams params;
629     params["value"] << (value ? "T" : "F");
630     mCallStack.PushCall("SetViewportEnable", params.str(), params);
631
632     mCommands.emplace_back();
633     mCommands.back().type                = CommandType::SET_VIEWPORT_TEST;
634     mCommands.back().viewportTest.enable = value;
635   }
636
637   [[nodiscard]] const std::vector<Command>& GetCommands() const
638   {
639     return mCommands;
640   }
641
642   /**
643    * Returns number of draw commands
644    * @return
645    */
646   int GetDrawCallsCount();
647
648   /**
649    * Retrieves state resolve for selected draw call
650    * @param drawCommandIndex
651    */
652   void GetStateForDrawCall(int drawCallIndex);
653
654   /**
655    * Retrieves commands of specified type
656    */
657   std::vector<Command*> GetCommandsByType(CommandTypeMask mask);
658
659 private:
660   TraceCallStack&    mCallStack;
661   TestGlAbstraction& mGlAbstraction;
662
663   std::vector<Command> mCommands;
664 };
665
666 } // namespace Dali
667
668 #endif //DALI_TEST_GRAPHICS_COMMAND_BUFFER_H