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