Test harness for UBO
[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-pipeline.h"
28 #include "test-graphics-buffer.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 };
51
52 using CommandTypeMask = uint32_t;
53 template<typename T>
54 inline CommandTypeMask operator|(T flags, CommandType bit)
55 {
56   return static_cast<CommandTypeMask>(flags) | static_cast<CommandTypeMask>(bit);
57 }
58
59 /**
60  * @brief Descriptor of single buffer binding within
61  * command buffer.
62  */
63 struct VertexBufferBindingDescriptor
64 {
65   const TestGraphicsBuffer* buffer{nullptr};
66   uint32_t            offset{0u};
67 };
68
69 /**
70  * @brief Descriptor of ix buffer binding within
71  * command buffer.
72  */
73 struct IndexBufferBindingDescriptor
74 {
75   const TestGraphicsBuffer* buffer{nullptr};
76   uint32_t            offset{};
77   Graphics::Format    format{};
78 };
79
80 /**
81  * @brief Descriptor of uniform buffer binding within
82  * command buffer.
83  */
84 struct UniformBufferBindingDescriptor
85 {
86   const TestGraphicsBuffer* buffer{nullptr};
87   uint32_t            binding{0u};
88   uint32_t            offset{0u};
89   bool                emulated; ///<true if UBO is emulated for old gfx API
90 };
91
92 /**
93  * @brief The descriptor of draw call
94  */
95 struct DrawCallDescriptor
96 {
97   /**
98    * @brief Enum specifying type of the draw call
99    */
100   enum class Type
101   {
102     DRAW,
103     DRAW_INDEXED,
104     DRAW_INDEXED_INDIRECT
105   };
106
107   Type type{}; ///< Type of the draw call
108
109   /**
110    * Union contains data for all types of draw calls.
111    */
112   union
113   {
114     /**
115      * @brief Vertex array draw
116      */
117     struct
118     {
119       uint32_t vertexCount;
120       uint32_t instanceCount;
121       uint32_t firstVertex;
122       uint32_t firstInstance;
123     } draw;
124
125     /**
126      * @brief Indexed draw
127      */
128     struct
129     {
130       uint32_t indexCount;
131       uint32_t instanceCount;
132       uint32_t firstIndex;
133       int32_t  vertexOffset;
134       uint32_t firstInstance;
135     } drawIndexed;
136
137     /**
138      * @brief Indexed draw indirect
139      */
140     struct
141     {
142       const TestGraphicsBuffer* buffer;
143       uint32_t            offset;
144       uint32_t            drawCount;
145       uint32_t            stride;
146     } drawIndexedIndirect;
147   };
148 };
149
150 /**
151  * Command structure allocates memory to store a single command
152  */
153 struct Command
154 {
155   Command()
156   {
157   }
158
159   ~Command()
160   {
161   }
162
163   /**
164    * @brief Copy constructor
165    * @param[in] rhs Command
166    */
167   Command(const Command& rhs)
168   {
169     switch(rhs.type)
170     {
171       case CommandType::BIND_VERTEX_BUFFERS:
172       {
173         bindVertexBuffers = rhs.bindVertexBuffers;
174         break;
175       }
176       case CommandType::BIND_INDEX_BUFFER:
177       {
178         bindIndexBuffer = rhs.bindIndexBuffer;
179         break;
180       }
181       case CommandType::BIND_SAMPLERS:
182       {
183         bindSamplers = rhs.bindSamplers;
184         break;
185       }
186       case CommandType::BIND_TEXTURES:
187       {
188         bindTextures = rhs.bindTextures;
189         break;
190       }
191       case CommandType::BIND_PIPELINE:
192       {
193         bindPipeline = rhs.bindPipeline;
194         break;
195       }
196       case CommandType::BIND_UNIFORM_BUFFER:
197       {
198         bindUniformBuffers = rhs.bindUniformBuffers;
199         break;
200       }
201       case CommandType::DRAW:
202       {
203         draw.type = rhs.draw.type;
204         draw.draw = rhs.draw.draw;
205         break;
206       }
207       case CommandType::DRAW_INDEXED:
208       {
209         draw.type        = rhs.draw.type;
210         draw.drawIndexed = rhs.draw.drawIndexed;
211         break;
212       }
213       case CommandType::DRAW_INDEXED_INDIRECT:
214       {
215         draw.type                = rhs.draw.type;
216         draw.drawIndexedIndirect = rhs.draw.drawIndexedIndirect;
217         break;
218       }
219       case CommandType::FLUSH:
220       {
221         // Nothing to do
222         break;
223       }
224     }
225     type = rhs.type;
226   }
227
228   /**
229    * @brief Copy constructor
230    * @param[in] rhs Command
231    */
232   Command(Command&& rhs) noexcept
233   {
234     switch(rhs.type)
235     {
236       case CommandType::BIND_VERTEX_BUFFERS:
237       {
238         bindVertexBuffers = std::move(rhs.bindVertexBuffers);
239         break;
240       }
241       case CommandType::BIND_INDEX_BUFFER:
242       {
243         bindIndexBuffer = rhs.bindIndexBuffer;
244         break;
245       }
246       case CommandType::BIND_UNIFORM_BUFFER:
247       {
248         bindUniformBuffers = std::move(rhs.bindUniformBuffers);
249         break;
250       }
251       case CommandType::BIND_SAMPLERS:
252       {
253         bindSamplers = std::move(rhs.bindSamplers);
254         break;
255       }
256       case CommandType::BIND_TEXTURES:
257       {
258         bindTextures = std::move(rhs.bindTextures);
259         break;
260       }
261       case CommandType::BIND_PIPELINE:
262       {
263         bindPipeline = rhs.bindPipeline;
264         break;
265       }
266       case CommandType::DRAW:
267       {
268         draw.type = rhs.draw.type;
269         draw.draw = rhs.draw.draw;
270         break;
271       }
272       case CommandType::DRAW_INDEXED:
273       {
274         draw.type        = rhs.draw.type;
275         draw.drawIndexed = rhs.draw.drawIndexed;
276         break;
277       }
278       case CommandType::DRAW_INDEXED_INDIRECT:
279       {
280         draw.type                = rhs.draw.type;
281         draw.drawIndexedIndirect = rhs.draw.drawIndexedIndirect;
282         break;
283       }
284       case CommandType::FLUSH:
285       {
286         // Nothing to do
287         break;
288       }
289     }
290     type = rhs.type;
291   }
292
293   CommandType type{CommandType::FLUSH}; ///< Type of command
294
295   union
296   {
297     struct
298     {
299       std::vector<Graphics::TextureBinding> textureBindings;
300     } bindTextures{};
301
302     // BindSampler command
303     struct
304     {
305       std::vector<Graphics::SamplerBinding> samplerBindings;
306     } bindSamplers;
307
308     struct
309     {
310       using Binding = VertexBufferBindingDescriptor;
311       std::vector<Binding> vertexBufferBindings;
312     } bindVertexBuffers;
313
314     struct : public IndexBufferBindingDescriptor
315     {
316     } bindIndexBuffer;
317
318     struct
319     {
320       std::vector<UniformBufferBindingDescriptor> uniformBufferBindings{};
321       UniformBufferBindingDescriptor              standaloneUniformsBufferBinding{};
322     } bindUniformBuffers;
323
324     struct
325     {
326       const TestGraphicsPipeline* pipeline{nullptr};
327     } bindPipeline;
328
329     struct : public DrawCallDescriptor
330     {
331     } draw;
332   };
333 };
334
335
336 class TestGraphicsCommandBuffer : public Graphics::CommandBuffer
337 {
338 public:
339   TestGraphicsCommandBuffer(TraceCallStack& callstack, TestGlAbstraction& glAbstraction);
340   ~TestGraphicsCommandBuffer()
341   {
342
343   }
344
345   void BindVertexBuffers(uint32_t                             firstBinding,
346                          std::vector<const Graphics::Buffer*> buffers,
347                          std::vector<uint32_t>                offsets) override
348   {
349     mCommands.emplace_back();
350     mCommands.back().type = CommandType::BIND_VERTEX_BUFFERS;
351     auto& bindings        = mCommands.back().bindVertexBuffers.vertexBufferBindings;
352     if(bindings.size() < firstBinding + buffers.size())
353     {
354       bindings.resize(firstBinding + buffers.size());
355       auto index = firstBinding;
356       for(auto& buf : buffers)
357       {
358         bindings[index].buffer = static_cast<const TestGraphicsBuffer*>(buf);
359         bindings[index].offset = offsets[index - firstBinding];
360         index++;
361       }
362     }
363     mCallStack.PushCall("BindVertexBuffers", "");
364   }
365
366   void BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings) override
367   {
368     printf("BindUniformBuffers: bindings.size(): %lu\n", bindings.size());
369
370     mCommands.emplace_back();
371     auto& cmd     = mCommands.back();
372     cmd.type      = CommandType::BIND_UNIFORM_BUFFER;
373     auto& bindCmd = cmd.bindUniformBuffers;
374     for(const auto& binding : bindings)
375     {
376       if(binding.buffer)
377       {
378         auto testBuffer = static_cast<const TestGraphicsBuffer*>(binding.buffer);
379         if(testBuffer->IsCPUAllocated()) // standalone uniforms
380         {
381           bindCmd.standaloneUniformsBufferBinding.buffer   = testBuffer;
382           bindCmd.standaloneUniformsBufferBinding.offset   = binding.offset;
383           bindCmd.standaloneUniformsBufferBinding.binding  = binding.binding;
384           bindCmd.standaloneUniformsBufferBinding.emulated = true;
385         }
386         else // Bind regular UBO
387         {
388           // resize binding slots
389           if(binding.binding >= bindCmd.uniformBufferBindings.size())
390           {
391             bindCmd.uniformBufferBindings.resize(binding.binding + 1);
392           }
393           auto& slot    = bindCmd.uniformBufferBindings[binding.binding];
394           slot.buffer   = testBuffer;
395           slot.offset   = binding.offset;
396           slot.binding  = binding.binding;
397           slot.emulated = false;
398         }
399       }
400     }
401     mCallStack.PushCall("BindUniformBuffers", "");
402   }
403
404   void BindPipeline(const Graphics::Pipeline& pipeline) override
405   {
406     mCommands.emplace_back();
407     mCommands.back().type                  = CommandType::BIND_PIPELINE;
408     mCommands.back().bindPipeline.pipeline = static_cast<const TestGraphicsPipeline*>(&pipeline);
409     mCallStack.PushCall("BindPipeline", "");
410   }
411
412   void BindTextures(std::vector<Graphics::TextureBinding>& textureBindings) override
413   {
414     mCommands.emplace_back();
415     mCommands.back().type                         = CommandType::BIND_TEXTURES;
416     mCommands.back().bindTextures.textureBindings = std::move(textureBindings);
417     mCallStack.PushCall("BindTextures", "");
418   }
419
420   void BindSamplers(std::vector<Graphics::SamplerBinding>& samplerBindings) override
421   {
422     mCommands.emplace_back();
423     mCommands.back().bindSamplers.samplerBindings = std::move(samplerBindings);
424     mCallStack.PushCall("BindSamplers", "");
425   }
426
427   void BindPushConstants(void*    data,
428                          uint32_t size,
429                          uint32_t binding) override
430   {
431     mCallStack.PushCall("BindPushConstants", "");
432   }
433
434   void BindIndexBuffer(const Graphics::Buffer& buffer,
435                        uint32_t                offset,
436                        Graphics::Format                  format) override
437   {
438     mCommands.emplace_back();
439     mCommands.back().type                   = CommandType::BIND_INDEX_BUFFER;
440     mCommands.back().bindIndexBuffer.buffer = static_cast<const TestGraphicsBuffer*>(&buffer);
441     mCommands.back().bindIndexBuffer.offset = offset;
442     mCommands.back().bindIndexBuffer.format = format;
443     mCallStack.PushCall("BindIndexBuffer", "");
444   }
445
446   void BeginRenderPass(
447     Graphics::RenderPass&   renderPass,
448     Graphics::RenderTarget& renderTarget,
449     Graphics::Extent2D                renderArea,
450     std::vector<Graphics::ClearValue> clearValues) override
451   {
452     mCallStack.PushCall("BeginRenderPass", "");
453   }
454
455   /**
456    * @brief Ends current render pass
457    *
458    * This command must be issued in order to finalize the render pass.
459    * It's up to the implementation whether anything has to be done but
460    * the Controller may use end RP marker in order to resolve resource
461    * dependencies (for example, to know when target texture is ready
462    * before passing it to another render pass).
463    */
464   void EndRenderPass() override
465   {
466     mCallStack.PushCall("EndRenderPass", "");
467   }
468
469   void Draw(
470     uint32_t vertexCount,
471     uint32_t instanceCount,
472     uint32_t firstVertex,
473     uint32_t firstInstance) override
474   {
475     mCommands.emplace_back();
476     mCommands.back().type  = CommandType::DRAW;
477     auto& cmd              = mCommands.back().draw;
478     cmd.type               = DrawCallDescriptor::Type::DRAW;
479     cmd.draw.vertexCount   = vertexCount;
480     cmd.draw.instanceCount = instanceCount;
481     cmd.draw.firstInstance = firstInstance;
482     cmd.draw.firstVertex   = firstVertex;
483     mCallStack.PushCall("Draw", "");
484   }
485
486   void DrawIndexed(
487     uint32_t indexCount,
488     uint32_t instanceCount,
489     uint32_t firstIndex,
490     int32_t  vertexOffset,
491     uint32_t firstInstance) override
492   {
493     mCommands.emplace_back();
494     mCommands.back().type         = CommandType::DRAW_INDEXED;
495     auto& cmd                     = mCommands.back().draw;
496     cmd.type                      = DrawCallDescriptor::Type::DRAW_INDEXED;
497     cmd.drawIndexed.firstIndex    = firstIndex;
498     cmd.drawIndexed.firstInstance = firstInstance;
499     cmd.drawIndexed.indexCount    = indexCount;
500     cmd.drawIndexed.vertexOffset  = vertexOffset;
501     cmd.drawIndexed.instanceCount = instanceCount;
502     mCallStack.PushCall("DrawIndexed", "");
503   }
504
505   void DrawIndexedIndirect(
506     Graphics::Buffer& buffer,
507     uint32_t          offset,
508     uint32_t          drawCount,
509     uint32_t          stride) override
510   {
511     mCommands.emplace_back();
512     mCommands.back().type             = CommandType::DRAW_INDEXED_INDIRECT;
513     auto& cmd                         = mCommands.back().draw;
514     cmd.type                          = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
515     cmd.drawIndexedIndirect.buffer    = static_cast<const TestGraphicsBuffer*>(&buffer);
516     cmd.drawIndexedIndirect.offset    = offset;
517     cmd.drawIndexedIndirect.drawCount = drawCount;
518     cmd.drawIndexedIndirect.stride    = stride;
519     mCallStack.PushCall("DrawIndexedIndirect", "");
520   }
521
522   void Reset() override
523   {
524     mCommands.clear();
525     mCallStack.PushCall("Reset", "");
526   }
527
528   void SetScissor(Graphics::Extent2D value) override
529   {
530     mCallStack.PushCall("SetScissor", "");
531   }
532
533   void SetScissorTestEnable(bool value) override
534   {
535     mCallStack.PushCall("SetScissorTestEnable", "");
536   }
537
538   void SetViewport(Graphics::Viewport value) override
539   {
540     mCallStack.PushCall("SetViewport", "");
541   }
542
543   void SetViewportEnable(bool value) override
544   {
545     mCallStack.PushCall("SetViewportEnable", "");
546   }
547
548   [[nodiscard]] const std::vector<Command>& GetCommands() const
549   {
550     return mCommands;
551   }
552
553   /**
554    * Returns number of draw commands
555    * @return
556    */
557   int GetDrawCallsCount();
558
559   /**
560    * Retrieves state resolve for selected draw call
561    * @param drawCommandIndex
562    */
563   void GetStateForDrawCall( int drawCallIndex );
564
565   /**
566    * Retrieves commands of specified type
567    */
568   std::vector<Command*> GetCommandsByType( CommandTypeMask mask );
569
570
571 private:
572   TraceCallStack&                       mCallStack;
573   TestGlAbstraction&                    mGlAbstraction;
574   std::vector<Command> mCommands;
575 };
576
577 } // namespace Dali
578
579 #endif //DALI_TEST_GRAPHICS_COMMAND_BUFFER_H