Merge changes I8a148074,I6532af40,I6cb64283,Id615bd9f into devel/vulkan
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / vulkan-graphics.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // INTERNAL INCLUDES
19 #include <dali/graphics/vulkan/vulkan-graphics.h>
20 #include <dali/graphics/vulkan/vulkan-command-pool.h>
21 #include <dali/graphics/vulkan/vulkan-queue.h>
22 #include <dali/graphics/vulkan/vulkan-surface.h>
23 #include <dali/integration-api/graphics/vulkan/vk-surface-factory.h>
24 #include <dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.h>
25
26 #include <dali/graphics/vulkan/vulkan-buffer.h>
27 #include <dali/graphics/vulkan/vulkan-image.h>
28 #include <dali/graphics/vulkan/vulkan-pipeline.h>
29 #include <dali/graphics/vulkan/vulkan-shader.h>
30 #include <dali/graphics/vulkan/vulkan-descriptor-set.h>
31 #include <dali/graphics/vulkan/vulkan-framebuffer.h>
32 #include <dali/graphics/vulkan/vulkan-graphics-controller.h>
33
34 #include <dali/graphics-api/graphics-api-controller.h>
35
36 #ifndef VK_KHR_XLIB_SURFACE_EXTENSION_NAME
37 #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
38 #endif
39
40 #ifndef VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
41 #define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface"
42 #endif
43
44 #ifndef VK_KHR_XCB_SURFACE_EXTENSION_NAME
45 #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
46 #endif
47
48 #include <iostream>
49
50 namespace Dali
51 {
52 namespace Graphics
53 {
54 using VkSurfaceFactory = Dali::Integration::Graphics::Vulkan::VkSurfaceFactory;
55 namespace Vulkan
56 {
57
58 const auto VALIDATION_LAYERS = std::vector< const char* >{
59
60   //"VK_LAYER_LUNARG_screenshot",           // screenshot
61   //"VK_LAYER_RENDERDOC_Capture",
62   //"VK_LAYER_LUNARG_parameter_validation", // parameter
63   //"VK_LAYER_LUNARG_vktrace",              // vktrace ( requires vktrace connection )
64   //"VK_LAYER_LUNARG_monitor",             // monitor
65   "VK_LAYER_LUNARG_swapchain",           // swapchain
66   "VK_LAYER_GOOGLE_threading",           // threading
67   "VK_LAYER_LUNARG_api_dump",            // api
68   "VK_LAYER_LUNARG_object_tracker",      // objects
69   "VK_LAYER_LUNARG_core_validation",     // core
70   "VK_LAYER_GOOGLE_unique_objects",      // unique objects
71   "VK_LAYER_GOOGLE_unique_objects",      // unique objects
72   "VK_LAYER_LUNARG_standard_validation", // standard
73 };
74
75 Graphics::Graphics() = default;
76
77 Graphics::~Graphics() = default;
78 #pragma GCC diagnostic push
79 #pragma GCC diagnostic ignored "-Wframe-larger-than="
80
81 Platform Graphics::GetDefaultPlatform() const
82 {
83 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
84   mPlatform = Platform::WAYLAND;
85 #elif VK_USE_PLATFORM_XCB_KHR
86   mPlatform = Platform::XCB;
87 #elif VK_USE_PLATFORM_XLIB_KHR
88   mPlatform =  Platform::XLIB;
89 #else
90   return mPlatform;
91 #endif
92 }
93
94 Dali::Graphics::API::Controller& Graphics::GetController()
95 {
96   if(!mGfxController)
97   {
98     mGfxController = Dali::Graphics::Vulkan::Controller::New(*this);
99   }
100
101   return *mGfxController.get();
102 }
103
104 std::vector<const char*> Graphics::PrepareDefaultInstanceExtensions()
105 {
106   auto extensions = vk::enumerateInstanceExtensionProperties();
107
108   std::string extensionName;
109
110   bool xlibAvailable    { false };
111   bool xcbAvailable     { false };
112   bool waylandAvailable { false };
113
114   for( auto&& ext : extensions.value )
115   {
116     extensionName = ext.extensionName;
117     if( extensionName == VK_KHR_XCB_SURFACE_EXTENSION_NAME )
118     {
119       xcbAvailable = true;
120     }
121     else if( extensionName == VK_KHR_XLIB_SURFACE_EXTENSION_NAME )
122     {
123       xlibAvailable = true;
124     }
125     else if( extensionName == VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME )
126     {
127       waylandAvailable = true;
128     }
129   }
130
131   std::vector<const char*> retval;
132
133   // depending on the platform validate extensions
134   auto platform = GetDefaultPlatform();
135
136   if( platform != Platform::UNDEFINED )
137   {
138     if (platform == Platform::XCB && xcbAvailable)
139     {
140       retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
141     }
142     else if (platform == Platform::XLIB && xlibAvailable)
143     {
144       retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
145     }
146     else if (platform == Platform::WAYLAND && waylandAvailable)
147     {
148       retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
149     }
150   }
151   else // try to determine the platform based on available extensions
152   {
153     if (xcbAvailable)
154     {
155       mPlatform = Platform::XCB;
156       retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
157     }
158     else if (xlibAvailable)
159     {
160       mPlatform = Platform::XLIB;
161       retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
162     }
163     else if (waylandAvailable)
164     {
165       mPlatform = Platform::WAYLAND;
166       retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
167     }
168     else
169     {
170       // can't determine the platform!
171       mPlatform = Platform::UNDEFINED;
172     }
173   }
174
175   // other essential extensions
176   retval.push_back( VK_KHR_SURFACE_EXTENSION_NAME );
177   retval.push_back( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );
178
179   return retval;
180 }
181
182 void Graphics::Create()
183 {
184
185   auto extensions = PrepareDefaultInstanceExtensions();
186
187   auto layers = vk::enumerateInstanceLayerProperties();
188   std::vector<const char*> validationLayers;
189   for( auto&& reqLayer : VALIDATION_LAYERS )
190   {
191     for( auto&& prop : layers.value )
192     {
193       std::cout << prop.layerName << std::endl;
194       if( std::string(prop.layerName) == reqLayer )
195       {
196         validationLayers.push_back(reqLayer);
197       }
198     }
199   }
200
201   CreateInstance(extensions, validationLayers);
202   PreparePhysicalDevice();
203 }
204
205 void Graphics::CreateInstance( const std::vector<const char*>& extensions, const std::vector<const char*>& validationLayers )
206 {
207   auto info = vk::InstanceCreateInfo{};
208
209   info.setEnabledExtensionCount(U32(extensions.size()))
210       .setPpEnabledExtensionNames(extensions.data())
211       .setEnabledLayerCount(U32(validationLayers.size()))
212       //.setEnabledLayerCount(0)
213       .setPpEnabledLayerNames(validationLayers.data());
214
215   mInstance = VkAssert(vk::createInstance(info, *mAllocator));
216 }
217
218 void Graphics::DestroyInstance()
219 {
220   if(mInstance)
221   {
222     mInstance.destroy(*mAllocator);
223     mInstance = nullptr;
224   }
225 }
226
227
228 void Graphics::PreparePhysicalDevice()
229 {
230   auto devices = VkAssert(mInstance.enumeratePhysicalDevices());
231   assert(devices.size() > 0 && "No Vulkan supported device found!");
232
233   // if only one, pick first
234   mPhysicalDevice = nullptr;
235   if(devices.size() == 1)
236   {
237     mPhysicalDevice = devices[0];
238   }
239   else // otherwise look for one which is a graphics device
240   {
241     for(auto& device : devices)
242     {
243       auto properties =device.getProperties();
244       if(properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ||
245          properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu)
246       {
247         mPhysicalDevice = device;
248         break;
249       }
250     }
251   }
252
253   assert(mPhysicalDevice && "No suitable Physical Device found!");
254
255   GetPhysicalDeviceProperties();
256
257   GetQueueFamilyProperties();
258
259   mDeviceMemoryManager = GpuMemoryManager::New( *this );
260 }
261 #pragma GCC diagnostic pop
262
263 #pragma GCC diagnostic push
264 #pragma GCC diagnostic ignored "-Wframe-larger-than="
265 void Graphics::GetPhysicalDeviceProperties()
266 {
267   // store data on heap to keep object smaller
268   mPhysicalDeviceProperties =
269     MakeUnique<vk::PhysicalDeviceProperties>(mPhysicalDevice.getProperties());
270   mPhysicalDeviceMemoryProperties =
271     MakeUnique<vk::PhysicalDeviceMemoryProperties>(mPhysicalDevice.getMemoryProperties());
272   mPhysicalDeviceFeatures =
273     MakeUnique<vk::PhysicalDeviceFeatures>(mPhysicalDevice.getFeatures());
274 }
275 #pragma GCC diagnostic pop
276
277 void Graphics::GetQueueFamilyProperties()
278 {
279   mQueueFamilyProperties = std::move(mPhysicalDevice.getQueueFamilyProperties());
280 }
281
282 FBID Graphics::CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory)
283 {
284   // create surface from the factory
285   auto surfaceRef = Surface::New( *this, std::move(surfaceFactory) );
286
287   if( surfaceRef->Create() )
288   {
289
290     // map surface to FBID
291     auto fbid = ++mBaseFBID;
292     mSurfaceFBIDMap[fbid] = SwapchainSurfacePair{ SwapchainRef{}, surfaceRef };
293     return fbid;
294   }
295   return -1;
296 }
297
298 SwapchainRef Graphics::CreateSwapchainForSurface( SurfaceRef surface )
299 {
300   auto swapchain = Swapchain::New( *this,
301                                    GetGraphicsQueue(0u),
302                                    surface, 2, 0 );
303
304   // store swapchain in the correct pair
305   for( auto&& val : mSurfaceFBIDMap )
306   {
307     if( val.second.surface == surface )
308     {
309       val.second.swapchain = swapchain;
310       break;
311     }
312   }
313
314   return swapchain;
315 }
316
317 SwapchainRef Graphics::GetSwapchainForSurface( SurfaceRef surface )
318 {
319   for( auto&& val : mSurfaceFBIDMap )
320   {
321     if( val.second.surface == surface )
322     {
323       return val.second
324                 .swapchain;
325     }
326   }
327   return SwapchainRef();
328 }
329
330 SwapchainRef Graphics::GetSwapchainForFBID( FBID surfaceId )
331 {
332   if(surfaceId == 0)
333   {
334     return mSurfaceFBIDMap.begin()->second.swapchain;
335   }
336   return mSurfaceFBIDMap[surfaceId].swapchain;
337 }
338
339 #pragma GCC diagnostic push
340 #pragma GCC diagnostic ignored "-Wframe-larger-than="
341 std::vector< vk::DeviceQueueCreateInfo > Graphics::GetQueueCreateInfos()
342 {
343   // surface is needed in order to find a family that supports presentation to this surface
344   // fixme: assuming all surfaces will be compatible with the queue family
345   assert(!mSurfaceFBIDMap.empty() &&
346          "At least one surface has to be created before creating VkDevice!");
347
348   auto queueInfos = std::vector< vk::DeviceQueueCreateInfo >{};
349
350   constexpr uint8_t MAX_QUEUE_TYPES = 3;
351   // find suitable family for each type of queue
352   uint32_t familyIndexType[MAX_QUEUE_TYPES];
353   std::fill(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES], -1u);
354
355   // Graphics
356   auto& graphicsFamily = familyIndexType[0];
357
358   // Transfer
359   auto& transferFamily = familyIndexType[1];
360
361   // Transfer
362   auto& presentFamily = familyIndexType[2];
363
364   auto queueFamilyIndex = 0u;
365   for(auto& prop : mQueueFamilyProperties)
366   {
367     if((prop.queueFlags & vk::QueueFlagBits::eGraphics) && graphicsFamily == -1u)
368     {
369       graphicsFamily = queueFamilyIndex;
370     }
371     if((prop.queueFlags & vk::QueueFlagBits::eTransfer) && transferFamily == -1u)
372     {
373       transferFamily = queueFamilyIndex;
374     }
375     if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.surface->GetSurfaceKHR())
376            .value &&
377        presentFamily == -1u)
378     {
379       presentFamily = queueFamilyIndex;
380     }
381     ++queueFamilyIndex;
382   }
383
384   assert(graphicsFamily != -1u && "No queue family that supports graphics operations!");
385   assert(transferFamily != -1u && "No queue family that supports transfer operations!");
386   assert(presentFamily != -1u && "No queue family that supports present operations!");
387
388   // todo: we may require that the family must be same for all types of operations, it makes
389   // easier to handle synchronisation related issues.
390
391   // sort queues
392   std::sort(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES]);
393
394   // allocate all queues from graphics family
395   uint32_t prevQueueFamilyIndex = -1u;
396
397   for(auto i = 0u; i < MAX_QUEUE_TYPES; ++i)
398   {
399     auto& familyIndex = familyIndexType[i];
400     if(prevQueueFamilyIndex == familyIndex)
401     {
402       continue;
403     }
404
405     auto& queueCount = mQueueFamilyProperties[familyIndex].queueCount;
406
407     // fill queue create info for the family.
408     // note the priorities are not being set as local pointer will out of scope, this
409     // will be fixed by the caller function
410     auto info = vk::DeviceQueueCreateInfo{}
411                     .setPQueuePriorities(nullptr)
412                     .setQueueCount(queueCount)
413                     .setQueueFamilyIndex(familyIndex);
414     queueInfos.push_back(info);
415     prevQueueFamilyIndex = familyIndex;
416   }
417
418   return queueInfos;
419 }
420 #pragma GCC diagnostic pop
421
422 #pragma GCC diagnostic push
423 #pragma GCC diagnostic ignored "-Wframe-larger-than="
424 void Graphics::CreateDevice()
425 {
426   auto queueInfos = GetQueueCreateInfos();
427   {
428     auto maxQueueCountPerFamily = 0u;
429     for( auto&& info : queueInfos )
430     {
431       maxQueueCountPerFamily = std::max( info.queueCount, maxQueueCountPerFamily );
432     }
433
434     auto priorities = std::vector<float>( maxQueueCountPerFamily );
435     std::fill( priorities.begin(), priorities.end(), 1.0f );
436
437     for( auto& info : queueInfos )
438     {
439       info.setPQueuePriorities( priorities.data() );
440     }
441
442     auto extensions = std::vector< const char* >{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
443
444     auto info = vk::DeviceCreateInfo{};
445     info.setEnabledExtensionCount(U32(extensions.size()))
446         .setPpEnabledExtensionNames(extensions.data())
447         .setPEnabledFeatures(&(*mPhysicalDeviceFeatures))
448         .setPQueueCreateInfos(queueInfos.data())
449         .setQueueCreateInfoCount(U32(queueInfos.size()));
450
451     mDevice = VkAssert(mPhysicalDevice.createDevice(info, *mAllocator));
452   }
453
454   // create Queue objects
455   for(auto& queueInfo : queueInfos)
456   {
457     for(auto i = 0u; i < queueInfo.queueCount; ++i)
458     {
459       auto queue = mDevice.getQueue(queueInfo.queueFamilyIndex, i);
460
461       // based on family push queue instance into right array
462       auto flags = mQueueFamilyProperties[queueInfo.queueFamilyIndex].queueFlags;
463       if(flags & vk::QueueFlagBits::eGraphics)
464       {
465         mGraphicsQueues.emplace_back(
466           MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
467       }
468       if(flags & vk::QueueFlagBits::eTransfer)
469       {
470         mTransferQueues.emplace_back(
471           MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
472       }
473       if(flags & vk::QueueFlagBits::eCompute)
474       {
475         mComputeQueues.emplace_back(
476           MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
477       }
478
479       // todo: present queue
480     }
481   }
482 }
483 #pragma GCC diagnostic pop
484
485 vk::Device Graphics::GetDevice() const
486 {
487   return mDevice;
488 }
489
490 vk::PhysicalDevice Graphics::GetPhysicalDevice() const
491 {
492   return mPhysicalDevice;
493 }
494
495 vk::Instance Graphics::GetInstance() const
496 {
497   return mInstance;
498 }
499
500 const vk::AllocationCallbacks& Graphics::GetAllocator() const
501 {
502   return *mAllocator;
503 }
504
505 Queue& Graphics::GetGraphicsQueue(uint32_t index) const
506 {
507   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
508   // this will change in the future
509   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
510
511   return *mGraphicsQueues[0].get(); // will be mGraphicsQueues[index]
512 }
513
514 Queue& Graphics::GetTransferQueue(uint32_t index) const
515 {
516   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
517   // this will change in the future
518   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
519
520   return *mTransferQueues[0].get(); // will be mGraphicsQueues[index]
521 }
522
523 Queue& Graphics::GetComputeQueue(uint32_t index) const
524 {
525   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
526   // this will change in the future
527   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
528
529   return *mComputeQueues[0].get(); // will be mGraphicsQueues[index]
530 }
531
532 Queue& Graphics::GetPresentQueue() const
533 {
534   // fixme: should be a dedicated presentation queue
535   return GetGraphicsQueue(0);
536 }
537
538 Handle< CommandPool > Graphics::CreateCommandPool(const vk::CommandPoolCreateInfo& info)
539 {
540   auto cmdpool = CommandPool::New( *this, vk::CommandPoolCreateInfo{}.
541                                                                        setQueueFamilyIndex( 0u ).
542                                                                        setFlags( vk::CommandPoolCreateFlagBits::eResetCommandBuffer ) );
543   return cmdpool;
544 }
545
546 SurfaceRef Graphics::GetSurface( FBID surfaceId )
547 {
548   // TODO: FBID == 0 means default framebuffer, but there should be no
549   // such thing as default framebuffer.
550   if( surfaceId == 0 )
551   {
552     return mSurfaceFBIDMap.begin()->second.surface;
553   }
554   return mSurfaceFBIDMap[surfaceId].surface;
555 }
556
557 // TODO: all this stuff should go into some vulkan cache
558
559 void Graphics::AddBuffer( Handle<Buffer> buffer )
560 {
561   mBuffersCache.push_back( buffer );
562 }
563
564 void Graphics::AddImage( Handle<Image> image )
565 {
566   mImageCache.push_back( image );
567 }
568
569 void Graphics::AddPipeline( Handle<Pipeline> pipeline )
570 {
571   mPipelineCache.push_back( pipeline );
572 }
573
574 void Graphics::AddShader( Handle<Shader> shader )
575 {
576   mShaderCache.push_back( shader );
577 }
578
579 void Graphics::AddCommandPool( Handle<CommandPool> pool )
580 {
581   mCommandPoolCache.push_back( pool );
582 }
583
584 void Graphics::AddDescriptorPool( Handle<DescriptorPool> pool )
585 {
586   mDescriptorPoolCache.push_back( pool );
587 }
588
589 void Graphics::AddFramebuffer( Handle<Framebuffer> framebuffer )
590 {
591   mFramebufferCache.push_back( framebuffer );
592 }
593
594 void Graphics::RemoveBuffer( Buffer& buffer )
595 {
596   auto index = 0u;
597   for( auto&& iter : mBuffersCache )
598   {
599     if( &*iter == &buffer )
600     {
601       iter.Reset();
602       mBuffersCache.erase( mBuffersCache.begin()+index );
603       return;
604     }
605   }
606 }
607
608 void Graphics::RemoveShader( Shader& shader )
609 {
610   auto index = 0u;
611   for( auto&& iter : mShaderCache )
612   {
613     if( &*iter == &shader )
614     {
615       iter.Reset();
616       mShaderCache.erase( mShaderCache.begin()+index );
617       return;
618     }
619     ++index;
620   }
621 }
622
623 void Graphics::RemoveCommandPool( CommandPool& commandPool )
624 {
625   NotImplemented();
626 }
627
628 void Graphics::RemoveDescriptorPool( std::unique_ptr<DescriptorPool> pool )
629 {
630   NotImplemented();
631 }
632
633 ShaderRef Graphics::FindShader( vk::ShaderModule shaderModule )
634 {
635   for( auto&& iter : mShaderCache )
636   {
637     if( iter->GetVkShaderModule() == shaderModule )
638     {
639       return Handle<Shader>(&*iter);
640     }
641   }
642   return Handle<Shader>();
643 }
644
645 ImageRef Graphics::FindImage( vk::Image image )
646 {
647   for( auto&& iter : mImageCache )
648   {
649     if( iter->GetVkImage() == image )
650     {
651       return ImageRef(&*iter);
652     }
653   }
654   return ImageRef();
655 }
656
657
658
659 } // namespace Vulkan
660 } // namespace Graphics
661 } // namespace Dali