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>
34 #include <dali/graphics-api/graphics-api-controller.h>
36 #ifndef VK_KHR_XLIB_SURFACE_EXTENSION_NAME
37 #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
40 #ifndef VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
41 #define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface"
44 #ifndef VK_KHR_XCB_SURFACE_EXTENSION_NAME
45 #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
54 using VkSurfaceFactory = Dali::Integration::Graphics::Vulkan::VkSurfaceFactory;
58 const auto VALIDATION_LAYERS = std::vector< const char* >{
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
74 Graphics::Graphics() = default;
76 Graphics::~Graphics() = default;
77 #pragma GCC diagnostic push
78 #pragma GCC diagnostic ignored "-Wframe-larger-than="
80 Platform Graphics::GetDefaultPlatform() const
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;
93 Dali::Graphics::API::Controller& Graphics::GetController()
97 mGfxController = Dali::Graphics::Vulkan::Controller::New(*this);
100 return *mGfxController.get();
103 std::vector<const char*> Graphics::PrepareDefaultInstanceExtensions()
105 auto extensions = vk::enumerateInstanceExtensionProperties();
107 std::string extensionName;
109 bool xlibAvailable { false };
110 bool xcbAvailable { false };
111 bool waylandAvailable { false };
113 for( auto&& ext : extensions.value )
115 extensionName = ext.extensionName;
116 if( extensionName == VK_KHR_XCB_SURFACE_EXTENSION_NAME )
120 else if( extensionName == VK_KHR_XLIB_SURFACE_EXTENSION_NAME )
122 xlibAvailable = true;
124 else if( extensionName == VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME )
126 waylandAvailable = true;
130 std::vector<const char*> retval;
132 // depending on the platform validate extensions
133 auto platform = GetDefaultPlatform();
135 if( platform != Platform::UNDEFINED )
137 if (platform == Platform::XCB && xcbAvailable)
139 retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
141 else if (platform == Platform::XLIB && xlibAvailable)
143 retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
145 else if (platform == Platform::WAYLAND && waylandAvailable)
147 retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
150 else // try to determine the platform based on available extensions
154 mPlatform = Platform::XCB;
155 retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
157 else if (xlibAvailable)
159 mPlatform = Platform::XLIB;
160 retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
162 else if (waylandAvailable)
164 mPlatform = Platform::WAYLAND;
165 retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
169 // can't determine the platform!
170 mPlatform = Platform::UNDEFINED;
174 // other essential extensions
175 retval.push_back( VK_KHR_SURFACE_EXTENSION_NAME );
176 retval.push_back( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );
181 void Graphics::Create()
184 auto extensions = PrepareDefaultInstanceExtensions();
186 auto layers = vk::enumerateInstanceLayerProperties();
187 std::vector<const char*> validationLayers;
188 for( auto&& reqLayer : VALIDATION_LAYERS )
190 for( auto&& prop : layers.value )
192 //std::cout << prop.layerName << std::endl;
193 if( std::string(prop.layerName) == reqLayer )
195 validationLayers.push_back(reqLayer);
200 CreateInstance(extensions, validationLayers);
201 PreparePhysicalDevice();
204 void Graphics::CreateInstance( const std::vector<const char*>& extensions, const std::vector<const char*>& validationLayers )
206 auto info = vk::InstanceCreateInfo{};
208 info.setEnabledExtensionCount(U32(extensions.size()))
209 .setPpEnabledExtensionNames(extensions.data())
210 //.setEnabledLayerCount(U32(validationLayers.size()))
211 .setEnabledLayerCount(0)
212 .setPpEnabledLayerNames(validationLayers.data());
214 mInstance = VkAssert(vk::createInstance(info, *mAllocator));
217 void Graphics::DestroyInstance()
221 mInstance.destroy(*mAllocator);
227 void Graphics::PreparePhysicalDevice()
229 auto devices = VkAssert(mInstance.enumeratePhysicalDevices());
230 assert(devices.size() > 0 && "No Vulkan supported device found!");
232 // if only one, pick first
233 mPhysicalDevice = nullptr;
234 if(devices.size() == 1)
236 mPhysicalDevice = devices[0];
238 else // otherwise look for one which is a graphics device
240 for(auto& device : devices)
242 auto properties =device.getProperties();
243 if(properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ||
244 properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu)
246 mPhysicalDevice = device;
252 assert(mPhysicalDevice && "No suitable Physical Device found!");
254 GetPhysicalDeviceProperties();
256 GetQueueFamilyProperties();
258 mDeviceMemoryManager = GpuMemoryManager::New( *this );
260 #pragma GCC diagnostic pop
262 #pragma GCC diagnostic push
263 #pragma GCC diagnostic ignored "-Wframe-larger-than="
264 void Graphics::GetPhysicalDeviceProperties()
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());
274 #pragma GCC diagnostic pop
276 void Graphics::GetQueueFamilyProperties()
278 mQueueFamilyProperties = std::move(mPhysicalDevice.getQueueFamilyProperties());
281 FBID Graphics::CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory)
283 const auto vkFactory = dynamic_cast< const VkSurfaceFactory* >(surfaceFactory.get());
289 auto surface = vkFactory->Create(mInstance, mAllocator.get(), mPhysicalDevice);
291 // map surface to FBID
292 auto fbid = ++mBaseFBID;
293 mSurfaceFBIDMap[fbid] = MakeUnique<Surface>(*this, surface, 3u);
297 #pragma GCC diagnostic push
298 #pragma GCC diagnostic ignored "-Wframe-larger-than="
299 std::vector< vk::DeviceQueueCreateInfo > Graphics::GetQueueCreateInfos()
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!");
306 auto queueInfos = std::vector< vk::DeviceQueueCreateInfo >{};
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);
314 auto& graphicsFamily = familyIndexType[0];
317 auto& transferFamily = familyIndexType[1];
320 auto& presentFamily = familyIndexType[2];
322 auto queueFamilyIndex = 0u;
323 for(auto& prop : mQueueFamilyProperties)
325 if((prop.queueFlags & vk::QueueFlagBits::eGraphics) && graphicsFamily == -1u)
327 graphicsFamily = queueFamilyIndex;
329 if((prop.queueFlags & vk::QueueFlagBits::eTransfer) && transferFamily == -1u)
331 transferFamily = queueFamilyIndex;
333 if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.get()->GetSurfaceKHR())
335 presentFamily == -1u)
337 presentFamily = queueFamilyIndex;
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!");
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.
350 std::sort(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES]);
352 // allocate all queues from graphics family
353 uint32_t prevQueueFamilyIndex = -1u;
355 for(auto i = 0u; i < MAX_QUEUE_TYPES; ++i)
357 auto& familyIndex = familyIndexType[i];
358 if(prevQueueFamilyIndex == familyIndex)
363 auto& queueCount = mQueueFamilyProperties[familyIndex].queueCount;
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;
378 #pragma GCC diagnostic pop
380 #pragma GCC diagnostic push
381 #pragma GCC diagnostic ignored "-Wframe-larger-than="
382 void Graphics::CreateDevice()
384 auto queueInfos = GetQueueCreateInfos();
386 auto maxQueueCountPerFamily = 0u;
387 for( auto&& info : queueInfos )
389 maxQueueCountPerFamily = std::max( info.queueCount, maxQueueCountPerFamily );
392 auto priorities = std::vector<float>( maxQueueCountPerFamily );
393 std::fill( priorities.begin(), priorities.end(), 1.0f );
395 for( auto& info : queueInfos )
397 info.setPQueuePriorities( priorities.data() );
400 auto extensions = std::vector< const char* >{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
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()));
409 mDevice = VkAssert(mPhysicalDevice.createDevice(info, *mAllocator));
412 // create Queue objects
413 for(auto& queueInfo : queueInfos)
415 for(auto i = 0u; i < queueInfo.queueCount; ++i)
417 auto queue = mDevice.getQueue(queueInfo.queueFamilyIndex, i);
419 // based on family push queue instance into right array
420 auto flags = mQueueFamilyProperties[queueInfo.queueFamilyIndex].queueFlags;
421 if(flags & vk::QueueFlagBits::eGraphics)
423 mGraphicsQueues.emplace_back(
424 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
426 if(flags & vk::QueueFlagBits::eTransfer)
428 mTransferQueues.emplace_back(
429 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
431 if(flags & vk::QueueFlagBits::eCompute)
433 mComputeQueues.emplace_back(
434 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
437 // todo: present queue
441 #pragma GCC diagnostic pop
443 vk::Device Graphics::GetDevice() const
448 vk::PhysicalDevice Graphics::GetPhysicalDevice() const
450 return mPhysicalDevice;
453 vk::Instance Graphics::GetInstance() const
458 const vk::AllocationCallbacks& Graphics::GetAllocator() const
463 Queue& Graphics::GetGraphicsQueue(uint32_t index) const
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!");
469 return *mGraphicsQueues[0].get(); // will be mGraphicsQueues[index]
472 Queue& Graphics::GetTransferQueue(uint32_t index) const
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!");
478 return *mTransferQueues[0].get(); // will be mGraphicsQueues[index]
481 Queue& Graphics::GetComputeQueue(uint32_t index) const
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!");
487 return *mComputeQueues[0].get(); // will be mGraphicsQueues[index]
490 Queue& Graphics::GetPresentQueue() const
492 return *mPresentQueue.get();
495 Handle< CommandPool > Graphics::CreateCommandPool(const vk::CommandPoolCreateInfo& info)
497 auto cmdpool = CommandPool::New( *this, vk::CommandPoolCreateInfo{}.
498 setQueueFamilyIndex( 0u ).
499 setFlags( vk::CommandPoolCreateFlagBits::eResetCommandBuffer ) );
503 Surface& Graphics::GetSurface( FBID surfaceId )
505 // TODO: FBID == 0 means default framebuffer, but there should be no
506 // such thing as default framebuffer.
509 return *mSurfaceFBIDMap.begin()->second.get();
511 return *mSurfaceFBIDMap[surfaceId].get();
514 // TODO: all this stuff should go into some vulkan cache
516 void Graphics::AddBuffer( Handle<Buffer> buffer )
518 mBuffersCache.push_back( buffer );
521 void Graphics::AddImage( Handle<Image> image )
523 mImageCache.push_back( image );
526 void Graphics::AddPipeline( Handle<Pipeline> pipeline )
528 mPipelineCache.push_back( pipeline );
531 void Graphics::AddShader( Handle<Shader> shader )
533 mShaderCache.push_back( shader );
536 void Graphics::AddCommandPool( Handle<CommandPool> pool )
538 mCommandPoolCache.push_back( pool );
541 void Graphics::AddDescriptorPool( Handle<DescriptorPool> pool )
543 mDescriptorPoolCache.push_back( pool );
546 void Graphics::AddFramebuffer( Handle<Framebuffer> framebuffer )
548 mFramebufferCache.push_back( framebuffer );
551 void Graphics::RemoveBuffer( Buffer& buffer )
554 for( auto&& iter : mBuffersCache )
556 if( &*iter == &buffer )
559 mBuffersCache.erase( mBuffersCache.begin()+index );
565 void Graphics::RemoveShader( Shader& shader )
568 for( auto&& iter : mShaderCache )
570 if( &*iter == &shader )
573 mShaderCache.erase( mShaderCache.begin()+index );
580 void Graphics::RemoveCommandPool( CommandPool& commandPool )
585 void Graphics::RemoveDescriptorPool( std::unique_ptr<DescriptorPool> pool )
590 Handle<Shader> Graphics::FindShader( vk::ShaderModule shaderModule )
592 for( auto&& iter : mShaderCache )
594 if( iter->GetVkShaderModule() == shaderModule )
596 return Handle<Shader>(&*iter);
599 return Handle<Shader>();
603 } // namespace Vulkan
604 } // namespace Graphics