2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
26 #ifndef VK_KHR_XLIB_SURFACE_EXTENSION_NAME
27 #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
30 #ifndef VK_KHR_XCB_SURFACE_EXTENSION_NAME
31 #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
38 using VkSurfaceFactory = Dali::Integration::Graphics::Vulkan::VkSurfaceFactory;
42 Graphics::Graphics() = default;
44 Graphics::~Graphics() = default;
46 void Graphics::Create()
49 PreparePhysicalDevice();
52 void Graphics::CreateInstance()
54 auto info = vk::InstanceCreateInfo{};
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 };
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
73 info.setEnabledExtensionCount(U32(extensions.size()))
74 .setPpEnabledExtensionNames(extensions.data())
75 .setEnabledLayerCount(U32(validationLayers.size()))
76 .setPpEnabledLayerNames(validationLayers.data());
78 mInstance = VkAssert(vk::createInstance(info, *mAllocator));
81 void Graphics::DestroyInstance()
85 mInstance.destroy(*mAllocator);
90 #pragma GCC diagnostic push
91 #pragma GCC diagnostic ignored "-Wframe-larger-than="
92 void Graphics::PreparePhysicalDevice()
94 auto devices = VkAssert(mInstance.enumeratePhysicalDevices());
95 assert(devices.size() > 0 && "No Vulkan supported device found!");
97 // if only one, pick first
98 mPhysicalDevice = nullptr;
99 if(devices.size() == 1)
101 mPhysicalDevice = devices[0];
103 else // otherwise look for one which is a graphics device
105 for(auto& device : devices)
107 auto properties =device.getProperties();
108 if(properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ||
109 properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu)
111 mPhysicalDevice = device;
117 assert(mPhysicalDevice && "No suitable Physical Device found!");
119 GetPhysicalDeviceProperties();
121 GetQueueFamilyProperties();
123 mDeviceMemoryManager = MakeUnique<DeviceMemoryManager>( *this );
125 #pragma GCC diagnostic pop
127 #pragma GCC diagnostic push
128 #pragma GCC diagnostic ignored "-Wframe-larger-than="
129 void Graphics::GetPhysicalDeviceProperties()
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());
139 #pragma GCC diagnostic pop
141 void Graphics::GetQueueFamilyProperties()
143 mQueueFamilyProperties = std::move(mPhysicalDevice.getQueueFamilyProperties());
146 FBID Graphics::CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory)
148 const auto vkFactory = dynamic_cast< const VkSurfaceFactory* >(surfaceFactory.get());
154 auto surface = vkFactory->Create(mInstance, mAllocator.get(), mPhysicalDevice);
156 // map surface to FBID
157 auto fbid = ++mBaseFBID;
158 mSurfaceFBIDMap[fbid] = MakeUnique<Surface>(*this, surface, 3u);
162 #pragma GCC diagnostic push
163 #pragma GCC diagnostic ignored "-Wframe-larger-than="
164 std::vector< vk::DeviceQueueCreateInfo > Graphics::GetQueueCreateInfos()
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!");
171 auto queueInfos = std::vector< vk::DeviceQueueCreateInfo >{};
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);
179 auto& graphicsFamily = familyIndexType[0];
182 auto& transferFamily = familyIndexType[1];
185 auto& presentFamily = familyIndexType[2];
187 auto queueFamilyIndex = 0u;
188 for(auto& prop : mQueueFamilyProperties)
190 if((prop.queueFlags & vk::QueueFlagBits::eGraphics) && graphicsFamily == -1u)
192 graphicsFamily = queueFamilyIndex;
194 if((prop.queueFlags & vk::QueueFlagBits::eTransfer) && transferFamily == -1u)
196 transferFamily = queueFamilyIndex;
198 if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.get()->GetSurfaceKHR())
200 presentFamily == -1u)
202 presentFamily = queueFamilyIndex;
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!");
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.
215 std::sort(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES]);
217 // allocate all queues from graphics family
218 uint32_t prevQueueFamilyIndex = -1u;
220 for(auto i = 0u; i < MAX_QUEUE_TYPES; ++i)
222 auto& familyIndex = familyIndexType[i];
223 if(prevQueueFamilyIndex == familyIndex)
228 auto& queueCount = mQueueFamilyProperties[familyIndex].queueCount;
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;
243 #pragma GCC diagnostic pop
245 #pragma GCC diagnostic push
246 #pragma GCC diagnostic ignored "-Wframe-larger-than="
247 void Graphics::CreateDevice()
249 auto queueInfos = GetQueueCreateInfos();
251 auto maxQueueCountPerFamily = 0u;
252 for( auto&& info : queueInfos )
254 maxQueueCountPerFamily = std::max( info.queueCount, maxQueueCountPerFamily );
257 auto priorities = std::vector<float>( maxQueueCountPerFamily );
258 std::fill( priorities.begin(), priorities.end(), 1.0f );
260 for( auto& info : queueInfos )
262 info.setPQueuePriorities( priorities.data() );
265 auto extensions = std::vector< const char* >{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
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()));
274 mDevice = VkAssert(mPhysicalDevice.createDevice(info, *mAllocator));
277 // create Queue objects
278 for(auto& queueInfo : queueInfos)
280 for(auto i = 0u; i < queueInfo.queueCount; ++i)
282 auto queue = mDevice.getQueue(queueInfo.queueFamilyIndex, i);
284 // based on family push queue instance into right array
285 auto flags = mQueueFamilyProperties[queueInfo.queueFamilyIndex].queueFlags;
286 if(flags & vk::QueueFlagBits::eGraphics)
288 mGraphicsQueues.emplace_back(
289 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
291 if(flags & vk::QueueFlagBits::eTransfer)
293 mTransferQueues.emplace_back(
294 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
296 if(flags & vk::QueueFlagBits::eCompute)
298 mComputeQueues.emplace_back(
299 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
302 // todo: present queue
306 #pragma GCC diagnostic pop
308 vk::Device Graphics::GetDevice() const
313 vk::PhysicalDevice Graphics::GetPhysicalDevice() const
315 return mPhysicalDevice;
318 vk::Instance Graphics::GetInstance() const
323 const vk::AllocationCallbacks& Graphics::GetAllocator() const
328 Queue& Graphics::GetGraphicsQueue(uint32_t index) const
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!");
334 return *mGraphicsQueues[0].get(); // will be mGraphicsQueues[index]
337 Queue& Graphics::GetTransferQueue(uint32_t index) const
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!");
343 return *mTransferQueues[0].get(); // will be mGraphicsQueues[index]
346 Queue& Graphics::GetComputeQueue(uint32_t index) const
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!");
352 return *mComputeQueues[0].get(); // will be mGraphicsQueues[index]
355 Queue& Graphics::GetPresentQueue() const
357 return *mPresentQueue.get();
360 std::unique_ptr< CommandPool > Graphics::CreateCommandPool(const vk::CommandPoolCreateInfo& info)
362 auto cmdpool = std::unique_ptr< CommandPool >(new CommandPool(*this, info));
366 Surface& Graphics::GetSurface( FBID surfaceId )
368 return *mSurfaceFBIDMap[surfaceId].get();
371 } // namespace Vulkan
372 } // namespace Graphics