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