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/api/vulkan-api-controller.h>
33 #include <dali/graphics/vulkan/vulkan-pipeline-cache.h>
34 #include <dali/graphics/vulkan/vulkan-sampler.h>
35 #include <dali/graphics/vulkan/vulkan-resource-cache.h>
36 #include <dali/graphics/vulkan/vulkan-debug.h>
37 #include <dali/graphics-api/graphics-api-controller.h>
39 #ifndef VK_KHR_XLIB_SURFACE_EXTENSION_NAME
40 #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
43 #ifndef VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
44 #define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface"
47 #ifndef VK_KHR_XCB_SURFACE_EXTENSION_NAME
48 #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;
77 Graphics::~Graphics() = default;
79 // Create methods -----------------------------------------------------------------------------------------------
80 void Graphics::Create()
83 auto extensions = PrepareDefaultInstanceExtensions();
85 auto layers = vk::enumerateInstanceLayerProperties();
86 std::vector<const char*> validationLayers;
87 for( auto&& reqLayer : VALIDATION_LAYERS )
89 for( auto&& prop : layers.value )
91 DALI_LOG_STREAM( gVulkanFilter, Debug::General, prop.layerName );
92 if( std::string(prop.layerName) == reqLayer )
94 validationLayers.push_back(reqLayer);
99 CreateInstance(extensions, validationLayers);
100 PreparePhysicalDevice();
103 #pragma GCC diagnostic push
104 #pragma GCC diagnostic ignored "-Wframe-larger-than="
105 void Graphics::CreateDevice()
107 auto queueInfos = GetQueueCreateInfos();
109 auto maxQueueCountPerFamily = 0u;
110 for( auto&& info : queueInfos )
112 maxQueueCountPerFamily = std::max( info.queueCount, maxQueueCountPerFamily );
115 auto priorities = std::vector<float>( maxQueueCountPerFamily );
116 std::fill( priorities.begin(), priorities.end(), 1.0f );
118 for( auto& info : queueInfos )
120 info.setPQueuePriorities( priorities.data() );
123 std::vector< const char* > extensions{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
125 auto info = vk::DeviceCreateInfo{};
126 info.setEnabledExtensionCount(U32(extensions.size()))
127 .setPpEnabledExtensionNames(extensions.data())
128 .setPEnabledFeatures(&(*mPhysicalDeviceFeatures))
129 .setPQueueCreateInfos(queueInfos.data())
130 .setQueueCreateInfoCount(U32(queueInfos.size()));
132 mDevice = VkAssert(mPhysicalDevice.createDevice(info, *mAllocator));
135 // create Queue objects
136 for(auto& queueInfo : queueInfos)
138 for(auto i = 0u; i < queueInfo.queueCount; ++i)
140 auto queue = mDevice.getQueue(queueInfo.queueFamilyIndex, i);
142 // based on family push queue instance into right array
143 auto flags = mQueueFamilyProperties[queueInfo.queueFamilyIndex].queueFlags;
144 if(flags & vk::QueueFlagBits::eGraphics)
146 mGraphicsQueues.emplace_back(
147 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
149 if(flags & vk::QueueFlagBits::eTransfer)
151 mTransferQueues.emplace_back(
152 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
154 if(flags & vk::QueueFlagBits::eCompute)
156 mComputeQueues.emplace_back(
157 MakeUnique<Queue>(*this, queue, queueInfo.queueFamilyIndex, i, flags));
160 // todo: present queue
164 mPipelineDatabase = std::make_unique<PipelineCache>( *this );
165 mResourceCacheMap[std::this_thread::get_id()] = MakeUnique<ResourceCache>();
167 #pragma GCC diagnostic pop
169 void Graphics::GetPhysicalDeviceProperties()
171 // store data on heap to keep object smaller
172 mPhysicalDeviceProperties =
173 MakeUnique<vk::PhysicalDeviceProperties>(mPhysicalDevice.getProperties());
174 mPhysicalDeviceMemoryProperties =
175 MakeUnique<vk::PhysicalDeviceMemoryProperties>(mPhysicalDevice.getMemoryProperties());
176 mPhysicalDeviceFeatures =
177 MakeUnique<vk::PhysicalDeviceFeatures>(mPhysicalDevice.getFeatures());
180 void Graphics::GetQueueFamilyProperties()
182 mQueueFamilyProperties = mPhysicalDevice.getQueueFamilyProperties();
185 FBID Graphics::CreateSurface(std::unique_ptr< SurfaceFactory > surfaceFactory)
187 // create surface from the factory
188 auto surfaceRef = Surface::New( *this, std::move(surfaceFactory) );
190 if( surfaceRef->Create() )
193 // map surface to FBID
194 auto fbid = ++mBaseFBID;
195 mSurfaceFBIDMap[fbid] = SwapchainSurfacePair{ RefCountedSwapchain{}, surfaceRef };
201 RefCountedSwapchain Graphics::CreateSwapchainForSurface( RefCountedSurface surface )
203 auto swapchain = Swapchain::New( *this,
204 GetGraphicsQueue(0u),
207 // store swapchain in the correct pair
208 for( auto&& val : mSurfaceFBIDMap )
210 if( val.second.surface == surface )
212 val.second.swapchain = swapchain;
220 RefCountedShader Graphics::CreateShader()
225 RefCountedPipeline Graphics::CreatePipeline()
230 RefCountedFence Graphics::CreateFence( const vk::FenceCreateInfo& fenceCreateInfo )
232 auto refCountedFence = Fence::New(*this);
234 VkAssert(mDevice.createFence(&fenceCreateInfo, mAllocator.get(), refCountedFence->Ref()));
236 return refCountedFence;
239 RefCountedBuffer Graphics::CreateBuffer(size_t size, BufferType type)
241 auto usageFlags = vk::BufferUsageFlags{};
244 case BufferType::VERTEX: {
245 usageFlags |= vk::BufferUsageFlagBits::eVertexBuffer;
248 case BufferType::INDEX: {
249 usageFlags |= vk::BufferUsageFlagBits::eIndexBuffer;
252 case BufferType::UNIFORM: {
253 usageFlags |= vk::BufferUsageFlagBits::eUniformBuffer;
256 case BufferType::SHADER_STORAGE: {
257 usageFlags |= vk::BufferUsageFlagBits::eStorageBuffer;
262 auto info = vk::BufferCreateInfo{};
263 info.setSharingMode(vk::SharingMode::eExclusive);
265 info.setUsage(usageFlags | vk::BufferUsageFlagBits::eTransferDst);
267 auto refCountedBuffer = Buffer::New(*this, info);
269 VkAssert(mDevice.createBuffer(&info, mAllocator.get(), refCountedBuffer->Ref()));
271 AddBuffer(refCountedBuffer);
273 return refCountedBuffer;
276 RefCountedBuffer Graphics::CreateBuffer( const vk::BufferCreateInfo& bufferCreateInfo )
278 auto refCountedBuffer = Buffer::New(*this, bufferCreateInfo);
280 VkAssert(mDevice.createBuffer(&bufferCreateInfo, mAllocator.get(), refCountedBuffer->Ref()));
282 AddBuffer(refCountedBuffer);
284 return refCountedBuffer;
287 RefCountedFramebuffer Graphics::CreateFramebuffer()
292 RefCountedImage Graphics::CreateImage()
297 RefCountedImageView Graphics::CreateImageView()
302 RefCountedDescriptorPool Graphics::CreateDescriptorPool()
307 RefCountedCommandPool Graphics::CreateCommandPool(const vk::CommandPoolCreateInfo& info)
309 return CommandPool::New( *this,
310 vk::CommandPoolCreateInfo{}.setQueueFamilyIndex( 0u )
311 .setFlags( vk::CommandPoolCreateFlagBits::eResetCommandBuffer ) );
314 RefCountedCommandBuffer Graphics::CreateCommandBuffer()
319 std::vector<RefCountedCommandBuffer> Graphics::CreateCommandBuffers()
324 RefCountedGpuMemoryBlock Graphics::CreateGpuMemoryBlock()
329 RefCountedDescriptorSet Graphics::CreateDescriptorSet()
334 RefCountedSampler Graphics::CreateSampler()
338 // --------------------------------------------------------------------------------------------------------------
340 // Actions ------------------------------------------------------------------------------------------------------
341 vk::Result Graphics::WaitForFence( RefCountedFence fence, uint32_t timeout )
343 return mDevice.waitForFences(1, *fence, VK_TRUE, timeout);
345 #pragma GCC diagnostic pop
347 vk::Result Graphics::WaitForFences( const std::vector<RefCountedFence>& fences, bool waitAll, uint32_t timeout )
349 std::vector<vk::Fence> vkFenceHandles{};
350 std::transform(fences.begin(),
352 std::back_inserter(vkFenceHandles),
353 [](RefCountedFence entry){ return entry->GetVkHandle(); });
355 auto priorities = std::vector<float>( maxQueueCountPerFamily );
356 std::fill( priorities.begin(), priorities.end(), 1.0f );
358 return mDevice.waitForFences(vkFenceHandles, vk::Bool32(waitAll), timeout);
361 vk::Result Graphics::ResetFence( RefCountedFence fence )
363 return mDevice.resetFences(1, *fence);
366 vk::Result Graphics::ResetFences( const std::vector<RefCountedFence>& fences )
368 std::vector<vk::Fence> vkFenceHandles{};
369 std::transform(fences.begin(),
371 std::back_inserter(vkFenceHandles),
372 [](RefCountedFence entry){ return entry->GetVkHandle(); });
374 return mDevice.resetFences(vkFenceHandles);
376 // --------------------------------------------------------------------------------------------------------------
378 // Getters ------------------------------------------------------------------------------------------------------
379 RefCountedSurface Graphics::GetSurface( FBID surfaceId )
381 // TODO: FBID == 0 means default framebuffer, but there should be no
382 // such thing as default framebuffer.
385 return mSurfaceFBIDMap.begin()->second.surface;
387 return mSurfaceFBIDMap[surfaceId].surface;
390 RefCountedSwapchain Graphics::GetSwapchainForSurface( RefCountedSurface surface )
392 for( auto&& val : mSurfaceFBIDMap )
394 if( val.second.surface == surface )
400 return RefCountedSwapchain();
403 RefCountedSwapchain Graphics::GetSwapchainForFBID( FBID surfaceId )
407 return mSurfaceFBIDMap.begin()->second.swapchain;
409 return mSurfaceFBIDMap[surfaceId].swapchain;
411 #pragma GCC diagnostic pop
413 vk::Device Graphics::GetDevice() const
418 vk::PhysicalDevice Graphics::GetPhysicalDevice() const
420 return mPhysicalDevice;
423 vk::Instance Graphics::GetInstance() const
428 const vk::AllocationCallbacks& Graphics::GetAllocator() const
433 GpuMemoryManager& Graphics::GetDeviceMemoryManager() const
435 return *mDeviceMemoryManager;
438 const vk::PhysicalDeviceMemoryProperties& Graphics::GetMemoryProperties() const
440 return *mPhysicalDeviceMemoryProperties;
443 Queue& Graphics::GetGraphicsQueue(uint32_t index) const
445 // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
446 // this will change in the future
447 assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
449 return *mGraphicsQueues[0]; // will be mGraphicsQueues[index]
452 Queue& Graphics::GetTransferQueue(uint32_t index) const
454 // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
455 // this will change in the future
456 assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
458 return *mTransferQueues[0]; // will be mGraphicsQueues[index]
461 Queue& Graphics::GetComputeQueue(uint32_t index) const
463 // todo: at the moment each type of queue may use only one, indices greater than 0 are invalid
464 // this will change in the future
465 assert(index == 0u && "Each type of queue may use only one, indices greater than 0 are invalid!");
467 return *mComputeQueues[0]; // will be mGraphicsQueues[index]
470 Queue& Graphics::GetPresentQueue() const
472 // fixme: should be a dedicated presentation queue
473 return GetGraphicsQueue(0);
476 Platform Graphics::GetDefaultPlatform() const
478 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
479 mPlatform = Platform::WAYLAND;
480 #elif VK_USE_PLATFORM_XCB_KHR
481 mPlatform = Platform::XCB;
482 #elif VK_USE_PLATFORM_XLIB_KHR
483 mPlatform = Platform::XLIB;
489 Dali::Graphics::API::Controller& Graphics::GetController()
493 mGfxController = Dali::Graphics::VulkanAPI::Controller::New(*this);
496 return *mGfxController;
499 PipelineCache& Graphics::GetPipelineCache()
501 return *mPipelineDatabase;
503 // --------------------------------------------------------------------------------------------------------------
505 // Cache manipulation methods -----------------------------------------------------------------------------------
506 void Graphics::AddBuffer( Handle<Buffer> buffer )
508 GetResourceCache(std::this_thread::get_id())->AddBuffer(std::move(buffer));
511 void Graphics::AddImage( Handle<Image> image )
513 GetResourceCache(std::this_thread::get_id())->AddImage(std::move(image));
516 void Graphics::AddShader( Handle<Shader> shader )
518 GetResourceCache(std::this_thread::get_id())->AddShader(std::move(shader));
521 void Graphics::AddCommandPool( Handle<CommandPool> pool )
523 GetResourceCache(std::this_thread::get_id())->AddCommandPool(std::move(pool));
526 void Graphics::AddDescriptorPool( Handle<DescriptorPool> pool )
528 GetResourceCache(std::this_thread::get_id())->AddDescriptorPool(std::move(pool));
531 void Graphics::AddFramebuffer( Handle<Framebuffer> framebuffer )
533 GetResourceCache(std::this_thread::get_id())->AddFramebuffer(std::move(framebuffer));
536 RefCountedShader Graphics::FindShader( vk::ShaderModule shaderModule )
538 return GetResourceCache(std::this_thread::get_id())->FindShader(shaderModule);
541 RefCountedImage Graphics::FindImage( vk::Image image )
543 return GetResourceCache(std::this_thread::get_id())->FindImage(image);
546 void Graphics::RemoveBuffer( Buffer& buffer )
548 GetResourceCache(std::this_thread::get_id())->RemoveBuffer(buffer);
551 void Graphics::RemoveShader( Shader& shader )
553 GetResourceCache(std::this_thread::get_id())->RemoveShader(shader);
556 void Graphics::RemoveCommandPool( CommandPool& commandPool )
558 GetResourceCache(std::this_thread::get_id())->RemoveCommandPool(commandPool);
561 void Graphics::RemoveDescriptorPool( DescriptorPool& pool )
563 GetResourceCache(std::this_thread::get_id())->RemoveDescriptorPool(pool);
566 void Graphics::RemoveFramebuffer( Framebuffer& framebuffer )
568 GetResourceCache(std::this_thread::get_id())->RemoveFramebuffer(framebuffer);
571 void Graphics::RemoveSampler( Sampler& sampler )
573 GetResourceCache(std::this_thread::get_id())->RemoveSampler(sampler);
576 void Graphics::CollectGarbage()
578 GetResourceCache(std::this_thread::get_id())->CollectGarbage();
581 void Graphics::DiscardResource( std::function<void()> deleter )
583 GetResourceCache(std::this_thread::get_id())->EnqueueDiscardOperation(std::move(deleter));
585 // --------------------------------------------------------------------------------------------------------------
588 void Graphics::CreateInstance( const std::vector<const char*>& extensions, const std::vector<const char*>& validationLayers )
590 auto info = vk::InstanceCreateInfo{};
592 info.setEnabledExtensionCount(U32(extensions.size()))
593 .setPpEnabledExtensionNames(extensions.data())
594 .setEnabledLayerCount(U32(validationLayers.size()))
595 .setPpEnabledLayerNames(validationLayers.data());
597 #if defined(DEBUG_ENABLED)
598 if( ! getenv("LOG_VULKAN") )
600 info.setEnabledLayerCount(0);
604 mInstance = VkAssert(vk::createInstance(info, *mAllocator));
607 void Graphics::DestroyInstance()
611 mInstance.destroy(*mAllocator);
617 void Graphics::PreparePhysicalDevice()
619 auto devices = VkAssert(mInstance.enumeratePhysicalDevices());
620 assert(!devices.empty() && "No Vulkan supported device found!");
622 // if only one, pick first
623 mPhysicalDevice = nullptr;
624 if(devices.size() == 1)
626 mPhysicalDevice = devices[0];
628 else // otherwise look for one which is a graphics device
630 for(auto& device : devices)
632 auto properties =device.getProperties();
633 if(properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ||
634 properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu)
636 mPhysicalDevice = device;
642 assert(mPhysicalDevice && "No suitable Physical Device found!");
644 GetPhysicalDeviceProperties();
646 GetQueueFamilyProperties();
648 mDeviceMemoryManager = GpuMemoryManager::New( *this );
651 void Graphics::GetPhysicalDeviceProperties()
653 // store data on heap to keep object smaller
654 mPhysicalDeviceProperties =
655 MakeUnique<vk::PhysicalDeviceProperties>(mPhysicalDevice.getProperties());
656 mPhysicalDeviceMemoryProperties =
657 MakeUnique<vk::PhysicalDeviceMemoryProperties>(mPhysicalDevice.getMemoryProperties());
658 mPhysicalDeviceFeatures =
659 MakeUnique<vk::PhysicalDeviceFeatures>(mPhysicalDevice.getFeatures());
662 void Graphics::GetQueueFamilyProperties()
664 mQueueFamilyProperties = mPhysicalDevice.getQueueFamilyProperties();
667 #pragma GCC diagnostic push
668 #pragma GCC diagnostic ignored "-Wframe-larger-than="
669 std::vector< vk::DeviceQueueCreateInfo > Graphics::GetQueueCreateInfos()
671 // surface is needed in order to find a family that supports presentation to this surface
672 // fixme: assuming all surfaces will be compatible with the queue family
673 assert(!mSurfaceFBIDMap.empty() &&
674 "At least one surface has to be created before creating VkDevice!");
676 std::vector< vk::DeviceQueueCreateInfo > queueInfos{};
678 constexpr uint8_t MAX_QUEUE_TYPES = 3;
679 // find suitable family for each type of queue
680 uint32_t familyIndexType[MAX_QUEUE_TYPES];
681 std::fill(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES], -1u);
684 auto& graphicsFamily = familyIndexType[0];
687 auto& transferFamily = familyIndexType[1];
690 auto& presentFamily = familyIndexType[2];
692 auto queueFamilyIndex = 0u;
693 for(auto& prop : mQueueFamilyProperties)
695 if((prop.queueFlags & vk::QueueFlagBits::eGraphics) && graphicsFamily == -1u)
697 graphicsFamily = queueFamilyIndex;
699 if((prop.queueFlags & vk::QueueFlagBits::eTransfer) && transferFamily == -1u)
701 transferFamily = queueFamilyIndex;
703 if(mPhysicalDevice.getSurfaceSupportKHR(queueFamilyIndex, mSurfaceFBIDMap.begin()->second.surface->GetSurfaceKHR())
705 presentFamily == -1u)
707 presentFamily = queueFamilyIndex;
712 assert(graphicsFamily != -1u && "No queue family that supports graphics operations!");
713 assert(transferFamily != -1u && "No queue family that supports transfer operations!");
714 assert(presentFamily != -1u && "No queue family that supports present operations!");
716 // todo: we may require that the family must be same for all types of operations, it makes
717 // easier to handle synchronisation related issues.
720 std::sort(&familyIndexType[0], &familyIndexType[MAX_QUEUE_TYPES]);
722 // allocate all queues from graphics family
723 uint32_t prevQueueFamilyIndex = -1u;
725 for(auto i = 0u; i < MAX_QUEUE_TYPES; ++i)
727 auto& familyIndex = familyIndexType[i];
728 if(prevQueueFamilyIndex == familyIndex)
733 auto& queueCount = mQueueFamilyProperties[familyIndex].queueCount;
735 // fill queue create info for the family.
736 // note the priorities are not being set as local pointer will out of scope, this
737 // will be fixed by the caller function
738 auto info = vk::DeviceQueueCreateInfo{}
739 .setPQueuePriorities(nullptr)
740 .setQueueCount(queueCount)
741 .setQueueFamilyIndex(familyIndex);
742 queueInfos.push_back(info);
743 prevQueueFamilyIndex = familyIndex;
748 #pragma GCC diagnostic pop
750 std::vector<const char*> Graphics::PrepareDefaultInstanceExtensions()
752 auto extensions = vk::enumerateInstanceExtensionProperties();
754 std::string extensionName;
756 bool xlibAvailable { false };
757 bool xcbAvailable { false };
758 bool waylandAvailable { false };
760 for( auto&& ext : extensions.value )
762 extensionName = ext.extensionName;
763 if( extensionName == VK_KHR_XCB_SURFACE_EXTENSION_NAME )
767 else if( extensionName == VK_KHR_XLIB_SURFACE_EXTENSION_NAME )
769 xlibAvailable = true;
771 else if( extensionName == VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME )
773 waylandAvailable = true;
777 std::vector<const char*> retval{};
779 // depending on the platform validate extensions
780 auto platform = GetDefaultPlatform();
782 if( platform != Platform::UNDEFINED )
784 if (platform == Platform::XCB && xcbAvailable)
786 retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
788 else if (platform == Platform::XLIB && xlibAvailable)
790 retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
792 else if (platform == Platform::WAYLAND && waylandAvailable)
794 retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
797 else // try to determine the platform based on available extensions
801 mPlatform = Platform::XCB;
802 retval.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
804 else if (xlibAvailable)
806 mPlatform = Platform::XLIB;
807 retval.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
809 else if (waylandAvailable)
811 mPlatform = Platform::WAYLAND;
812 retval.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
816 // can't determine the platform!
817 mPlatform = Platform::UNDEFINED;
821 // other essential extensions
822 retval.push_back( VK_KHR_SURFACE_EXTENSION_NAME );
823 retval.push_back( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );
828 std::unique_ptr<ResourceCache>& Graphics::GetResourceCache(std::thread::id threadId)
830 if( mResourceCacheMap.count(threadId) == 0 )
832 std::lock_guard<std::mutex> lock{ mMutex };
833 mResourceCacheMap[threadId] = MakeUnique< ResourceCache >();
836 return mResourceCacheMap[threadId];
839 } // namespace Vulkan
840 } // namespace Graphics