[Vulkan] Working build
[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_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::Vulkan::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 = std::move(mPhysicalDevice.getQueueFamilyProperties());
279 }
280
281 FBID Graphics::CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory)
282 {
283   const auto vkFactory = dynamic_cast< const VkSurfaceFactory* >(surfaceFactory.get());
284   if(!vkFactory)
285   {
286     return FBID{0u};
287   }
288
289   auto surface = vkFactory->Create(mInstance, mAllocator.get(), mPhysicalDevice);
290
291   // map surface to FBID
292   auto fbid             = ++mBaseFBID;
293   mSurfaceFBIDMap[fbid] = MakeUnique<Surface>(*this, surface, 3u);
294   return fbid;
295 }
296
297 #pragma GCC diagnostic push
298 #pragma GCC diagnostic ignored "-Wframe-larger-than="
299 std::vector< vk::DeviceQueueCreateInfo > Graphics::GetQueueCreateInfos()
300 {
301   // surface is needed in order to find a family that supports presentation to this surface
302   // fixme: assuming all surfaces will be compatible with the queue family
303   assert(!mSurfaceFBIDMap.empty() &&
304          "At least one surface has to be created before creating VkDevice!");
305
306   auto queueInfos = std::vector< vk::DeviceQueueCreateInfo >{};
307
308   constexpr uint8_t MAX_QUEUE_TYPES = 3;
309   // find suitable family for each type of queue
310   uint32_t familyIndexType[MAX_QUEUE_TYPES];
311   std::fill(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES], -1u);
312
313   // Graphics
314   auto& graphicsFamily = familyIndexType[0];
315
316   // Transfer
317   auto& transferFamily = familyIndexType[1];
318
319   // Transfer
320   auto& presentFamily = familyIndexType[2];
321
322   auto queueFamilyIndex = 0u;
323   for(auto& prop : mQueueFamilyProperties)
324   {
325     if((prop.queueFlags & vk::QueueFlagBits::eGraphics) && graphicsFamily == -1u)
326     {
327       graphicsFamily = queueFamilyIndex;
328     }
329     if((prop.queueFlags & vk::QueueFlagBits::eTransfer) && transferFamily == -1u)
330     {
331       transferFamily = queueFamilyIndex;
332     }
333     if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.get()->GetSurfaceKHR())
334            .value &&
335        presentFamily == -1u)
336     {
337       presentFamily = queueFamilyIndex;
338     }
339     ++queueFamilyIndex;
340   }
341
342   assert(graphicsFamily != -1u && "No queue family that supports graphics operations!");
343   assert(transferFamily != -1u && "No queue family that supports transfer operations!");
344   assert(presentFamily != -1u && "No queue family that supports present operations!");
345
346   // todo: we may require that the family must be same for all types of operations, it makes
347   // easier to handle synchronisation related issues.
348
349   // sort queues
350   std::sort(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES]);
351
352   // allocate all queues from graphics family
353   uint32_t prevQueueFamilyIndex = -1u;
354
355   for(auto i = 0u; i < MAX_QUEUE_TYPES; ++i)
356   {
357     auto& familyIndex = familyIndexType[i];
358     if(prevQueueFamilyIndex == familyIndex)
359     {
360       continue;
361     }
362
363     auto& queueCount = mQueueFamilyProperties[familyIndex].queueCount;
364
365     // fill queue create info for the family.
366     // note the priorities are not being set as local pointer will out of scope, this
367     // will be fixed by the caller function
368     auto info = vk::DeviceQueueCreateInfo{}
369                     .setPQueuePriorities(nullptr)
370                     .setQueueCount(queueCount)
371                     .setQueueFamilyIndex(familyIndex);
372     queueInfos.push_back(info);
373     prevQueueFamilyIndex = familyIndex;
374   }
375
376   return queueInfos;
377 }
378 #pragma GCC diagnostic pop
379
380 #pragma GCC diagnostic push
381 #pragma GCC diagnostic ignored "-Wframe-larger-than="
382 void Graphics::CreateDevice()
383 {
384   auto queueInfos = GetQueueCreateInfos();
385   {
386     auto maxQueueCountPerFamily = 0u;
387     for( auto&& info : queueInfos )
388     {
389       maxQueueCountPerFamily = std::max( info.queueCount, maxQueueCountPerFamily );
390     }
391
392     auto priorities = std::vector<float>( maxQueueCountPerFamily );
393     std::fill( priorities.begin(), priorities.end(), 1.0f );
394
395     for( auto& info : queueInfos )
396     {
397       info.setPQueuePriorities( priorities.data() );
398     }
399
400     auto extensions = std::vector< const char* >{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
401
402     auto info = vk::DeviceCreateInfo{};
403     info.setEnabledExtensionCount(U32(extensions.size()))
404         .setPpEnabledExtensionNames(extensions.data())
405         .setPEnabledFeatures(&(*mPhysicalDeviceFeatures))
406         .setPQueueCreateInfos(queueInfos.data())
407         .setQueueCreateInfoCount(U32(queueInfos.size()));
408
409     mDevice = VkAssert(mPhysicalDevice.createDevice(info, *mAllocator));
410   }
411
412   // create Queue objects
413   for(auto& queueInfo : queueInfos)
414   {
415     for(auto i = 0u; i < queueInfo.queueCount; ++i)
416     {
417       auto queue = mDevice.getQueue(queueInfo.queueFamilyIndex, i);
418
419       // based on family push queue instance into right array
420       auto flags = mQueueFamilyProperties[queueInfo.queueFamilyIndex].queueFlags;
421       if(flags & vk::QueueFlagBits::eGraphics)
422       {
423         mGraphicsQueues.emplace_back(
424           MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
425       }
426       if(flags & vk::QueueFlagBits::eTransfer)
427       {
428         mTransferQueues.emplace_back(
429           MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
430       }
431       if(flags & vk::QueueFlagBits::eCompute)
432       {
433         mComputeQueues.emplace_back(
434           MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
435       }
436
437       // todo: present queue
438     }
439   }
440 }
441 #pragma GCC diagnostic pop
442
443 vk::Device Graphics::GetDevice() const
444 {
445   return mDevice;
446 }
447
448 vk::PhysicalDevice Graphics::GetPhysicalDevice() const
449 {
450   return mPhysicalDevice;
451 }
452
453 vk::Instance Graphics::GetInstance() const
454 {
455   return mInstance;
456 }
457
458 const vk::AllocationCallbacks& Graphics::GetAllocator() const
459 {
460   return *mAllocator;
461 }
462
463 Queue& Graphics::GetGraphicsQueue(uint32_t index) const
464 {
465   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
466   // this will change in the future
467   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
468
469   return *mGraphicsQueues[0].get(); // will be mGraphicsQueues[index]
470 }
471
472 Queue& Graphics::GetTransferQueue(uint32_t index) const
473 {
474   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
475   // this will change in the future
476   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
477
478   return *mTransferQueues[0].get(); // will be mGraphicsQueues[index]
479 }
480
481 Queue& Graphics::GetComputeQueue(uint32_t index) const
482 {
483   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
484   // this will change in the future
485   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
486
487   return *mComputeQueues[0].get(); // will be mGraphicsQueues[index]
488 }
489
490 Queue& Graphics::GetPresentQueue() const
491 {
492   return *mPresentQueue.get();
493 }
494
495 Handle< CommandPool > Graphics::CreateCommandPool(const vk::CommandPoolCreateInfo& info)
496 {
497   auto cmdpool = CommandPool::New( *this, vk::CommandPoolCreateInfo{}.
498                                                                        setQueueFamilyIndex( 0u ).
499                                                                        setFlags( vk::CommandPoolCreateFlagBits::eResetCommandBuffer ) );
500   return cmdpool;
501 }
502
503 Surface& Graphics::GetSurface( FBID surfaceId )
504 {
505   // TODO: FBID == 0 means default framebuffer, but there should be no
506   // such thing as default framebuffer.
507   if( surfaceId == 0 )
508   {
509     return *mSurfaceFBIDMap.begin()->second.get();
510   }
511   return *mSurfaceFBIDMap[surfaceId].get();
512 }
513
514 // TODO: all this stuff should go into some vulkan cache
515
516 void Graphics::AddBuffer( Handle<Buffer> buffer )
517 {
518   mBuffersCache.push_back( buffer );
519 }
520
521 void Graphics::AddImage( Handle<Image> image )
522 {
523   mImageCache.push_back( image );
524 }
525
526 void Graphics::AddPipeline( Handle<Pipeline> pipeline )
527 {
528   mPipelineCache.push_back( pipeline );
529 }
530
531 void Graphics::AddShader( Handle<Shader> shader )
532 {
533   mShaderCache.push_back( shader );
534 }
535
536 void Graphics::AddCommandPool( Handle<CommandPool> pool )
537 {
538   mCommandPoolCache.push_back( pool );
539 }
540
541 void Graphics::AddDescriptorPool( Handle<DescriptorPool> pool )
542 {
543   mDescriptorPoolCache.push_back( pool );
544 }
545
546 void Graphics::AddFramebuffer( Handle<Framebuffer> framebuffer )
547 {
548   mFramebufferCache.push_back( framebuffer );
549 }
550
551 void Graphics::RemoveBuffer( Buffer& buffer )
552 {
553   auto index = 0u;
554   for( auto&& iter : mBuffersCache )
555   {
556     if( &*iter == &buffer )
557     {
558       iter.Reset();
559       mBuffersCache.erase( mBuffersCache.begin()+index );
560       return;
561     }
562   }
563 }
564
565 void Graphics::RemoveShader( Shader& shader )
566 {
567   auto index = 0u;
568   for( auto&& iter : mShaderCache )
569   {
570     if( &*iter == &shader )
571     {
572       iter.Reset();
573       mShaderCache.erase( mShaderCache.begin()+index );
574       return;
575     }
576     ++index;
577   }
578 }
579
580 void Graphics::RemoveCommandPool( CommandPool& commandPool )
581 {
582   NotImplemented();
583 }
584
585 void Graphics::RemoveDescriptorPool( std::unique_ptr<DescriptorPool> pool )
586 {
587   NotImplemented();
588 }
589
590 Handle<Shader> Graphics::FindShader( vk::ShaderModule shaderModule )
591 {
592   for( auto&& iter : mShaderCache )
593   {
594     if( iter->GetVkShaderModule() == shaderModule )
595     {
596       return Handle<Shader>(&*iter);
597     }
598   }
599   return Handle<Shader>();
600 }
601
602
603 } // namespace Vulkan
604 } // namespace Graphics
605 } // namespace Dali