Test harness for UBO
[platform/core/uifw/dali-core.git] / automated-tests / src / dali / dali-test-suite-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     mCommands.emplace_back();
369     auto& cmd     = mCommands.back();
370     cmd.type      = CommandType::BIND_UNIFORM_BUFFER;
371     auto& bindCmd = cmd.bindUniformBuffers;
372     for(const auto& binding : bindings)
373     {
374       if(binding.buffer)
375       {
376         auto testBuffer = static_cast<const TestGraphicsBuffer*>(binding.buffer);
377         if(testBuffer->IsCPUAllocated()) // standalone uniforms
378         {
379           bindCmd.standaloneUniformsBufferBinding.buffer   = testBuffer;
380           bindCmd.standaloneUniformsBufferBinding.offset   = binding.offset;
381           bindCmd.standaloneUniformsBufferBinding.binding  = binding.binding;
382           bindCmd.standaloneUniformsBufferBinding.emulated = true;
383         }
384         else // Bind regular UBO
385         {
386           // resize binding slots
387           if(binding.binding >= bindCmd.uniformBufferBindings.size())
388           {
389             bindCmd.uniformBufferBindings.resize(binding.binding + 1);
390           }
391           auto& slot    = bindCmd.uniformBufferBindings[binding.binding];
392           slot.buffer   = testBuffer;
393           slot.offset   = binding.offset;
394           slot.binding  = binding.binding;
395           slot.emulated = false;
396         }
397       }
398     }
399     mCallStack.PushCall("BindUniformBuffers", "");
400   }
401
402   void BindPipeline(const Graphics::Pipeline& pipeline) override
403   {
404     mCommands.emplace_back();
405     mCommands.back().type                  = CommandType::BIND_PIPELINE;
406     mCommands.back().bindPipeline.pipeline = static_cast<const TestGraphicsPipeline*>(&pipeline);
407     mCallStack.PushCall("BindPipeline", "");
408   }
409
410   void BindTextures(std::vector<Graphics::TextureBinding>& textureBindings) override
411   {
412     mCommands.emplace_back();
413     mCommands.back().type                         = CommandType::BIND_TEXTURES;
414     mCommands.back().bindTextures.textureBindings = std::move(textureBindings);
415     mCallStack.PushCall("BindTextures", "");
416   }
417
418   void BindSamplers(std::vector<Graphics::SamplerBinding>& samplerBindings) override
419   {
420     mCommands.emplace_back();
421     mCommands.back().bindSamplers.samplerBindings = std::move(samplerBindings);
422     mCallStack.PushCall("BindSamplers", "");
423   }
424
425   void BindPushConstants(void*    data,
426                          uint32_t size,
427                          uint32_t binding) override
428   {
429     mCallStack.PushCall("BindPushConstants", "");
430   }
431
432   void BindIndexBuffer(const Graphics::Buffer& buffer,
433                        uint32_t                offset,
434                        Graphics::Format                  format) override
435   {
436     mCommands.emplace_back();
437     mCommands.back().type                   = CommandType::BIND_INDEX_BUFFER;
438     mCommands.back().bindIndexBuffer.buffer = static_cast<const TestGraphicsBuffer*>(&buffer);
439     mCommands.back().bindIndexBuffer.offset = offset;
440     mCommands.back().bindIndexBuffer.format = format;
441     mCallStack.PushCall("BindIndexBuffer", "");
442   }
443
444   void BeginRenderPass(
445     Graphics::RenderPass&   renderPass,
446     Graphics::RenderTarget& renderTarget,
447     Graphics::Extent2D                renderArea,
448     std::vector<Graphics::ClearValue> clearValues) override
449   {
450     mCallStack.PushCall("BeginRenderPass", "");
451   }
452
453   /**
454    * @brief Ends current render pass
455    *
456    * This command must be issued in order to finalize the render pass.
457    * It's up to the implementation whether anything has to be done but
458    * the Controller may use end RP marker in order to resolve resource
459    * dependencies (for example, to know when target texture is ready
460    * before passing it to another render pass).
461    */
462   void EndRenderPass() override
463   {
464     mCallStack.PushCall("EndRenderPass", "");
465   }
466
467   void Draw(
468     uint32_t vertexCount,
469     uint32_t instanceCount,
470     uint32_t firstVertex,
471     uint32_t firstInstance) override
472   {
473     mCommands.emplace_back();
474     mCommands.back().type  = CommandType::DRAW;
475     auto& cmd              = mCommands.back().draw;
476     cmd.type               = DrawCallDescriptor::Type::DRAW;
477     cmd.draw.vertexCount   = vertexCount;
478     cmd.draw.instanceCount = instanceCount;
479     cmd.draw.firstInstance = firstInstance;
480     cmd.draw.firstVertex   = firstVertex;
481     mCallStack.PushCall("Draw", "");
482   }
483
484   void DrawIndexed(
485     uint32_t indexCount,
486     uint32_t instanceCount,
487     uint32_t firstIndex,
488     int32_t  vertexOffset,
489     uint32_t firstInstance) override
490   {
491     mCommands.emplace_back();
492     mCommands.back().type         = CommandType::DRAW_INDEXED;
493     auto& cmd                     = mCommands.back().draw;
494     cmd.type                      = DrawCallDescriptor::Type::DRAW_INDEXED;
495     cmd.drawIndexed.firstIndex    = firstIndex;
496     cmd.drawIndexed.firstInstance = firstInstance;
497     cmd.drawIndexed.indexCount    = indexCount;
498     cmd.drawIndexed.vertexOffset  = vertexOffset;
499     cmd.drawIndexed.instanceCount = instanceCount;
500     mCallStack.PushCall("DrawIndexed", "");
501   }
502
503   void DrawIndexedIndirect(
504     Graphics::Buffer& buffer,
505     uint32_t          offset,
506     uint32_t          drawCount,
507     uint32_t          stride) override
508   {
509     mCommands.emplace_back();
510     mCommands.back().type             = CommandType::DRAW_INDEXED_INDIRECT;
511     auto& cmd                         = mCommands.back().draw;
512     cmd.type                          = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
513     cmd.drawIndexedIndirect.buffer    = static_cast<const TestGraphicsBuffer*>(&buffer);
514     cmd.drawIndexedIndirect.offset    = offset;
515     cmd.drawIndexedIndirect.drawCount = drawCount;
516     cmd.drawIndexedIndirect.stride    = stride;
517     mCallStack.PushCall("DrawIndexedIndirect", "");
518   }
519
520   void Reset() override
521   {
522     mCommands.clear();
523     mCallStack.PushCall("Reset", "");
524   }
525
526   void SetScissor(Graphics::Extent2D value) override
527   {
528     mCallStack.PushCall("SetScissor", "");
529   }
530
531   void SetScissorTestEnable(bool value) override
532   {
533     mCallStack.PushCall("SetScissorTestEnable", "");
534   }
535
536   void SetViewport(Graphics::Viewport value) override
537   {
538     mCallStack.PushCall("SetViewport", "");
539   }
540
541   void SetViewportEnable(bool value) override
542   {
543     mCallStack.PushCall("SetViewportEnable", "");
544   }
545
546   [[nodiscard]] const std::vector<Command>& GetCommands() const
547   {
548     return mCommands;
549   }
550
551   /**
552    * Returns number of draw commands
553    * @return
554    */
555   int GetDrawCallsCount();
556
557   /**
558    * Retrieves state resolve for selected draw call
559    * @param drawCommandIndex
560    */
561   void GetStateForDrawCall( int drawCallIndex );
562
563   /**
564    * Retrieves commands of specified type
565    */
566   std::vector<Command*> GetCommandsByType( CommandTypeMask mask );
567
568
569 private:
570   TraceCallStack&                       mCallStack;
571   TestGlAbstraction&                    mGlAbstraction;
572   std::vector<Command> mCommands;
573 };
574
575 } // namespace Dali
576
577 #endif //DALI_TEST_GRAPHICS_COMMAND_BUFFER_H