2 * Copyright (c) 2018 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/gpu-memory/vulkan-gpu-memory-manager.h>
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>
35 #include <dali/graphics-api/graphics-api-controller.h>
37 #ifndef VK_KHR_XLIB_SURFACE_EXTENSION_NAME
38 #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
41 #ifndef VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
42 #define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface"
45 #ifndef VK_KHR_XCB_SURFACE_EXTENSION_NAME
46 #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
55 using VkSurfaceFactory = Dali::Integration::Graphics::Vulkan::VkSurfaceFactory;
59 const auto VALIDATION_LAYERS = std::vector< const char* >{
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
76 Graphics::Graphics() = default;
78 Graphics::~Graphics() = default;
79 #pragma GCC diagnostic push
80 #pragma GCC diagnostic ignored "-Wframe-larger-than="
82 Platform Graphics::GetDefaultPlatform() const
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;
95 Dali::Graphics::API::Controller& Graphics::GetController()
99 mGfxController = Dali::Graphics::Vulkan::Controller::New(*this);
102 return *mGfxController.get();
105 std::vector<const char*> Graphics::PrepareDefaultInstanceExtensions()
107 auto extensions = vk::enumerateInstanceExtensionProperties();
109 std::string extensionName;
111 bool xlibAvailable { false };
112 bool xcbAvailable { false };
113 bool waylandAvailable { false };
115 for( auto&& ext : extensions.value )
117 extensionName = ext.extensionName;
118 if( extensionName == VK_KHR_XCB_SURFACE_EXTENSION_NAME )
122 else if( extensionName == VK_KHR_XLIB_SURFACE_EXTENSION_NAME )
124 xlibAvailable = true;
126 else if( extensionName == VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME )
128 waylandAvailable = true;
132 std::vector<const char*> retval;
134 // depending on the platform validate extensions
135 auto platform = GetDefaultPlatform();
137 if( platform != Platform::UNDEFINED )
139 if (platform == Platform::XCB && xcbAvailable)
141 retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
143 else if (platform == Platform::XLIB && xlibAvailable)
145 retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
147 else if (platform == Platform::WAYLAND && waylandAvailable)
149 retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
152 else // try to determine the platform based on available extensions
156 mPlatform = Platform::XCB;
157 retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
159 else if (xlibAvailable)
161 mPlatform = Platform::XLIB;
162 retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
164 else if (waylandAvailable)
166 mPlatform = Platform::WAYLAND;
167 retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
171 // can't determine the platform!
172 mPlatform = Platform::UNDEFINED;
176 // other essential extensions
177 retval.push_back( VK_KHR_SURFACE_EXTENSION_NAME );
178 retval.push_back( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );
183 void Graphics::Create()
186 auto extensions = PrepareDefaultInstanceExtensions();
188 auto layers = vk::enumerateInstanceLayerProperties();
189 std::vector<const char*> validationLayers;
190 for( auto&& reqLayer : VALIDATION_LAYERS )
192 for( auto&& prop : layers.value )
194 std::cout << prop.layerName << std::endl;
195 if( std::string(prop.layerName) == reqLayer )
197 validationLayers.push_back(reqLayer);
202 CreateInstance(extensions, validationLayers);
203 PreparePhysicalDevice();
206 void Graphics::CreateInstance( const std::vector<const char*>& extensions, const std::vector<const char*>& validationLayers )
208 auto info = vk::InstanceCreateInfo{};
210 info.setEnabledExtensionCount(U32(extensions.size()))
211 .setPpEnabledExtensionNames(extensions.data())
212 .setEnabledLayerCount(U32(validationLayers.size()))
213 .setEnabledLayerCount(0)
214 .setPpEnabledLayerNames(validationLayers.data());
216 mInstance = VkAssert(vk::createInstance(info, *mAllocator));
219 void Graphics::DestroyInstance()
223 mInstance.destroy(*mAllocator);
229 void Graphics::PreparePhysicalDevice()
231 auto devices = VkAssert(mInstance.enumeratePhysicalDevices());
232 assert(devices.size() > 0 && "No Vulkan supported device found!");
234 // if only one, pick first
235 mPhysicalDevice = nullptr;
236 if(devices.size() == 1)
238 mPhysicalDevice = devices[0];
240 else // otherwise look for one which is a graphics device
242 for(auto& device : devices)
244 auto properties =device.getProperties();
245 if(properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ||
246 properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu)
248 mPhysicalDevice = device;
254 assert(mPhysicalDevice && "No suitable Physical Device found!");
256 GetPhysicalDeviceProperties();
258 GetQueueFamilyProperties();
260 mDeviceMemoryManager = GpuMemoryManager::New( *this );
262 #pragma GCC diagnostic pop
264 #pragma GCC diagnostic push
265 #pragma GCC diagnostic ignored "-Wframe-larger-than="
266 void Graphics::GetPhysicalDeviceProperties()
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());
276 #pragma GCC diagnostic pop
278 void Graphics::GetQueueFamilyProperties()
280 mQueueFamilyProperties = mPhysicalDevice.getQueueFamilyProperties();
283 FBID Graphics::CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory)
285 // create surface from the factory
286 auto surfaceRef = Surface::New( *this, std::move(surfaceFactory) );
288 if( surfaceRef->Create() )
291 // map surface to FBID
292 auto fbid = ++mBaseFBID;
293 mSurfaceFBIDMap[fbid] = SwapchainSurfacePair{ SwapchainRef{}, surfaceRef };
299 SwapchainRef Graphics::CreateSwapchainForSurface( SurfaceRef surface )
301 auto swapchain = Swapchain::New( *this,
302 GetGraphicsQueue(0u),
305 // store swapchain in the correct pair
306 for( auto&& val : mSurfaceFBIDMap )
308 if( val.second.surface == surface )
310 val.second.swapchain = swapchain;
318 SwapchainRef Graphics::GetSwapchainForSurface( SurfaceRef surface )
320 for( auto&& val : mSurfaceFBIDMap )
322 if( val.second.surface == surface )
328 return SwapchainRef();
331 SwapchainRef Graphics::GetSwapchainForFBID( FBID surfaceId )
335 return mSurfaceFBIDMap.begin()->second.swapchain;
337 return mSurfaceFBIDMap[surfaceId].swapchain;
340 #pragma GCC diagnostic push
341 #pragma GCC diagnostic ignored "-Wframe-larger-than="
342 std::vector< vk::DeviceQueueCreateInfo > Graphics::GetQueueCreateInfos()
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!");
349 auto queueInfos = std::vector< vk::DeviceQueueCreateInfo >{};
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);
357 auto& graphicsFamily = familyIndexType[0];
360 auto& transferFamily = familyIndexType[1];
363 auto& presentFamily = familyIndexType[2];
365 auto queueFamilyIndex = 0u;
366 for(auto& prop : mQueueFamilyProperties)
368 if((prop.queueFlags & vk::QueueFlagBits::eGraphics) && graphicsFamily == -1u)
370 graphicsFamily = queueFamilyIndex;
372 if((prop.queueFlags & vk::QueueFlagBits::eTransfer) && transferFamily == -1u)
374 transferFamily = queueFamilyIndex;
376 if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.surface->GetSurfaceKHR())
378 presentFamily == -1u)
380 presentFamily = queueFamilyIndex;
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!");
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.
393 std::sort(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES]);
395 // allocate all queues from graphics family
396 uint32_t prevQueueFamilyIndex = -1u;
398 for(auto i = 0u; i < MAX_QUEUE_TYPES; ++i)
400 auto& familyIndex = familyIndexType[i];
401 if(prevQueueFamilyIndex == familyIndex)
406 auto& queueCount = mQueueFamilyProperties[familyIndex].queueCount;
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;
421 #pragma GCC diagnostic pop
423 #pragma GCC diagnostic push
424 #pragma GCC diagnostic ignored "-Wframe-larger-than="
425 void Graphics::CreateDevice()
427 auto queueInfos = GetQueueCreateInfos();
429 auto maxQueueCountPerFamily = 0u;
430 for( auto&& info : queueInfos )
432 maxQueueCountPerFamily = std::max( info.queueCount, maxQueueCountPerFamily );
435 auto priorities = std::vector<float>( maxQueueCountPerFamily );
436 std::fill( priorities.begin(), priorities.end(), 1.0f );
438 for( auto& info : queueInfos )
440 info.setPQueuePriorities( priorities.data() );
443 auto extensions = std::vector< const char* >{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
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()));
452 mDevice = VkAssert(mPhysicalDevice.createDevice(info, *mAllocator));
455 // create Queue objects
456 for(auto& queueInfo : queueInfos)
458 for(auto i = 0u; i < queueInfo.queueCount; ++i)
460 auto queue = mDevice.getQueue(queueInfo.queueFamilyIndex, i);
462 // based on family push queue instance into right array
463 auto flags = mQueueFamilyProperties[queueInfo.queueFamilyIndex].queueFlags;
464 if(flags & vk::QueueFlagBits::eGraphics)
466 mGraphicsQueues.emplace_back(
467 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
469 if(flags & vk::QueueFlagBits::eTransfer)
471 mTransferQueues.emplace_back(
472 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
474 if(flags & vk::QueueFlagBits::eCompute)
476 mComputeQueues.emplace_back(
477 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
480 // todo: present queue
484 mPipelineDatabase = std::make_unique<PipelineCache>( *this );
486 #pragma GCC diagnostic pop
488 vk::Device Graphics::GetDevice() const
493 vk::PhysicalDevice Graphics::GetPhysicalDevice() const
495 return mPhysicalDevice;
498 vk::Instance Graphics::GetInstance() const
503 const vk::AllocationCallbacks& Graphics::GetAllocator() const
508 Queue& Graphics::GetGraphicsQueue(uint32_t index) const
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!");
514 return *mGraphicsQueues[0].get(); // will be mGraphicsQueues[index]
517 Queue& Graphics::GetTransferQueue(uint32_t index) const
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!");
523 return *mTransferQueues[0].get(); // will be mGraphicsQueues[index]
526 Queue& Graphics::GetComputeQueue(uint32_t index) const
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!");
532 return *mComputeQueues[0].get(); // will be mGraphicsQueues[index]
535 Queue& Graphics::GetPresentQueue() const
537 // fixme: should be a dedicated presentation queue
538 return GetGraphicsQueue(0);
541 Handle< CommandPool > Graphics::CreateCommandPool(const vk::CommandPoolCreateInfo& info)
543 auto cmdpool = CommandPool::New( *this, vk::CommandPoolCreateInfo{}.
544 setQueueFamilyIndex( 0u ).
545 setFlags( vk::CommandPoolCreateFlagBits::eResetCommandBuffer ) );
549 SurfaceRef Graphics::GetSurface( FBID surfaceId )
551 // TODO: FBID == 0 means default framebuffer, but there should be no
552 // such thing as default framebuffer.
555 return mSurfaceFBIDMap.begin()->second.surface;
557 return mSurfaceFBIDMap[surfaceId].surface;
560 // TODO: all this stuff should go into some vulkan cache
562 void Graphics::AddBuffer( Handle<Buffer> buffer )
564 mBuffersCache.push_back( buffer );
567 void Graphics::AddImage( Handle<Image> image )
569 mImageCache.push_back( image );
572 void Graphics::AddPipeline( Handle<Pipeline> pipeline )
574 mPipelineCache.push_back( pipeline );
577 void Graphics::AddShader( Handle<Shader> shader )
579 mShaderCache.push_back( shader );
582 void Graphics::AddCommandPool( Handle<CommandPool> pool )
584 mCommandPoolCache.push_back( pool );
587 void Graphics::AddDescriptorPool( Handle<DescriptorPool> pool )
589 mDescriptorPoolCache.push_back( pool );
592 void Graphics::AddFramebuffer( Handle<Framebuffer> framebuffer )
594 mFramebufferCache.push_back( framebuffer );
597 void Graphics::RemoveBuffer( Buffer& buffer )
600 for( auto&& iter : mBuffersCache )
602 if( &*iter == &buffer )
605 mBuffersCache.erase( mBuffersCache.begin()+index );
611 void Graphics::RemoveShader( Shader& shader )
614 for( auto&& iter : mShaderCache )
616 if( &*iter == &shader )
619 mShaderCache.erase( mShaderCache.begin()+index );
626 void Graphics::RemoveCommandPool( CommandPool& commandPool )
631 void Graphics::RemoveDescriptorPool( std::unique_ptr<DescriptorPool> pool )
636 ShaderRef Graphics::FindShader( vk::ShaderModule shaderModule )
638 for( auto&& iter : mShaderCache )
640 if( iter->GetVkShaderModule() == shaderModule )
642 return Handle<Shader>(&*iter);
645 return Handle<Shader>();
648 ImageRef Graphics::FindImage( vk::Image image )
650 for( auto&& iter : mImageCache )
652 if( iter->GetVkImage() == image )
654 return ImageRef(&*iter);
662 } // namespace Vulkan
663 } // namespace Graphics