202c364d826001d49c7f66f419af5007b051395d
[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 #include <dali/graphics/vulkan/vulkan-sampler.h>
35 #include <dali/graphics/vulkan/vulkan-resource-cache.h>
36 #include <dali/graphics/vulkan/vulkan-debug.h>
37 #include <dali/graphics-api/graphics-api-controller.h>
38
39 #ifndef VK_KHR_XLIB_SURFACE_EXTENSION_NAME
40 #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
41 #endif
42
43 #ifndef VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
44 #define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface"
45 #endif
46
47 #ifndef VK_KHR_XCB_SURFACE_EXTENSION_NAME
48 #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
49 #endif
50
51 namespace Dali
52 {
53 namespace Graphics
54 {
55 using VkSurfaceFactory = Dali::Integration::Graphics::Vulkan::VkSurfaceFactory;
56 namespace Vulkan
57 {
58
59 const auto VALIDATION_LAYERS = std::vector< const char* >{
60
61   //"VK_LAYER_LUNARG_screenshot",           // screenshot
62   "VK_LAYER_RENDERDOC_Capture",
63   "VK_LAYER_LUNARG_parameter_validation", // parameter
64   //"VK_LAYER_LUNARG_vktrace",              // vktrace ( requires vktrace connection )
65   //"VK_LAYER_LUNARG_monitor",             // monitor
66   "VK_LAYER_LUNARG_swapchain",           // swapchain
67   "VK_LAYER_GOOGLE_threading",           // threading
68   "VK_LAYER_LUNARG_api_dump",            // api
69   "VK_LAYER_LUNARG_object_tracker",      // objects
70   "VK_LAYER_LUNARG_core_validation",     // core
71   "VK_LAYER_GOOGLE_unique_objects",      // unique objects
72   "VK_LAYER_GOOGLE_unique_objects",      // unique objects
73   "VK_LAYER_LUNARG_standard_validation", // standard
74 };
75
76 Graphics::Graphics() = default;
77 Graphics::~Graphics() = default;
78
79 // Create methods -----------------------------------------------------------------------------------------------
80 void Graphics::Create()
81 {
82
83   auto extensions = PrepareDefaultInstanceExtensions();
84
85   auto layers = vk::enumerateInstanceLayerProperties();
86   std::vector<const char*> validationLayers;
87   for( auto&& reqLayer : VALIDATION_LAYERS )
88   {
89     for( auto&& prop : layers.value )
90     {
91       DALI_LOG_STREAM( gVulkanFilter, Debug::General, prop.layerName );
92       if( std::string(prop.layerName) == reqLayer )
93       {
94         validationLayers.push_back(reqLayer);
95       }
96     }
97   }
98
99   CreateInstance(extensions, validationLayers);
100   PreparePhysicalDevice();
101 }
102
103 #pragma GCC diagnostic push
104 #pragma GCC diagnostic ignored "-Wframe-larger-than="
105 void Graphics::CreateDevice()
106 {
107   auto queueInfos = GetQueueCreateInfos();
108   {
109     auto maxQueueCountPerFamily = 0u;
110     for( auto&& info : queueInfos )
111     {
112       maxQueueCountPerFamily = std::max( info.queueCount, maxQueueCountPerFamily );
113     }
114
115     auto priorities = std::vector<float>( maxQueueCountPerFamily );
116     std::fill( priorities.begin(), priorities.end(), 1.0f );
117
118     for( auto& info : queueInfos )
119     {
120       info.setPQueuePriorities( priorities.data() );
121     }
122
123     std::vector< const char* > extensions{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
124
125     auto info = vk::DeviceCreateInfo{};
126     info.setEnabledExtensionCount(U32(extensions.size()))
127             .setPpEnabledExtensionNames(extensions.data())
128             .setPEnabledFeatures(&(*mPhysicalDeviceFeatures))
129             .setPQueueCreateInfos(queueInfos.data())
130             .setQueueCreateInfoCount(U32(queueInfos.size()));
131
132     mDevice = VkAssert(mPhysicalDevice.createDevice(info, *mAllocator));
133   }
134
135   // create Queue objects
136   for(auto& queueInfo : queueInfos)
137   {
138     for(auto i = 0u; i < queueInfo.queueCount; ++i)
139     {
140       auto queue = mDevice.getQueue(queueInfo.queueFamilyIndex, i);
141
142       // based on family push queue instance into right array
143       auto flags = mQueueFamilyProperties[queueInfo.queueFamilyIndex].queueFlags;
144       if(flags & vk::QueueFlagBits::eGraphics)
145       {
146         mGraphicsQueues.emplace_back(
147                 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
148       }
149       if(flags & vk::QueueFlagBits::eTransfer)
150       {
151         mTransferQueues.emplace_back(
152                 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
153       }
154       if(flags & vk::QueueFlagBits::eCompute)
155       {
156         mComputeQueues.emplace_back(
157                 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
158       }
159
160       // todo: present queue
161     }
162   }
163
164   mPipelineDatabase = std::make_unique<PipelineCache>( *this );
165   mResourceCacheMap[std::this_thread::get_id()] = MakeUnique<ResourceCache>();
166 }
167 #pragma GCC diagnostic pop
168
169 void Graphics::GetPhysicalDeviceProperties()
170 {
171   // store data on heap to keep object smaller
172   mPhysicalDeviceProperties =
173     MakeUnique<vk::PhysicalDeviceProperties>(mPhysicalDevice.getProperties());
174   mPhysicalDeviceMemoryProperties =
175     MakeUnique<vk::PhysicalDeviceMemoryProperties>(mPhysicalDevice.getMemoryProperties());
176   mPhysicalDeviceFeatures =
177     MakeUnique<vk::PhysicalDeviceFeatures>(mPhysicalDevice.getFeatures());
178 }
179
180 void Graphics::GetQueueFamilyProperties()
181 {
182   mQueueFamilyProperties = mPhysicalDevice.getQueueFamilyProperties();
183 }
184
185 FBID Graphics::CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory)
186 {
187   // create surface from the factory
188   auto surfaceRef = Surface::New( *this, std::move(surfaceFactory) );
189
190   if( surfaceRef->Create() )
191   {
192
193     // map surface to FBID
194     auto fbid = ++mBaseFBID;
195     mSurfaceFBIDMap[fbid] = SwapchainSurfacePair{ RefCountedSwapchain{}, surfaceRef };
196     return fbid;
197   }
198   return -1;
199 }
200
201 RefCountedSwapchain Graphics::CreateSwapchainForSurface( RefCountedSurface surface )
202 {
203   auto swapchain = Swapchain::New( *this,
204                                    GetGraphicsQueue(0u),
205                                    surface, 4, 0 );
206
207   // store swapchain in the correct pair
208   for( auto&& val : mSurfaceFBIDMap )
209   {
210     if( val.second.surface == surface )
211     {
212       val.second.swapchain = swapchain;
213       break;
214     }
215   }
216
217   return swapchain;
218 }
219
220 RefCountedShader Graphics::CreateShader()
221 {
222   NotImplemented()
223 }
224
225 RefCountedPipeline Graphics::CreatePipeline()
226 {
227   NotImplemented()
228 }
229
230 RefCountedFence Graphics::CreateFence( const vk::FenceCreateInfo& fenceCreateInfo )
231 {
232   auto refCountedFence = Fence::New(*this);
233
234   VkAssert(mDevice.createFence(&fenceCreateInfo, mAllocator.get(), refCountedFence->Ref()));
235
236   return refCountedFence;
237 }
238
239 RefCountedBuffer Graphics::CreateBuffer(size_t size, BufferType type)
240 {
241   auto usageFlags = vk::BufferUsageFlags{};
242
243   switch ( type ) {
244     case BufferType::VERTEX: {
245       usageFlags |= vk::BufferUsageFlagBits::eVertexBuffer;
246       break;
247     };
248     case BufferType::INDEX: {
249       usageFlags |= vk::BufferUsageFlagBits::eIndexBuffer;
250       break;
251     };
252     case BufferType::UNIFORM: {
253       usageFlags |= vk::BufferUsageFlagBits::eUniformBuffer;
254       break;
255     };
256     case BufferType::SHADER_STORAGE: {
257       usageFlags |= vk::BufferUsageFlagBits::eStorageBuffer;
258       break;
259     };
260   }
261
262   auto info = vk::BufferCreateInfo{};
263   info.setSharingMode(vk::SharingMode::eExclusive);
264   info.setSize(size);
265   info.setUsage(usageFlags | vk::BufferUsageFlagBits::eTransferDst);
266
267   auto refCountedBuffer = Buffer::New(*this, info);
268
269   VkAssert(mDevice.createBuffer(&info, mAllocator.get(), refCountedBuffer->Ref()));
270
271   AddBuffer(refCountedBuffer);
272
273   return refCountedBuffer;
274 }
275
276 RefCountedBuffer Graphics::CreateBuffer( const vk::BufferCreateInfo& bufferCreateInfo )
277 {
278   auto refCountedBuffer = Buffer::New(*this, bufferCreateInfo);
279
280   VkAssert(mDevice.createBuffer(&bufferCreateInfo, mAllocator.get(), refCountedBuffer->Ref()));
281
282   AddBuffer(refCountedBuffer);
283
284   return refCountedBuffer;
285 }
286
287 RefCountedFramebuffer Graphics::CreateFramebuffer()
288 {
289   NotImplemented()
290 }
291
292 RefCountedImage Graphics::CreateImage()
293 {
294   NotImplemented()
295 }
296
297 RefCountedImageView Graphics::CreateImageView()
298 {
299   NotImplemented()
300 }
301
302 RefCountedDescriptorPool Graphics::CreateDescriptorPool()
303 {
304   NotImplemented()
305 }
306
307 RefCountedCommandPool Graphics::CreateCommandPool(const vk::CommandPoolCreateInfo& info)
308 {
309   return CommandPool::New( *this,
310                            vk::CommandPoolCreateInfo{}.setQueueFamilyIndex( 0u )
311                                                       .setFlags( vk::CommandPoolCreateFlagBits::eResetCommandBuffer ) );
312 }
313
314 RefCountedCommandBuffer Graphics::CreateCommandBuffer()
315 {
316   NotImplemented()
317 }
318
319 std::vector<RefCountedCommandBuffer> Graphics::CreateCommandBuffers()
320 {
321   NotImplemented()
322 }
323
324 RefCountedGpuMemoryBlock Graphics::CreateGpuMemoryBlock()
325 {
326   NotImplemented()
327 }
328
329 RefCountedDescriptorSet Graphics::CreateDescriptorSet()
330 {
331   NotImplemented()
332 }
333
334 RefCountedSampler Graphics::CreateSampler()
335 {
336   NotImplemented()
337 }
338 // --------------------------------------------------------------------------------------------------------------
339
340 // Actions ------------------------------------------------------------------------------------------------------
341 vk::Result Graphics::WaitForFence( RefCountedFence fence, uint32_t timeout )
342 {
343   return mDevice.waitForFences(1, *fence, VK_TRUE, timeout);
344 }
345 #pragma GCC diagnostic pop
346
347 vk::Result Graphics::WaitForFences( const std::vector<RefCountedFence>& fences, bool waitAll, uint32_t timeout )
348 {
349   std::vector<vk::Fence> vkFenceHandles{};
350   std::transform(fences.begin(),
351                  fences.end(),
352                  std::back_inserter(vkFenceHandles),
353                  [](RefCountedFence entry){ return entry->GetVkHandle(); });
354
355     auto priorities = std::vector<float>( maxQueueCountPerFamily );
356     std::fill( priorities.begin(), priorities.end(), 1.0f );
357
358   return mDevice.waitForFences(vkFenceHandles, vk::Bool32(waitAll), timeout);
359 }
360
361 vk::Result Graphics::ResetFence( RefCountedFence fence )
362 {
363   return mDevice.resetFences(1, *fence);
364 }
365
366 vk::Result Graphics::ResetFences( const std::vector<RefCountedFence>& fences )
367 {
368   std::vector<vk::Fence> vkFenceHandles{};
369   std::transform(fences.begin(),
370                  fences.end(),
371                  std::back_inserter(vkFenceHandles),
372                  [](RefCountedFence entry){ return entry->GetVkHandle(); });
373
374   return mDevice.resetFences(vkFenceHandles);
375 }
376 // --------------------------------------------------------------------------------------------------------------
377
378 // Getters ------------------------------------------------------------------------------------------------------
379 RefCountedSurface Graphics::GetSurface( FBID surfaceId )
380 {
381   // TODO: FBID == 0 means default framebuffer, but there should be no
382   // such thing as default framebuffer.
383   if( surfaceId == 0 )
384   {
385     return mSurfaceFBIDMap.begin()->second.surface;
386   }
387   return mSurfaceFBIDMap[surfaceId].surface;
388 }
389
390 RefCountedSwapchain Graphics::GetSwapchainForSurface( RefCountedSurface surface )
391 {
392   for( auto&& val : mSurfaceFBIDMap )
393   {
394     if( val.second.surface == surface )
395     {
396       return val.second
397               .swapchain;
398     }
399   }
400   return RefCountedSwapchain();
401 }
402
403 RefCountedSwapchain Graphics::GetSwapchainForFBID( FBID surfaceId )
404 {
405   if(surfaceId == 0)
406   {
407     return mSurfaceFBIDMap.begin()->second.swapchain;
408   }
409   return mSurfaceFBIDMap[surfaceId].swapchain;
410 }
411 #pragma GCC diagnostic pop
412
413 vk::Device Graphics::GetDevice() const
414 {
415   return mDevice;
416 }
417
418 vk::PhysicalDevice Graphics::GetPhysicalDevice() const
419 {
420   return mPhysicalDevice;
421 }
422
423 vk::Instance Graphics::GetInstance() const
424 {
425   return mInstance;
426 }
427
428 const vk::AllocationCallbacks& Graphics::GetAllocator() const
429 {
430   return *mAllocator;
431 }
432
433 GpuMemoryManager& Graphics::GetDeviceMemoryManager() const
434 {
435   return *mDeviceMemoryManager;
436 }
437
438 const vk::PhysicalDeviceMemoryProperties& Graphics::GetMemoryProperties() const
439 {
440   return *mPhysicalDeviceMemoryProperties;
441 }
442
443 Queue& Graphics::GetGraphicsQueue(uint32_t index) const
444 {
445   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
446   // this will change in the future
447   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
448
449   return *mGraphicsQueues[0]; // will be mGraphicsQueues[index]
450 }
451
452 Queue& Graphics::GetTransferQueue(uint32_t index) const
453 {
454   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
455   // this will change in the future
456   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
457
458   return *mTransferQueues[0]; // will be mGraphicsQueues[index]
459 }
460
461 Queue& Graphics::GetComputeQueue(uint32_t index) const
462 {
463   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
464   // this will change in the future
465   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
466
467   return *mComputeQueues[0]; // will be mGraphicsQueues[index]
468 }
469
470 Queue& Graphics::GetPresentQueue() const
471 {
472   // fixme: should be a dedicated presentation queue
473   return GetGraphicsQueue(0);
474 }
475
476 Platform Graphics::GetDefaultPlatform() const
477 {
478 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
479   mPlatform = Platform::WAYLAND;
480 #elif VK_USE_PLATFORM_XCB_KHR
481   mPlatform = Platform::XCB;
482 #elif VK_USE_PLATFORM_XLIB_KHR
483   mPlatform =  Platform::XLIB;
484 #else
485   return mPlatform;
486 #endif
487 }
488
489 Dali::Graphics::API::Controller& Graphics::GetController()
490 {
491   if(!mGfxController)
492   {
493     mGfxController = Dali::Graphics::VulkanAPI::Controller::New(*this);
494   }
495
496   return *mGfxController;
497 }
498
499 PipelineCache& Graphics::GetPipelineCache()
500 {
501   return *mPipelineDatabase;
502 }
503 // --------------------------------------------------------------------------------------------------------------
504
505 // Cache manipulation methods -----------------------------------------------------------------------------------
506 void Graphics::AddBuffer( Handle<Buffer> buffer )
507 {
508   GetResourceCache(std::this_thread::get_id())->AddBuffer(std::move(buffer));
509 }
510
511 void Graphics::AddImage( Handle<Image> image )
512 {
513   GetResourceCache(std::this_thread::get_id())->AddImage(std::move(image));
514 }
515
516 void Graphics::AddShader( Handle<Shader> shader )
517 {
518   GetResourceCache(std::this_thread::get_id())->AddShader(std::move(shader));
519 }
520
521 void Graphics::AddCommandPool( Handle<CommandPool> pool )
522 {
523   GetResourceCache(std::this_thread::get_id())->AddCommandPool(std::move(pool));
524 }
525
526 void Graphics::AddDescriptorPool( Handle<DescriptorPool> pool )
527 {
528   GetResourceCache(std::this_thread::get_id())->AddDescriptorPool(std::move(pool));
529 }
530
531 void Graphics::AddFramebuffer( Handle<Framebuffer> framebuffer )
532 {
533   GetResourceCache(std::this_thread::get_id())->AddFramebuffer(std::move(framebuffer));
534 }
535
536 RefCountedShader Graphics::FindShader( vk::ShaderModule shaderModule )
537 {
538   return GetResourceCache(std::this_thread::get_id())->FindShader(shaderModule);
539 }
540
541 RefCountedImage Graphics::FindImage( vk::Image image )
542 {
543   return GetResourceCache(std::this_thread::get_id())->FindImage(image);
544 }
545
546 void Graphics::RemoveBuffer( Buffer& buffer )
547 {
548   GetResourceCache(std::this_thread::get_id())->RemoveBuffer(buffer);
549 }
550
551 void Graphics::RemoveShader( Shader& shader )
552 {
553   GetResourceCache(std::this_thread::get_id())->RemoveShader(shader);
554 }
555
556 void Graphics::RemoveCommandPool( CommandPool& commandPool )
557 {
558   GetResourceCache(std::this_thread::get_id())->RemoveCommandPool(commandPool);
559 }
560
561 void Graphics::RemoveDescriptorPool( DescriptorPool& pool )
562 {
563   GetResourceCache(std::this_thread::get_id())->RemoveDescriptorPool(pool);
564 }
565
566 void Graphics::RemoveFramebuffer( Framebuffer& framebuffer )
567 {
568   GetResourceCache(std::this_thread::get_id())->RemoveFramebuffer(framebuffer);
569 }
570
571 void Graphics::RemoveSampler( Sampler& sampler )
572 {
573   GetResourceCache(std::this_thread::get_id())->RemoveSampler(sampler);
574 }
575
576 void Graphics::CollectGarbage()
577 {
578   GetResourceCache(std::this_thread::get_id())->CollectGarbage();
579 }
580
581 void Graphics::DiscardResource( std::function<void()> deleter )
582 {
583   GetResourceCache(std::this_thread::get_id())->EnqueueDiscardOperation(std::move(deleter));
584 }
585 // --------------------------------------------------------------------------------------------------------------
586
587
588 void Graphics::CreateInstance( const std::vector<const char*>& extensions, const std::vector<const char*>& validationLayers )
589 {
590   auto info = vk::InstanceCreateInfo{};
591
592   info.setEnabledExtensionCount(U32(extensions.size()))
593       .setPpEnabledExtensionNames(extensions.data())
594       .setEnabledLayerCount(U32(validationLayers.size()))
595       .setPpEnabledLayerNames(validationLayers.data());
596
597 #if defined(DEBUG_ENABLED)
598   if( ! getenv("LOG_VULKAN") )
599   {
600     info.setEnabledLayerCount(0);
601   }
602 #endif
603
604   mInstance = VkAssert(vk::createInstance(info, *mAllocator));
605 }
606
607 void Graphics::DestroyInstance()
608 {
609   if(mInstance)
610   {
611     mInstance.destroy(*mAllocator);
612     mInstance = nullptr;
613   }
614 }
615
616
617 void Graphics::PreparePhysicalDevice()
618 {
619   auto devices = VkAssert(mInstance.enumeratePhysicalDevices());
620   assert(!devices.empty() && "No Vulkan supported device found!");
621
622   // if only one, pick first
623   mPhysicalDevice = nullptr;
624   if(devices.size() == 1)
625   {
626     mPhysicalDevice = devices[0];
627   }
628   else // otherwise look for one which is a graphics device
629   {
630     for(auto& device : devices)
631     {
632       auto properties =device.getProperties();
633       if(properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ||
634          properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu)
635       {
636         mPhysicalDevice = device;
637         break;
638       }
639     }
640   }
641
642   assert(mPhysicalDevice && "No suitable Physical Device found!");
643
644   GetPhysicalDeviceProperties();
645
646   GetQueueFamilyProperties();
647
648   mDeviceMemoryManager = GpuMemoryManager::New( *this );
649 }
650
651 void Graphics::GetPhysicalDeviceProperties()
652 {
653   // store data on heap to keep object smaller
654   mPhysicalDeviceProperties =
655     MakeUnique<vk::PhysicalDeviceProperties>(mPhysicalDevice.getProperties());
656   mPhysicalDeviceMemoryProperties =
657     MakeUnique<vk::PhysicalDeviceMemoryProperties>(mPhysicalDevice.getMemoryProperties());
658   mPhysicalDeviceFeatures =
659     MakeUnique<vk::PhysicalDeviceFeatures>(mPhysicalDevice.getFeatures());
660 }
661
662 void Graphics::GetQueueFamilyProperties()
663 {
664   mQueueFamilyProperties = mPhysicalDevice.getQueueFamilyProperties();
665 }
666
667 #pragma GCC diagnostic push
668 #pragma GCC diagnostic ignored "-Wframe-larger-than="
669 std::vector< vk::DeviceQueueCreateInfo > Graphics::GetQueueCreateInfos()
670 {
671   // surface is needed in order to find a family that supports presentation to this surface
672   // fixme: assuming all surfaces will be compatible with the queue family
673   assert(!mSurfaceFBIDMap.empty() &&
674          "At least one surface has to be created before creating VkDevice!");
675
676   std::vector< vk::DeviceQueueCreateInfo > queueInfos{};
677
678   constexpr uint8_t MAX_QUEUE_TYPES = 3;
679   // find suitable family for each type of queue
680   uint32_t familyIndexType[MAX_QUEUE_TYPES];
681   std::fill(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES], -1u);
682
683   // Graphics
684   auto& graphicsFamily = familyIndexType[0];
685
686   // Transfer
687   auto& transferFamily = familyIndexType[1];
688
689   // Transfer
690   auto& presentFamily = familyIndexType[2];
691
692   auto queueFamilyIndex = 0u;
693   for(auto& prop : mQueueFamilyProperties)
694   {
695     if((prop.queueFlags & vk::QueueFlagBits::eGraphics) && graphicsFamily == -1u)
696     {
697       graphicsFamily = queueFamilyIndex;
698     }
699     if((prop.queueFlags & vk::QueueFlagBits::eTransfer) && transferFamily == -1u)
700     {
701       transferFamily = queueFamilyIndex;
702     }
703     if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.surface->GetSurfaceKHR())
704            .value &&
705        presentFamily == -1u)
706     {
707       presentFamily = queueFamilyIndex;
708     }
709     ++queueFamilyIndex;
710   }
711
712   assert(graphicsFamily != -1u && "No queue family that supports graphics operations!");
713   assert(transferFamily != -1u && "No queue family that supports transfer operations!");
714   assert(presentFamily != -1u && "No queue family that supports present operations!");
715
716   // todo: we may require that the family must be same for all types of operations, it makes
717   // easier to handle synchronisation related issues.
718
719   // sort queues
720   std::sort(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES]);
721
722   // allocate all queues from graphics family
723   uint32_t prevQueueFamilyIndex = -1u;
724
725   for(auto i = 0u; i < MAX_QUEUE_TYPES; ++i)
726   {
727     auto& familyIndex = familyIndexType[i];
728     if(prevQueueFamilyIndex == familyIndex)
729     {
730       continue;
731     }
732
733     auto& queueCount = mQueueFamilyProperties[familyIndex].queueCount;
734
735     // fill queue create info for the family.
736     // note the priorities are not being set as local pointer will out of scope, this
737     // will be fixed by the caller function
738     auto info = vk::DeviceQueueCreateInfo{}
739                     .setPQueuePriorities(nullptr)
740                     .setQueueCount(queueCount)
741                     .setQueueFamilyIndex(familyIndex);
742     queueInfos.push_back(info);
743     prevQueueFamilyIndex = familyIndex;
744   }
745
746   return queueInfos;
747 }
748 #pragma GCC diagnostic pop
749
750 std::vector<const char*> Graphics::PrepareDefaultInstanceExtensions()
751 {
752   auto extensions = vk::enumerateInstanceExtensionProperties();
753
754   std::string extensionName;
755
756   bool xlibAvailable    { false };
757   bool xcbAvailable     { false };
758   bool waylandAvailable { false };
759
760   for( auto&& ext : extensions.value )
761   {
762     extensionName = ext.extensionName;
763     if( extensionName == VK_KHR_XCB_SURFACE_EXTENSION_NAME )
764     {
765       xcbAvailable = true;
766     }
767     else if( extensionName == VK_KHR_XLIB_SURFACE_EXTENSION_NAME )
768     {
769       xlibAvailable = true;
770     }
771     else if( extensionName == VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME )
772     {
773       waylandAvailable = true;
774     }
775   }
776
777   std::vector<const char*> retval{};
778
779   // depending on the platform validate extensions
780   auto platform = GetDefaultPlatform();
781
782   if( platform != Platform::UNDEFINED )
783   {
784     if (platform == Platform::XCB && xcbAvailable)
785     {
786       retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
787     }
788     else if (platform == Platform::XLIB && xlibAvailable)
789     {
790       retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
791     }
792     else if (platform == Platform::WAYLAND && waylandAvailable)
793     {
794       retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
795     }
796   }
797   else // try to determine the platform based on available extensions
798   {
799     if (xcbAvailable)
800     {
801       mPlatform = Platform::XCB;
802       retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
803     }
804     else if (xlibAvailable)
805     {
806       mPlatform = Platform::XLIB;
807       retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
808     }
809     else if (waylandAvailable)
810     {
811       mPlatform = Platform::WAYLAND;
812       retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
813     }
814     else
815     {
816       // can't determine the platform!
817       mPlatform = Platform::UNDEFINED;
818     }
819   }
820
821   // other essential extensions
822   retval.push_back( VK_KHR_SURFACE_EXTENSION_NAME );
823   retval.push_back( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );
824
825   return retval;
826 }
827
828 std::unique_ptr<ResourceCache>& Graphics::GetResourceCache(std::thread::id threadId)
829 {
830   if( mResourceCacheMap.count(threadId) == 0 )
831   {
832     std::lock_guard<std::mutex> lock{ mMutex };
833     mResourceCacheMap[threadId] = MakeUnique< ResourceCache >();
834   }
835
836   return mResourceCacheMap[threadId];
837 }
838
839 } // namespace Vulkan
840 } // namespace Graphics
841 } // namespace Dali