[Vulkan] Basic Vulkan backend
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / vulkan-standalone-test.cpp
1 /*
2  * This is the test code that allows to run Vulkan backend
3  * as standalone application. Supports both Xcb and Xlib window
4  * integration. MUST NOT BE COMPILED WITH DALI!
5  */
6
7 // for surface implementation
8 #ifndef VK_USE_PLATFORM_XLIB_KHR
9 #define VK_USE_PLATFORM_XLIB_KHR
10 #endif
11 #ifndef VK_USE_PLATFORM_XCB_KHR
12 #define VK_USE_PLATFORM_XCB_KHR
13 #endif
14
15 #include <glm/glm.hpp>
16 #include <glm/matrix.hpp>
17 #include <glm/vector_relational.hpp>
18 #include <glm/gtc/matrix_transform.hpp>
19
20 using namespace glm;
21
22 #include <dali/integration-api/graphics/vulkan/vulkan-hpp-wrapper.h>
23
24 #include <dali/integration-api/graphics/vulkan/vk-surface-factory.h>
25 #include <dali/integration-api/graphics/graphics.h>
26 #include <xcb/xcb.h>
27 #include <unistd.h>
28
29 // internals
30 #include <dali/graphics/vulkan/vulkan-buffer.h>
31 #include <dali/graphics/vulkan/vulkan-graphics.h>
32 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.h>
33 #include <dali/graphics/vulkan/vulkan-shader.h>
34 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
35 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.h>
36 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-allocator.h>
37 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-handle.h>
38 #include <dali/graphics/vulkan/vulkan-pipeline.h>
39 #include <dali/graphics/vulkan/vulkan-command-pool.h>
40 #include <dali/graphics/vulkan/vulkan-command-buffer.h>
41 #include <dali/graphics/vulkan/vulkan-surface.h>
42 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
43
44 #include "generated/spv-shaders-gen.h"
45
46 #define USE_XLIB 0
47 #include <iostream>
48
49 using Dali::Integration::Graphics::Graphics;
50 using Dali::Integration::Graphics::Vulkan::VkSurfaceFactory;
51 using Dali::Graphics::Vulkan::Buffer;
52 using Dali::Graphics::Vulkan::DeviceMemory;
53 using Dali::Graphics::Vulkan::Shader;
54 using Dali::Graphics::Vulkan::DescriptorSetLayout;
55 using Dali::Graphics::Vulkan::GpuMemoryManager;
56 using Dali::Graphics::Vulkan::GpuMemoryAllocator;
57 using Dali::Graphics::Vulkan::Shader;
58 using Dali::Graphics::Vulkan::ShaderRef;
59 using Dali::Graphics::Vulkan::Pipeline;
60 using Dali::Graphics::Vulkan::PipelineRef;
61 using Dali::Graphics::Vulkan::CommandPool;
62 using Dali::Graphics::Vulkan::CommandBuffer;
63 using Dali::Graphics::Vulkan::DescriptorPool;
64
65 extern std::vector<uint8_t> VSH;
66 extern std::vector<uint8_t> FSH;
67
68 template< typename T, typename... Args >
69 std::unique_ptr< T > MakeUnique(Args&&... args)
70 {
71   return std::unique_ptr< T >(new T(std::forward< Args >(args)...));
72 }
73
74
75 class VkSurfaceXlib : public Dali::Integration::Graphics::Vulkan::VkSurfaceFactory
76 {
77 public:
78   /**
79    * Instantiates surface factory ( should
80    * @param display
81    * @param window
82    */
83   VkSurfaceXlib(Display* display, Window window)
84     : VkSurfaceFactory(), mDisplay(display), mWindow(window)
85   {
86   }
87
88   virtual vk::SurfaceKHR Create(vk::Instance instance, vk::AllocationCallbacks* allocCallbacks,
89                                 vk::PhysicalDevice physicalDevice) const override
90   {
91     vk::XlibSurfaceCreateInfoKHR info;
92     info.setDpy(mDisplay).setWindow(mWindow);
93     auto retval = instance.createXlibSurfaceKHR(info, allocCallbacks).value;
94     return retval;
95   }
96
97 private:
98   Display*       mDisplay;
99   Window         mWindow;
100   vk::SurfaceKHR mSurface;
101 };
102
103 class VkSurfaceXcb : public Dali::Integration::Graphics::Vulkan::VkSurfaceFactory
104 {
105 public:
106   /**
107    * Instantiates surface factory ( should
108    * @param display
109    * @param window
110    */
111   VkSurfaceXcb(xcb_connection_t* connection, xcb_window_t window)
112     : VkSurfaceFactory{}, mConnection(connection), mWindow(window)
113   {
114   }
115
116   virtual vk::SurfaceKHR Create(vk::Instance instance, vk::AllocationCallbacks* allocCallbacks,
117                                 vk::PhysicalDevice physicalDevice) const override
118   {
119     vk::XcbSurfaceCreateInfoKHR info;
120     info.setConnection(mConnection).setWindow(mWindow);
121     auto retval = instance.createXcbSurfaceKHR(info, allocCallbacks).value;
122     return retval;
123   }
124
125 private:
126   xcb_connection_t* mConnection;
127   xcb_window_t      mWindow;
128   vk::SurfaceKHR    mSurface;
129 };
130
131 namespace Test
132 {
133 struct xlib_window_t
134 {
135   uint32_t width{0u};
136   uint32_t height{0u};
137   Window   window{};
138   Display* display{nullptr};
139
140   ~xlib_window_t()
141   {
142     XDestroyWindow(display, window);
143   }
144 };
145
146 std::unique_ptr< xlib_window_t > create_xlib_window(int width, int height)
147 {
148   std::unique_ptr< xlib_window_t > wnd{new xlib_window_t};
149   // 1. Create Window ( done by DALI
150
151   wnd->width         = width;
152   wnd->height        = height;
153   wnd->display       = XOpenDisplay(nullptr);
154   auto defaultScreen = DefaultScreen(wnd->display);
155   wnd->window =
156     XCreateSimpleWindow(wnd->display, RootWindow(wnd->display, defaultScreen), 0, 0, wnd->width,
157                         wnd->height, 1, BlackPixel(wnd->display, defaultScreen),
158                         WhitePixel(wnd->display, defaultScreen));
159
160   XSelectInput(wnd->display, wnd->window, ExposureMask | KeyPressMask);
161   XMapWindow(wnd->display, wnd->window);
162   XSync(wnd->display, false);
163
164   return wnd;
165 }
166
167 struct xcb_window_t
168 {
169   uint32_t          width{0u};
170   uint32_t          height{0u};
171   ::xcb_window_t    window;
172   xcb_connection_t* connection;
173
174   ~xcb_window_t()
175   {
176     xcb_destroy_window(connection, window);
177   }
178 };
179
180 std::unique_ptr< Test::xcb_window_t > create_xcb_window(int width, int height)
181 {
182   std::unique_ptr< Test::xcb_window_t > wnd{new Test::xcb_window_t};
183   // 1. Create Window ( done by DALI
184
185   wnd->width  = width;
186   wnd->height = height;
187
188   int screenNum(0);
189
190   xcb_connection_t*     connection = xcb_connect(NULL, &screenNum);
191   const xcb_setup_t*    setup      = xcb_get_setup(connection);
192   xcb_screen_iterator_t iter       = xcb_setup_roots_iterator(setup);
193   for(int i = 0; i < screenNum; ++i)
194     xcb_screen_next(&iter);
195
196   xcb_screen_t* screen = iter.data;
197   ::xcb_window_t  window = xcb_generate_id(connection);
198
199   uint32_t mask     = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
200   uint32_t values[] = {screen->white_pixel, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS};
201
202   xcb_create_window(connection, XCB_COPY_FROM_PARENT, window, screen->root, 0, 0, wnd->width,
203                     wnd->height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask,
204                     values);
205
206   xcb_map_window(connection, window);
207   const uint32_t coords[] = {100, 100};
208   xcb_configure_window(connection, window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
209   xcb_flush(connection);
210
211   wnd->connection = connection;
212   wnd->window     = window;
213
214   return wnd;
215 }
216 }
217
218 namespace VulkanTest
219 {
220
221 Dali::Graphics::Vulkan::GpuMemoryBlockHandle test_gpu_memory_manager( Dali::Graphics::Vulkan::Graphics& graphics,
222                                          GpuMemoryManager& gpuManager,
223                                          const Dali::Graphics::Vulkan::Handle<Buffer>& buffer )
224 {
225   auto device = graphics.GetDevice();
226   auto& allocator = graphics.GetAllocator();
227
228   auto& gpuAllocator = gpuManager.GetDefaultAllocator();
229   return gpuAllocator.Allocate( buffer, vk::MemoryPropertyFlagBits::eHostVisible );
230 }
231
232 struct UniformData
233 {
234   mat4 modelMat;
235   mat4 viewMat;
236   mat4 projMat;
237   vec4 color;
238 } __attribute__((aligned(16)));
239
240
241 mat4 MVP;
242
243
244
245
246 template <class T>
247 void update_buffer( Dali::Graphics::Vulkan::BufferHandle buffer, T& value )
248 {
249   auto ptr = reinterpret_cast<T*>(buffer->GetMemoryHandle()->Map());
250   *ptr = value;
251   buffer->GetMemoryHandle()->Unmap();
252 }
253
254 void update_translation( Dali::Graphics::Vulkan::BufferHandle buffer )
255 {
256   static float x = 0.0f;
257   x += 0.5f;
258
259   UniformData ub;
260   ub.modelMat = mat4{1.0f};
261   ub.modelMat = glm::translate( ub.modelMat, vec3( x, x, 0.0f ));
262   ub.modelMat = glm::rotate( ub.modelMat, glm::radians( x ), glm::vec3( 0.0f, 0.0f, 1.0f) );
263   ub.viewMat = lookAt( vec3( 0.0f, 0.0f, 10.0f ),
264                         vec3( 0.0f, 0.0f, 0.0f ),
265                         vec3( 0.0f, 1.0f, 0.0f ) );
266
267   glm::mat4 clip( 1.0f, 0.0f, 0.0f, 0.0f,
268                   0.0f, -1.0f, 0.0f, 0.0f,
269                   0.0f, 0.0f, 0.5f, 0.0f,
270                   0.0f, 0.0f, 0.5f, 1.0f );
271
272   ub.projMat = clip * ortho( 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 100.0f );
273   ub.color = vec4( x / 640.0f, x / 480.0f, 1.0f, 1.0f );
274   update_buffer( buffer, ub );
275 }
276
277 Dali::Graphics::Vulkan::BufferHandle create_uniform_buffer( Dali::Graphics::Vulkan::Graphics& gr )
278 {
279   // create uniform buffer
280   auto uniformBuffer = Buffer::New( gr, sizeof(UniformData), Buffer::Type::UNIFORM );
281
282   // allocate memory
283   auto memory = gr.GetDeviceMemoryManager().GetDefaultAllocator().Allocate( uniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible );
284
285   // bind memory
286   uniformBuffer->BindMemory( memory );
287
288   auto ub = reinterpret_cast<UniformData*>(memory->Map());
289
290   ub->modelMat = mat4{1.0f};
291   //ub->modelMat = glm::translate( ub->modelMat, vec3( 0.0f, 0.0f, 0.0f ));
292
293   ub->viewMat = lookAt( vec3( 0.0f, 0.0f, 10.0f ),
294                         vec3( 0.0f, 0.0f, 0.0f ),
295                         vec3( 0.0f, 1.0f, 0.0f ) );
296
297   glm::mat4 clip( 1.0f, 0.0f, 0.0f, 0.0f,
298                   0.0f, -1.0f, 0.0f, 0.0f,
299                   0.0f, 0.0f, 0.5f, 0.0f,
300                   0.0f, 0.0f, 0.5f, 1.0f );
301
302   ub->projMat = clip * ortho( 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 100.0f );
303   ub->color = vec4( 0.0f, 1.0f, 1.0f, 1.0f );
304
305
306   MVP = ub->projMat * ub->viewMat * ub->modelMat;
307
308   memory->Unmap();
309
310   return uniformBuffer;
311 }
312
313 Dali::Graphics::Vulkan::Handle<DescriptorPool>
314 create_descriptor_pool( Dali::Graphics::Vulkan::Graphics& gr )
315 {
316   vk::DescriptorPoolSize size;
317   size.setDescriptorCount( 1024 ).setType( vk::DescriptorType::eUniformBuffer );
318
319   // TODO: how to organize this???
320   auto pool = DescriptorPool::New( gr,
321     vk::DescriptorPoolCreateInfo{}.
322       setMaxSets( 1024 ).
323       setPoolSizeCount(1).setPPoolSizes(&size));
324   return pool;
325 }
326
327 void test_handle()
328 {
329   /*
330   using namespace Dali::Graphics::Vulkan;
331   GpuMemoryBlockHandle handle( new GpuMemoryBlock() );
332
333   decltype(handle) handle2 = handle;
334   handle.GetRefCount();*/
335 }
336
337 PipelineRef
338 create_pipeline( Dali::Graphics::Vulkan::Graphics& graphics,
339                       Dali::Graphics::Vulkan::ShaderRef vertexShader,
340                       Dali::Graphics::Vulkan::ShaderRef fragmentShader
341                       )
342 {
343   using namespace Dali::Graphics::Vulkan;
344   auto pipelineInfo = vk::GraphicsPipelineCreateInfo{};
345   auto pipeline = Pipeline::New( graphics, pipelineInfo );
346
347   pipeline->SetShader( vertexShader, Shader::Type::VERTEX );
348   pipeline->SetShader( fragmentShader, Shader::Type::FRAGMENT );
349   pipeline->SetViewport( 0, 0, 640, 480 );
350   pipeline->SetVertexInputState(
351     std::vector<vk::VertexInputAttributeDescription>{vk::VertexInputAttributeDescription{}.
352                                            setBinding( 0 ).
353                                            setOffset( 0 ).
354                                            setLocation( 0 ).
355                                            setFormat( vk::Format::eR32G32B32Sfloat )},
356     std::vector<vk::VertexInputBindingDescription>{vk::VertexInputBindingDescription{}.
357                                            setBinding( 0 ).
358                                            setStride( sizeof(float)*3  ).
359                                            setInputRate( vk::VertexInputRate::eVertex)}
360   );
361   pipeline->SetInputAssemblyState( vk::PrimitiveTopology::eTriangleList, false );
362
363   if( !pipeline->Compile() )
364   {
365     pipeline.Reset();
366   }
367   return pipeline;
368 }
369
370 int RunTestMain()
371 {
372
373 #if USE_XLIB == 1
374   auto window = Test::create_xlib_window(640, 480);
375   auto surfaceFactory =
376       std::unique_ptr< VkSurfaceXlib >{new VkSurfaceXlib{window->display, window->window}};
377 #else
378   auto window         = Test::create_xcb_window(640, 480);
379   auto surfaceFactory =
380          std::unique_ptr<VkSurfaceXcb>{new VkSurfaceXcb{window->connection, window->window}};
381 #endif
382
383
384   auto graphics = MakeUnique<Graphics>();
385   auto fbid = graphics->Create( std::move(surfaceFactory) );
386
387   // access internal implementation
388   auto& gr = graphics->GetImplementation<Dali::Graphics::Vulkan::Graphics>();
389
390   // GPU memory manager
391   auto& memmgr = gr.GetDeviceMemoryManager();
392
393   const vec3 VERTICES[] =
394           {
395             {0.0f, 0.0f, 0.0f},
396             {320.0f, 0.0f, 0.0f},
397             {0.0f, 160.0f, 0.0f},
398           };
399
400
401
402
403   // shaders
404   auto vertexShader = Shader::New( gr, VSH_CODE.data(), VSH_CODE.size() );
405   vertexShader->SetDescriptorSetLayout( 0, vk::DescriptorSetLayoutCreateInfo{}.
406     setBindingCount( 1 ).
407     setPBindings( std::vector<vk::DescriptorSetLayoutBinding>{
408                     vk::DescriptorSetLayoutBinding{}.
409                                                       setBinding( 0 ).
410                                                       setStageFlags( vk::ShaderStageFlagBits::eVertex ).
411                                                       setDescriptorType( vk::DescriptorType::eUniformBuffer ).
412                                                       setDescriptorCount( 1 )
413                   }.data()
414     ));
415
416   auto fragmentShader = Shader::New( gr, FSH_CODE.data(), FSH_CODE.size() );
417
418   // buffer
419   auto vertexBuffer = Buffer::New( gr, sizeof(float)*3*3, Buffer::Type::VERTEX );
420
421   auto descriptorPool = create_descriptor_pool( gr );
422   auto descriptorSet = descriptorPool->AllocateDescriptorSets( vk::DescriptorSetAllocateInfo{}
423   .setPSetLayouts( vertexShader->GetDescriptorSetLayouts().data() )
424   .setDescriptorSetCount( static_cast<uint32_t>(vertexShader->GetDescriptorSetLayouts().size())));
425
426
427
428   auto& gpuManager = gr.GetDeviceMemoryManager();
429
430   auto bufferMemory = test_gpu_memory_manager( gr, gpuManager, vertexBuffer );
431   vertexBuffer->BindMemory( bufferMemory );
432
433   auto ptr = static_cast<uint8_t*>(bufferMemory->Map());
434   std::copy( reinterpret_cast<const uint8_t*>(VERTICES), reinterpret_cast<const uint8_t*>(VERTICES)+(sizeof(float)*9), ptr);
435   bufferMemory->Unmap();
436
437   auto pipeline = create_pipeline( gr, vertexShader, fragmentShader );
438
439   auto commandPool = CommandPool::New( gr );
440
441   auto uniformBuffer = create_uniform_buffer( gr );
442
443   descriptorSet[0]->WriteUniformBuffer( 0, uniformBuffer, 0, uniformBuffer->GetSize() );
444
445   // get new buffer
446   auto cmdDraw = commandPool->NewCommandBuffer( false );
447
448   // begin recording
449   cmdDraw->Begin( vk::CommandBufferUsageFlagBits::eRenderPassContinue);
450
451   // vertex buffer
452   cmdDraw->BindVertexBuffer( 0, vertexBuffer, 0 );
453
454   // pipeline
455   cmdDraw->BindGraphicsPipeline( pipeline );
456
457   // descriptor sets
458   cmdDraw->BindDescriptorSets( descriptorSet, 0 );
459
460   // do draw
461   cmdDraw->Draw( 3, 1, 0, 0 );
462
463   // finish
464   cmdDraw->End();
465
466
467
468   bool running = true;
469
470   while( running )
471   {
472     graphics->PreRender( fbid );
473     // queue submit draw
474
475     auto cmdbuf = gr.GetSurface( fbid ).GetCurrentCommandBuffer();
476
477     // get command buffer for current frame and execute the draw call
478     cmdbuf->ExecuteCommands( { cmdDraw } );
479
480
481     graphics->PostRender( fbid );
482
483     update_translation( uniformBuffer );
484   }
485   return 0;
486 }
487 }
488
489 int main()
490 {
491   VulkanTest::RunTestMain();
492 }