Simplified Vulkan backend [WIP]
[platform/core/uifw/dali-core.git] / dali / graphics / vulkan / vulkan-graphics.cpp
1 /*
2  * Copyright (c) 2017 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/vulkan-device-memory-manager.h>
25
26 #ifndef VK_KHR_XLIB_SURFACE_EXTENSION_NAME
27 #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
28 #endif
29
30 #ifndef VK_KHR_XCB_SURFACE_EXTENSION_NAME
31 #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
32 #endif
33
34 namespace Dali
35 {
36 namespace Graphics
37 {
38 using VkSurfaceFactory = Dali::Integration::Graphics::Vulkan::VkSurfaceFactory;
39 namespace Vulkan
40 {
41
42 Graphics::Graphics() = default;
43
44 Graphics::~Graphics() = default;
45
46 void Graphics::Create()
47 {
48   CreateInstance();
49   PreparePhysicalDevice();
50 }
51
52 void Graphics::CreateInstance()
53 {
54   auto info = vk::InstanceCreateInfo{};
55   auto extensions =
56       std::vector< const char* >{VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
57                                  VK_KHR_XLIB_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME };
58
59   const auto validationLayers = std::vector< const char* >{
60       //"VK_LAYER_LUNARG_screenshot",           // screenshot
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_LUNARG_standard_validation", // standard
71   };
72
73   info.setEnabledExtensionCount(U32(extensions.size()))
74       .setPpEnabledExtensionNames(extensions.data())
75       .setEnabledLayerCount(U32(validationLayers.size()))
76       .setPpEnabledLayerNames(validationLayers.data());
77
78   mInstance = VkAssert(vk::createInstance(info, mAllocator));
79 }
80
81 void Graphics::DestroyInstance()
82 {
83   if(mInstance)
84   {
85     mInstance.destroy(mAllocator);
86     mInstance = nullptr;
87   }
88 }
89
90 #pragma GCC diagnostic push
91 #pragma GCC diagnostic ignored "-Wframe-larger-than="
92 void Graphics::PreparePhysicalDevice()
93 {
94   auto devices = VkAssert(mInstance.enumeratePhysicalDevices());
95   assert(devices.size() > 0 && "No Vulkan supported device found!");
96
97   // if only one, pick first
98   mPhysicalDevice = nullptr;
99   if(devices.size() == 1)
100   {
101     mPhysicalDevice = devices[0];
102   }
103   else // otherwise look for one which is a graphics device
104   {
105     for(auto& device : devices)
106     {
107       auto properties =device.getProperties();
108       if(properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ||
109          properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu)
110       {
111         mPhysicalDevice = device;
112         break;
113       }
114     }
115   }
116
117   assert(mPhysicalDevice && "No suitable Physical Device found!");
118
119   GetPhysicalDeviceProperties();
120
121   GetQueueFamilyProperties();
122
123   mDeviceMemoryManager = MakeUnique<DeviceMemoryManager>( *this );
124 }
125 #pragma GCC diagnostic pop
126
127 #pragma GCC diagnostic push
128 #pragma GCC diagnostic ignored "-Wframe-larger-than="
129 void Graphics::GetPhysicalDeviceProperties()
130 {
131   // store data on heap to keep object smaller
132   mPhysicalDeviceProperties =
133     MakeUnique<vk::PhysicalDeviceProperties>(mPhysicalDevice.getProperties());
134   mPhysicalDeviceMemoryProperties =
135     MakeUnique<vk::PhysicalDeviceMemoryProperties>(mPhysicalDevice.getMemoryProperties());
136   mPhysicalDeviceFeatures =
137     MakeUnique<vk::PhysicalDeviceFeatures>(mPhysicalDevice.getFeatures());
138 }
139 #pragma GCC diagnostic pop
140
141 void Graphics::GetQueueFamilyProperties()
142 {
143   mQueueFamilyProperties = std::move(mPhysicalDevice.getQueueFamilyProperties());
144 }
145
146 FBID Graphics::CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory)
147 {
148   const auto vkFactory = dynamic_cast< const VkSurfaceFactory* >(surfaceFactory.get());
149   if(!vkFactory)
150   {
151     return FBID{0u};
152   }
153
154   auto surface = vkFactory->Create(mInstance, mAllocator, mPhysicalDevice);
155
156   // map surface to FBID
157   auto fbid             = ++mBaseFBID;
158   mSurfaceFBIDMap[fbid] = MakeUnique<Surface>(*this, surface, 3u);
159   return fbid;
160 }
161
162 #pragma GCC diagnostic push
163 #pragma GCC diagnostic ignored "-Wframe-larger-than="
164 std::vector< vk::DeviceQueueCreateInfo > Graphics::GetQueueCreateInfos()
165 {
166   // surface is needed in order to find a family that supports presentation to this surface
167   // fixme: assuming all surfaces will be compatible with the queue family
168   assert(!mSurfaceFBIDMap.empty() &&
169          "At least one surface has to be created before creating VkDevice!");
170
171   auto queueInfos = std::vector< vk::DeviceQueueCreateInfo >{};
172
173   constexpr uint8_t MAX_QUEUE_TYPES = 3;
174   // find suitable family for each type of queue
175   uint32_t familyIndexType[MAX_QUEUE_TYPES];
176   std::fill(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES], -1u);
177
178   // Graphics
179   auto& graphicsFamily = familyIndexType[0];
180
181   // Transfer
182   auto& transferFamily = familyIndexType[1];
183
184   // Transfer
185   auto& presentFamily = familyIndexType[2];
186
187   auto queueFamilyIndex = 0u;
188   for(auto& prop : mQueueFamilyProperties)
189   {
190     if((prop.queueFlags & vk::QueueFlagBits::eGraphics) && graphicsFamily == -1u)
191     {
192       graphicsFamily = queueFamilyIndex;
193     }
194     if((prop.queueFlags & vk::QueueFlagBits::eTransfer) && transferFamily == -1u)
195     {
196       transferFamily = queueFamilyIndex;
197     }
198     if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.get()->GetSurfaceKHR())
199            .value &&
200        presentFamily == -1u)
201     {
202       presentFamily = queueFamilyIndex;
203     }
204     ++queueFamilyIndex;
205   }
206
207   assert(graphicsFamily != -1u && "No queue family that supports graphics operations!");
208   assert(transferFamily != -1u && "No queue family that supports transfer operations!");
209   assert(presentFamily != -1u && "No queue family that supports present operations!");
210
211   // todo: we may require that the family must be same for all types of operations, it makes
212   // easier to handle synchronisation related issues.
213
214   // sort queues
215   std::sort(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES]);
216
217   // allocate all queues from graphics family
218   uint32_t prevQueueFamilyIndex = -1u;
219
220   for(auto i = 0u; i < MAX_QUEUE_TYPES; ++i)
221   {
222     auto& familyIndex = familyIndexType[i];
223     if(prevQueueFamilyIndex == familyIndex)
224     {
225       continue;
226     }
227
228     auto& queueCount = mQueueFamilyProperties[familyIndex].queueCount;
229
230     // fill queue create info for the family.
231     // note the priorities are not being set as local pointer will out of scope, this
232     // will be fixed by the caller function
233     auto info = vk::DeviceQueueCreateInfo{}
234                     .setPQueuePriorities(nullptr)
235                     .setQueueCount(queueCount)
236                     .setQueueFamilyIndex(familyIndex);
237     queueInfos.push_back(info);
238     prevQueueFamilyIndex = familyIndex;
239   }
240
241   return queueInfos;
242 }
243 #pragma GCC diagnostic pop
244
245 #pragma GCC diagnostic push
246 #pragma GCC diagnostic ignored "-Wframe-larger-than="
247 void Graphics::CreateDevice()
248 {
249   auto queueInfos = GetQueueCreateInfos();
250   {
251     auto maxQueueCountPerFamily = 0u;
252     for( auto&& info : queueInfos )
253     {
254       maxQueueCountPerFamily = std::max( info.queueCount, maxQueueCountPerFamily );
255     }
256
257     auto priorities = std::vector<float>( maxQueueCountPerFamily );
258     std::fill( priorities.begin(), priorities.end(), 1.0f );
259
260     for( auto& info : queueInfos )
261     {
262       info.setPQueuePriorities( priorities.data() );
263     }
264
265     auto extensions = std::vector< const char* >{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
266
267     auto info = vk::DeviceCreateInfo{};
268     info.setEnabledExtensionCount(U32(extensions.size()))
269         .setPpEnabledExtensionNames(extensions.data())
270         .setPEnabledFeatures(&(*mPhysicalDeviceFeatures))
271         .setPQueueCreateInfos(queueInfos.data())
272         .setQueueCreateInfoCount(U32(queueInfos.size()));
273
274     mDevice = VkAssert(mPhysicalDevice.createDevice(info, mAllocator));
275   }
276
277   // create Queue objects
278   for(auto& queueInfo : queueInfos)
279   {
280     for(auto i = 0u; i < queueInfo.queueCount; ++i)
281     {
282       auto queue = mDevice.getQueue(queueInfo.queueFamilyIndex, i);
283
284       // based on family push queue instance into right array
285       auto flags = mQueueFamilyProperties[queueInfo.queueFamilyIndex].queueFlags;
286       if(flags & vk::QueueFlagBits::eGraphics)
287       {
288         mGraphicsQueues.emplace_back(
289           MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
290       }
291       if(flags & vk::QueueFlagBits::eTransfer)
292       {
293         mTransferQueues.emplace_back(
294           MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
295       }
296       if(flags & vk::QueueFlagBits::eCompute)
297       {
298         mComputeQueues.emplace_back(
299           MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
300       }
301
302       // todo: present queue
303     }
304   }
305 }
306 #pragma GCC diagnostic pop
307
308 vk::Device Graphics::GetDevice() const
309 {
310   return mDevice;
311 }
312
313 vk::PhysicalDevice Graphics::GetPhysicalDevice() const
314 {
315   return mPhysicalDevice;
316 }
317
318 vk::Instance Graphics::GetInstance() const
319 {
320   return mInstance;
321 }
322
323 vk::AllocationCallbacks* Graphics::GetAllocator() const
324 {
325   return mAllocator;
326 }
327
328 Queue& Graphics::GetGraphicsQueue(uint32_t index) const
329 {
330   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
331   // this will change in the future
332   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
333
334   return *mGraphicsQueues[0].get(); // will be mGraphicsQueues[index]
335 }
336
337 Queue& Graphics::GetTransferQueue(uint32_t index) const
338 {
339   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
340   // this will change in the future
341   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
342
343   return *mTransferQueues[0].get(); // will be mGraphicsQueues[index]
344 }
345
346 Queue& Graphics::GetComputeQueue(uint32_t index) const
347 {
348   // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
349   // this will change in the future
350   assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
351
352   return *mComputeQueues[0].get(); // will be mGraphicsQueues[index]
353 }
354
355 Queue& Graphics::GetPresentQueue() const
356 {
357   return *mPresentQueue.get();
358 }
359
360 std::unique_ptr< CommandPool > Graphics::CreateCommandPool(const vk::CommandPoolCreateInfo& info)
361 {
362   auto cmdpool = std::unique_ptr< CommandPool >(new CommandPool(*this, info));
363   return cmdpool;
364 }
365
366 Surface& Graphics::GetSurface( FBID surfaceId )
367 {
368   return *mSurfaceFBIDMap[surfaceId].get();
369 }
370
371 } // namespace Vulkan
372 } // namespace Graphics
373 } // namespace Dali