// Find and create a compute capable device queue void getComputeQueue() { uint32_t queueIndex = 0; uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL); assert(queueCount >= 1); std::vector<VkQueueFamilyProperties> queueProps; queueProps.resize(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data()); for (queueIndex = 0; queueIndex < queueCount; queueIndex++) { if (queueProps[queueIndex].queueFlags & VK_QUEUE_COMPUTE_BIT) break; } assert(queueIndex < queueCount); VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.pNext = NULL; queueCreateInfo.queueFamilyIndex = queueIndex; queueCreateInfo.queueCount = 1; vkGetDeviceQueue(device, queueIndex, 0, &computeQueue); }
static uint32_t getComputeQueueFamilyIndex() { uint32_t queueFamilyCount; vkGetPhysicalDeviceQueueFamilyProperties(kPhysicalDevice, &queueFamilyCount, NULL); std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(kPhysicalDevice, &queueFamilyCount, queueFamilies.data()); uint32_t i = 0; for (; i < queueFamilies.size(); ++i) { VkQueueFamilyProperties props = queueFamilies[i]; if (props.queueCount > 0 && (props.queueFlags & VK_QUEUE_COMPUTE_BIT)) { break; } } if (i == queueFamilies.size()) { throw std::runtime_error("could not find a queue family that supports operations"); } return i; }
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) { QueueFamilyIndices indices; uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); int i = 0; for (const auto& queueFamily : queueFamilies) { if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { indices.graphicsFamily = i; } VkBool32 presentSupport = false; vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); if (queueFamily.queueCount > 0 && presentSupport) { indices.presentFamily = i; } if (indices.isComplete()) { break; } i++; } return indices; }
/** * Get the index of a queue family that supports the requested queue flags * * @param queueFlags Queue flags to find a queue family index for * * @return INdex * * @throw Throws an exception if no queue family index could be found that supports the requested flags */ uint32_t getQueueFamiliyIndex(VkQueueFlagBits queueFlags) { uint32_t queueCount; // Get number of available queue families on this device vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL); assert(queueCount >= 1); // Get available queue families std::vector<VkQueueFamilyProperties> queueProps; queueProps.resize(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data()); for (uint32_t i = 0; i < queueCount; i++) { if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { return i; break; } } // todo: Advanced search for devices that have dedicated queues for compute and transfer // Try to find queues with only the requested flags or (if not present) with as few // other flags set as possible (example: http://vulkan.gpuinfo.org/displayreport.php?id=509#queuefamilies) #if defined(__ANDROID__) //todo : Exceptions are disabled by default on Android (need to add LOCAL_CPP_FEATURES += exceptions to Android.mk), so for now just return zero return 0; #else throw std::runtime_error("Could not find a matching queue family index"); #endif }
VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 *pSupported) { const auto instance_dat = *GetGlobalContext().GetInstanceData( GetGlobalContext().GetPhysicalDeviceData(physicalDevice)->instance_); for (uint32_t i = 0; i <= queueFamilyIndex; ++i) { uint32_t property_count = 0; instance_dat.vkGetPhysicalDeviceQueueFamilyProperties( physicalDevice, &property_count, nullptr); assert(property_count > queueFamilyIndex); std::vector<VkQueueFamilyProperties> properties(property_count); instance_dat.vkGetPhysicalDeviceQueueFamilyProperties( physicalDevice, &property_count, properties.data()); if (properties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { *pSupported = (i == queueFamilyIndex); return VK_SUCCESS; } } // For now only support the FIRST graphics queue. It looks like all of // the commands we will have to run are transfer commands, so // we can probably get away with ANY queue (other than // SPARSE_BINDING). *pSupported = false; return VK_SUCCESS; }
int sample_main() { struct sample_info info = {}; init_instance(info, "vulkansamples_device"); init_enumerate_device(info); /* VULKAN_KEY_START */ VkDeviceQueueCreateInfo queue_info = {}; vkGetPhysicalDeviceQueueFamilyProperties(info.gpus[0], &info.queue_count, NULL); assert(info.queue_count >= 1); info.queue_props.resize(info.queue_count); vkGetPhysicalDeviceQueueFamilyProperties(info.gpus[0], &info.queue_count, info.queue_props.data()); assert(info.queue_count >= 1); bool found = false; for (unsigned int i = 0; i < info.queue_count; i++) { if (info.queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { queue_info.queueFamilyIndex = i; found = true; break; } } assert(found); assert(info.queue_count >= 1); float queue_priorities[1] = {0.0}; queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_info.pNext = NULL; queue_info.queueCount = 1; queue_info.pQueuePriorities = queue_priorities; VkDeviceCreateInfo device_info = {}; device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_info.pNext = NULL; device_info.queueCreateInfoCount = 1; device_info.pQueueCreateInfos = &queue_info; device_info.enabledExtensionCount = 0; device_info.ppEnabledExtensionNames = NULL; device_info.enabledLayerCount = 0; device_info.ppEnabledLayerNames = NULL; device_info.pEnabledFeatures = NULL; VkDevice device; VkResult U_ASSERT_ONLY res = vkCreateDevice(info.gpus[0], &device_info, NULL, &device); assert(res == VK_SUCCESS); vkDestroyDevice(device, NULL); /* VULKAN_KEY_END */ destroy_instance(info); return 0; }
TEST(WrapObjects, Insert) { VkInstance instance = VK_NULL_HANDLE; VkResult result = vkCreateInstance(VK::InstanceCreateInfo(), VK_NULL_HANDLE, &instance); ASSERT_EQ(result, VK_SUCCESS); uint32_t physicalCount = 0; result = vkEnumeratePhysicalDevices(instance, &physicalCount, nullptr); ASSERT_EQ(result, VK_SUCCESS); ASSERT_GT(physicalCount, 0u); std::unique_ptr<VkPhysicalDevice[]> physical(new VkPhysicalDevice[physicalCount]); result = vkEnumeratePhysicalDevices(instance, &physicalCount, physical.get()); ASSERT_EQ(result, VK_SUCCESS); ASSERT_GT(physicalCount, 0u); for(uint32_t p = 0; p < physicalCount; ++p) { uint32_t familyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical[p], &familyCount, nullptr); ASSERT_EQ(result, VK_SUCCESS); ASSERT_GT(familyCount, 0u); std::unique_ptr<VkQueueFamilyProperties[]> family(new VkQueueFamilyProperties[familyCount]); vkGetPhysicalDeviceQueueFamilyProperties(physical[p], &familyCount, family.get()); ASSERT_EQ(result, VK_SUCCESS); ASSERT_GT(familyCount, 0u); for(uint32_t q = 0; q < familyCount; ++q) { if(~family[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) { continue; } float const priorities[] = {0.0f}; // Temporary required due to MSVC bug. VkDeviceQueueCreateInfo const queueInfo[1] { VK::DeviceQueueCreateInfo(). queueFamilyIndex(q). queueCount(1). pQueuePriorities(priorities) }; auto const deviceInfo = VK::DeviceCreateInfo(). queueCreateInfoCount(1). pQueueCreateInfos(queueInfo); VkDevice device; result = vkCreateDevice(physical[p], deviceInfo, nullptr, &device); ASSERT_EQ(result, VK_SUCCESS); vkDestroyDevice(device, nullptr); } } vkDestroyInstance(instance, nullptr); }
Error GrManagerImpl::initDevice(const GrManagerInitInfo& init) { uint32_t count = 0; vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &count, nullptr); ANKI_LOGI("VK: Number of queue families: %u\n", count); DynamicArrayAuto<VkQueueFamilyProperties> queueInfos(getAllocator()); queueInfos.create(count); vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &count, &queueInfos[0]); uint32_t desiredFamilyIdx = MAX_U32; const VkQueueFlags DESITED_QUEUE_FLAGS = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; for(U i = 0; i < count; ++i) { if((queueInfos[i].queueFlags & DESITED_QUEUE_FLAGS) == DESITED_QUEUE_FLAGS) { VkBool32 supportsPresent = false; ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &supportsPresent)); if(supportsPresent) { desiredFamilyIdx = i; break; } } } if(desiredFamilyIdx == MAX_U32) { ANKI_LOGE("Couldn't find a queue family with graphics+compute+transfer+present." "The assumption was wrong. The code needs to be reworked"); return ErrorCode::FUNCTION_FAILED; } m_queueIdx = desiredFamilyIdx; F32 priority = 1.0; VkDeviceQueueCreateInfo q = {}; q.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; q.queueFamilyIndex = desiredFamilyIdx; q.queueCount = 1; q.pQueuePriorities = &priority; static Array<const char*, 1> DEV_EXTENSIONS = {{VK_KHR_SWAPCHAIN_EXTENSION_NAME}}; VkDeviceCreateInfo ci = {}; ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; ci.queueCreateInfoCount = 1; ci.pQueueCreateInfos = &q; ci.enabledExtensionCount = DEV_EXTENSIONS.getSize(); ci.ppEnabledExtensionNames = &DEV_EXTENSIONS[0]; ci.pEnabledFeatures = &m_devFeatures; ANKI_VK_CHECK(vkCreateDevice(m_physicalDevice, &ci, nullptr, &m_device)); return ErrorCode::NONE; }
Device::Device(VkPhysicalDevice physicalDevice) : physicalDevice(physicalDevice) { // select a queue family with compute support uint32_t numQueues; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, nullptr); VkQueueFamilyProperties *queueFamilyProperties = new VkQueueFamilyProperties[numQueues]; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, queueFamilyProperties); for (uint32_t i = 0; i < numQueues; i++) { if (queueFamilyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { computeQueueFamily = i; break; } } delete [] queueFamilyProperties; if (computeQueueFamily == -1) { throw ERROR_DEVICES; } VkDeviceQueueCreateInfo queueCreateInfo = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; queueCreateInfo.queueCount = 1; float priorities[] = {1.0f}; queueCreateInfo.pQueuePriorities = priorities; queueCreateInfo.queueFamilyIndex = computeQueueFamily; // create the logical device VkPhysicalDeviceFeatures physicalDeviceFeatures = {}; VkDeviceCreateInfo deviceCreateInfo = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; deviceCreateInfo.pEnabledFeatures = &physicalDeviceFeatures; deviceCreateInfo.queueCreateInfoCount = 1; if (VK_SUCCESS != vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device)) { throw ERROR_DEVICES; } vkGetDeviceQueue(device, computeQueueFamily, 0, &queue); vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties); // get indices of memory types we care about VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties; vkGetPhysicalDeviceMemoryProperties(physicalDevice, &physicalDeviceMemoryProperties); for (uint32_t i = 0; i < physicalDeviceMemoryProperties.memoryTypeCount; i++) { if (physicalDeviceMemoryProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT && memoryTypeMappable == -1) { memoryTypeMappable = i; } if (physicalDeviceMemoryProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT && memoryTypeLocal == -1) { memoryTypeLocal = i; } } // create the implicit command buffer implicitCommandBuffer = new CommandBuffer(*this); }
std::vector<VkQueueFamilyProperties> PhysicalDevice::queue_properties() const { std::vector<VkQueueFamilyProperties> info; uint32_t count; // Call once with NULL data to receive count vkGetPhysicalDeviceQueueFamilyProperties(handle(), &count, NULL); info.resize(count); vkGetPhysicalDeviceQueueFamilyProperties(handle(), &count, info.data()); return info; }
bool findSupportedQueue() { std::cout << "looking for supported queue..."; vkGetPhysicalDeviceQueueFamilyProperties( gDevices[0], &gQueueCount, nullptr ); gQueueProps.resize( gQueueCount ); vkGetPhysicalDeviceQueueFamilyProperties( gDevices[0], &gQueueCount, gQueueProps.data() ); VkWin32SurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = nullptr; createInfo.hinstance = ghInstance; createInfo.hwnd = ghWnd; createInfo.flags = 0; gQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; gQueueInfo.pNext = nullptr; gQueueInfo.queueCount = 1; gQueueInfo.pQueuePriorities = gQueuePriorities; VkResult res = vkCreateWin32SurfaceKHR( gInstance, &createInfo, nullptr, &gSurface ); if( res != VK_SUCCESS ) { std::cout << "surface creating error " << res << std::endl; return false; } gQueueFamilyIndex = -1; for( u32 i = 0; i < gQueueCount; ++i ) { if( gQueueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT ) { VkBool32 support = false; vkGetPhysicalDeviceSurfaceSupportKHR( gDevices[0], i, gSurface, &support ); if( support == VK_TRUE ) { gQueueFamilyIndex = i; break; } } } if( gQueueFamilyIndex == -1 ) { std::cout << "supported queue not found\n" << std::endl; return false; } gQueueInfo.queueFamilyIndex = gQueueFamilyIndex; std::cout << "found\n"; return true; }
void Renderer::_InitDevice() { { uint32_t gpu_count = 0; vkEnumeratePhysicalDevices( _instance, &gpu_count, nullptr ); std::vector<VkPhysicalDevice> gpu_list( gpu_count ); vkEnumeratePhysicalDevices( _instance, &gpu_count, gpu_list.data() ); _gpu = gpu_list[ 0 ]; vkGetPhysicalDeviceProperties( _gpu, &_gpu_properties ); } { uint32_t family_count = 0; vkGetPhysicalDeviceQueueFamilyProperties( _gpu, &family_count, nullptr ); std::vector<VkQueueFamilyProperties> family_property_list( family_count ); vkGetPhysicalDeviceQueueFamilyProperties( _gpu, &family_count, family_property_list.data() ); bool found = false; for( uint32_t i=0; i < family_count; ++i ) { if( family_property_list[ i ].queueFlags & VK_QUEUE_GRAPHICS_BIT ) { found = true; _graphics_family_index = i; } } if( !found ) { assert( 0 && "Vulkan ERROR: Queue family supporting graphics not found." ); std::exit( -1 ); } } float queue_priorities[] { 1.0f }; VkDeviceQueueCreateInfo device_queue_create_info {}; device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; device_queue_create_info.queueFamilyIndex = _graphics_family_index; device_queue_create_info.queueCount = 1; device_queue_create_info.pQueuePriorities = queue_priorities; VkDeviceCreateInfo device_create_info {}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.queueCreateInfoCount = 1; device_create_info.pQueueCreateInfos = &device_queue_create_info; device_create_info.enabledLayerCount = _device_layers.size(); device_create_info.ppEnabledLayerNames = _device_layers.data(); device_create_info.enabledExtensionCount = _device_extensions.size(); device_create_info.ppEnabledExtensionNames = _device_extensions.data(); ErrorCheck( vkCreateDevice( _gpu, &device_create_info, nullptr, &_device ) ); vkGetDeviceQueue( _device, _graphics_family_index, 0, &_queue ); }
bool VkContext::GetQueueFamilies() { u32 familyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(physDev, &familyCount, nullptr); if (familyCount == 0) { std::cout << "Vulkan GPU does not support any queue family" << std::endl; return false; } std::vector<VkQueueFamilyProperties> families(familyCount); vkGetPhysicalDeviceQueueFamilyProperties(physDev, &familyCount, families.data()); // Get a queue with support for both graphics and present u32 graphicsQueueIndex = UINT32_MAX; u32 presentQueueIndex = UINT32_MAX; for (u32 i = 0; i < familyCount; i++) { VkBool32 presentSupport = VK_FALSE; vkGetPhysicalDeviceSurfaceSupportKHR(physDev, i, surf, &presentSupport); if (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { if (graphicsQueueIndex == UINT32_MAX) { graphicsQueueIndex = i; } if (presentSupport) { graphicsQueueIndex = i; presentQueueIndex = i; break; } } } if (graphicsQueueIndex == UINT32_MAX || presentQueueIndex == UINT32_MAX) { std::cout << "Present or graphics queue not found" << std::endl; return false; } if (graphicsQueueIndex != presentQueueIndex) { std::cout << "Unable to find queue which supports both present and graphics" << std::endl; return false; } queueIndex = graphicsQueueIndex; return true; }
bool Instance::GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice device, std::vector<VkQueueFamilyProperties>* queueFamilyProperties) { NazaraAssert(queueFamilyProperties, "Invalid device vector"); // First, query physical device count UInt32 queueFamiliesCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamiliesCount, nullptr); if (queueFamiliesCount == 0) { NazaraError("Failed to query physical device count"); return false; } // Now we can get the list of the available physical device queueFamilyProperties->resize(queueFamiliesCount); vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamiliesCount, queueFamilyProperties->data()); return true; }
bool Device::GetDeviceQueueProps(VkPhysicalDevice gpu) { vkGetPhysicalDeviceQueueFamilyProperties(gpu, &m_QueueCount, NULL); if(m_QueueCount < 1) return false; VKLOG(Info, "Device-PhysicDeviceQueue count = %d.", m_QueueCount); queueProps.resize(m_QueueCount); vkGetPhysicalDeviceQueueFamilyProperties(gpu, &m_QueueCount, queueProps.data()); uint32 qId = 0; for (qId = 0; qId < m_QueueCount; qId++) { if (queueProps[qId].queueFlags & VK_QUEUE_GRAPHICS_BIT) { m_GfxQueueIndex = qId; VKLOG(Info, "Device-graphicsQueueIndex(%d) queueFlags(%d).", qId, queueProps[qId].queueFlags); break; } } return qId < m_QueueCount; }
void Device::init_queues() { uint32_t queue_node_count; // Call with NULL data to get count vkGetPhysicalDeviceQueueFamilyProperties(phy_.handle(), &queue_node_count, NULL); EXPECT(queue_node_count >= 1); VkQueueFamilyProperties *queue_props = new VkQueueFamilyProperties[queue_node_count]; vkGetPhysicalDeviceQueueFamilyProperties(phy_.handle(), &queue_node_count, queue_props); for (uint32_t i = 0; i < queue_node_count; i++) { VkQueue queue; for (uint32_t j = 0; j < queue_props[i].queueCount; j++) { // TODO: Need to add support for separate MEMMGR and work queues, // including synchronization vkGetDeviceQueue(handle(), i, j, &queue); if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { queues_[GRAPHICS].push_back(new Queue(queue, i)); } if (queue_props[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { queues_[COMPUTE].push_back(new Queue(queue, i)); } if (queue_props[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { queues_[DMA].push_back(new Queue(queue, i)); } } } delete[] queue_props; EXPECT(!queues_[GRAPHICS].empty() || !queues_[COMPUTE].empty()); }
//from the physicaldevice as a param, returns a grphics queueFamily cabable of a rendering pipeline. uint32_t FindGraphicsQueueFamilyIndex(VkPhysicalDevice vkPhysicalDevice, VkSurfaceKHR surface) { uint32_t queueCount = 0; uint32_t graphicsAndPresentingQueueIndex = 0; VkBool32 supportsPresent; vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, &queueCount, nullptr); Assert(queueCount > 0, "physical device has no available queues"); std::vector<VkQueueFamilyProperties> queueProperties(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, &queueCount, queueProperties.data()); for (; graphicsAndPresentingQueueIndex < queueCount; graphicsAndPresentingQueueIndex++) { GetPhysicalDeviceSurfaceSupportKHR(vkPhysicalDevice, graphicsAndPresentingQueueIndex, surface, &supportsPresent); if (queueProperties[graphicsAndPresentingQueueIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT && supportsPresent) break; } Assert(graphicsAndPresentingQueueIndex < queueCount, "this gpu doesn't support graphics rendering.... what a useful gpu"); return graphicsAndPresentingQueueIndex; }
bool Tutorial01::CheckPhysicalDeviceProperties( VkPhysicalDevice physical_device, uint32_t &queue_family_index ) { VkPhysicalDeviceProperties device_properties; VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties( physical_device, &device_properties ); vkGetPhysicalDeviceFeatures( physical_device, &device_features ); uint32_t major_version = VK_VERSION_MAJOR( device_properties.apiVersion ); uint32_t minor_version = VK_VERSION_MINOR( device_properties.apiVersion ); uint32_t patch_version = VK_VERSION_PATCH( device_properties.apiVersion ); if( (major_version < 1) || (device_properties.limits.maxImageDimension2D < 4096) ) { std::cout << "Physical device " << physical_device << " doesn't support required parameters!" << std::endl; return false; } uint32_t queue_families_count = 0; vkGetPhysicalDeviceQueueFamilyProperties( physical_device, &queue_families_count, nullptr ); if( queue_families_count == 0 ) { std::cout << "Physical device " << physical_device << " doesn't have any queue families!" << std::endl; return false; } std::vector<VkQueueFamilyProperties> queue_family_properties( queue_families_count ); vkGetPhysicalDeviceQueueFamilyProperties( physical_device, &queue_families_count, queue_family_properties.data() ); for( uint32_t i = 0; i < queue_families_count; ++i ) { if( (queue_family_properties[i].queueCount > 0) && (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) ) { queue_family_index = i; std::cout << "Selected device: " << device_properties.deviceName << std::endl; return true; } } std::cout << "Could not find queue family with required properties on physical device " << physical_device << "!" << std::endl; return false; }
void getPresentationQueue(VulkanContext& context, VulkanSurfaceContext& sc) { uint32_t queueFamiliesCount; vkGetPhysicalDeviceQueueFamilyProperties(context.physicalDevice, &queueFamiliesCount, nullptr); std::vector<VkQueueFamilyProperties> queueFamiliesProperties(queueFamiliesCount); vkGetPhysicalDeviceQueueFamilyProperties(context.physicalDevice, &queueFamiliesCount, queueFamiliesProperties.data()); uint32_t presentQueueFamilyIndex = 0xffff; for (uint32_t j = 0; j < queueFamiliesCount; ++j) { VkBool32 supported = VK_FALSE; vkGetPhysicalDeviceSurfaceSupportKHR(context.physicalDevice, j, sc.surface, &supported); if (supported) { presentQueueFamilyIndex = j; break; } } ASSERT_POSTCONDITION(presentQueueFamilyIndex != 0xffff, "This physical device does not support the presentation queue."); if (context.graphicsQueueFamilyIndex != presentQueueFamilyIndex) { vkGetDeviceQueue(context.device, presentQueueFamilyIndex, 0, &sc.presentQueue); } else { sc.presentQueue = context.graphicsQueue; } ASSERT_POSTCONDITION(sc.presentQueue, "Unable to obtain presentation queue."); }
void VulkanExampleBase::initVulkan(bool enableValidation) { VkResult err; // Vulkan instance err = createInstance(enableValidation); if (err) { vkTools::exitFatal("Could not create Vulkan instance : \n" + vkTools::errorString(err), "Fatal error"); } #if defined(__ANDROID__) loadVulkanFunctions(instance); #endif // Physical device uint32_t gpuCount = 0; // Get number of available physical devices err = vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr); assert(!err); assert(gpuCount > 0); // Enumerate devices std::vector<VkPhysicalDevice> physicalDevices(gpuCount); err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data()); if (err) { vkTools::exitFatal("Could not enumerate phyiscal devices : \n" + vkTools::errorString(err), "Fatal error"); } // Note : // This example will always use the first physical device reported, // change the vector index if you have multiple Vulkan devices installed // and want to use another one physicalDevice = physicalDevices[0]; // Find a queue that supports graphics operations uint32_t graphicsQueueIndex = 0; uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL); assert(queueCount >= 1); std::vector<VkQueueFamilyProperties> queueProps; queueProps.resize(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data()); for (graphicsQueueIndex = 0; graphicsQueueIndex < queueCount; graphicsQueueIndex++) { if (queueProps[graphicsQueueIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) break; } assert(graphicsQueueIndex < queueCount); // Vulkan device std::array<float, 1> queuePriorities = { 0.0f }; VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = graphicsQueueIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = queuePriorities.data(); err = createDevice(queueCreateInfo, enableValidation); assert(!err); // Store properties (including limits) and features of the phyiscal device // So examples can check against them and see if a feature is actually supported vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); #if defined(__ANDROID__) LOGD(deviceProperties.deviceName); #endif // Gather physical device memory properties vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); // Get the graphics queue vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue); // Find a suitable depth format VkBool32 validDepthFormat = vkTools::getSupportedDepthFormat(physicalDevice, &depthFormat); assert(validDepthFormat); swapChain.connect(instance, physicalDevice, device); // Create synchronization objects VkSemaphoreCreateInfo semaphoreCreateInfo = vkTools::initializers::semaphoreCreateInfo(); // Create a semaphore used to synchronize image presentation // Ensures that the image is displayed before we start submitting new commands to the queu err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.presentComplete); assert(!err); // Create a semaphore used to synchronize command submission // Ensures that the image is not presented until all commands have been sumbitted and executed err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.renderComplete); assert(!err); // Set up submit info structure // Semaphores will stay the same during application lifetime // Command buffer submission info is set by each example submitInfo = vkTools::initializers::submitInfo(); submitInfo.pWaitDstStageMask = &submitPipelineStages; submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = &semaphores.presentComplete; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &semaphores.renderComplete; }
bool VulkanDevice::Init(VulkanInstance * vulkanInstance, HWND hwnd) { VkResult result; // GPU uint32_t numGPUs = 0; vkEnumeratePhysicalDevices(vulkanInstance->GetInstance(), &numGPUs, VK_NULL_HANDLE); if (numGPUs == 0) { gLogManager->AddMessage("ERROR: No GPUs found!"); return false; } std::vector<VkPhysicalDevice> pGPUs(numGPUs); vkEnumeratePhysicalDevices(vulkanInstance->GetInstance(), &numGPUs, pGPUs.data()); gpu = pGPUs[0]; vkGetPhysicalDeviceProperties(gpu, &gpuProperties); vkGetPhysicalDeviceMemoryProperties(gpu, &memoryProperties); gLogManager->AddMessage("Rendering with: " + std::string(gpuProperties.deviceName)); // Queue family uint32_t numQueueFamily = 0; vkGetPhysicalDeviceQueueFamilyProperties(gpu, &numQueueFamily, VK_NULL_HANDLE); if (numQueueFamily == 0) { gLogManager->AddMessage("ERROR: No Queue Families were found!"); return false; } queueFamiliyProperties.resize(numQueueFamily); vkGetPhysicalDeviceQueueFamilyProperties(gpu, &numQueueFamily, queueFamiliyProperties.data()); // Surface VkWin32SurfaceCreateInfoKHR win32SurfaceCI{}; win32SurfaceCI.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; win32SurfaceCI.hinstance = GetModuleHandle(NULL); win32SurfaceCI.hwnd = hwnd; result = vkCreateWin32SurfaceKHR(vulkanInstance->GetInstance(), &win32SurfaceCI, VK_NULL_HANDLE, &surface); if (result != VK_SUCCESS) { gLogManager->AddMessage("ERROR: Couldn't create Win32 Surface!"); return false; } VkBool32 * supportsPresent = new VkBool32[queueFamiliyProperties.size()]; for (uint32_t i = 0; i < queueFamiliyProperties.size(); i++) vkGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supportsPresent[i]); graphicsQueueFamilyIndex = UINT32_MAX; for (uint32_t i = 0; i < queueFamiliyProperties.size(); i++) { if ((queueFamiliyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { if (supportsPresent[i] == VK_TRUE) { graphicsQueueFamilyIndex = i; break; } } } delete[] supportsPresent; if (graphicsQueueFamilyIndex == UINT32_MAX) { gLogManager->AddMessage("ERROR: Couldn't find a graphics queue family index!"); return false; } uint32_t numFormats; result = vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &numFormats, VK_NULL_HANDLE); if (result != VK_SUCCESS) { gLogManager->AddMessage("ERROR: Couldn't get surface formats!"); return false; } VkSurfaceFormatKHR * pSurfaceFormats = new VkSurfaceFormatKHR[numFormats]; result = vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &numFormats, pSurfaceFormats); if (numFormats == 1 && pSurfaceFormats[0].format == VK_FORMAT_UNDEFINED) format = VK_FORMAT_B8G8R8A8_UNORM; else format = pSurfaceFormats[0].format; // Device queue float pQueuePriorities[] = { 1.0f }; VkDeviceQueueCreateInfo deviceQueueCI{}; deviceQueueCI.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; deviceQueueCI.queueCount = 1; deviceQueueCI.queueFamilyIndex = graphicsQueueFamilyIndex; deviceQueueCI.pQueuePriorities = pQueuePriorities; VkPhysicalDeviceFeatures deviceFeatures{}; deviceFeatures.shaderClipDistance = VK_TRUE; deviceFeatures.shaderCullDistance = VK_TRUE; deviceFeatures.geometryShader = VK_TRUE; deviceFeatures.shaderTessellationAndGeometryPointSize = VK_TRUE; deviceFeatures.fillModeNonSolid = VK_TRUE; // Device VkDeviceCreateInfo deviceCI{}; deviceCI.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCI.queueCreateInfoCount = 1; deviceCI.pQueueCreateInfos = &deviceQueueCI; deviceCI.enabledExtensionCount = (uint32_t)deviceExtensions.size(); deviceCI.ppEnabledExtensionNames = deviceExtensions.data(); deviceCI.pEnabledFeatures = &deviceFeatures; result = vkCreateDevice(gpu, &deviceCI, VK_NULL_HANDLE, &device); if (result != VK_SUCCESS) { gLogManager->AddMessage("ERROR: vkCreateDevice() failed!"); return false; } vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &deviceQueue); return true; }
// Create the base Vulkan objects needed by the GrVkGpu object const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndexPtr, bool(*canPresent)(VkInstance, VkPhysicalDevice, uint32_t queueIndex)) { VkPhysicalDevice physDev; VkDevice device; VkInstance inst; VkResult err; const VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType nullptr, // pNext "vktest", // pApplicationName 0, // applicationVersion "vktest", // pEngineName 0, // engineVerison kGrVkMinimumVersion, // apiVersion }; GrVkExtensions extensions; extensions.initInstance(kGrVkMinimumVersion); SkTArray<const char*> instanceLayerNames; SkTArray<const char*> instanceExtensionNames; uint32_t extensionFlags = 0; #ifdef ENABLE_VK_LAYERS for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) { if (extensions.hasInstanceLayer(kDebugLayerNames[i])) { instanceLayerNames.push_back(kDebugLayerNames[i]); } } if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) { instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); extensionFlags |= kEXT_debug_report_GrVkExtensionFlag; } #endif if (extensions.hasInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME)) { instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME); extensionFlags |= kKHR_surface_GrVkExtensionFlag; } if (extensions.hasInstanceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { instanceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); extensionFlags |= kKHR_swapchain_GrVkExtensionFlag; } #ifdef SK_BUILD_FOR_WIN if (extensions.hasInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) { instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); extensionFlags |= kKHR_win32_surface_GrVkExtensionFlag; } #elif SK_BUILD_FOR_ANDROID if (extensions.hasInstanceExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) { instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); extensionFlags |= kKHR_android_surface_GrVkExtensionFlag; } #elif SK_BUILD_FOR_UNIX if (extensions.hasInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME)) { instanceExtensionNames.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); extensionFlags |= kKHR_xlib_surface_GrVkExtensionFlag; } #endif const VkInstanceCreateInfo instance_create = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType nullptr, // pNext 0, // flags &app_info, // pApplicationInfo (uint32_t) instanceLayerNames.count(), // enabledLayerNameCount instanceLayerNames.begin(), // ppEnabledLayerNames (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount instanceExtensionNames.begin(), // ppEnabledExtensionNames }; err = vkCreateInstance(&instance_create, nullptr, &inst); if (err < 0) { SkDebugf("vkCreateInstance failed: %d\n", err); return nullptr; } uint32_t gpuCount; err = vkEnumeratePhysicalDevices(inst, &gpuCount, nullptr); if (err) { SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err); vkDestroyInstance(inst, nullptr); return nullptr; } SkASSERT(gpuCount > 0); // Just returning the first physical device instead of getting the whole array. // TODO: find best match for our needs gpuCount = 1; err = vkEnumeratePhysicalDevices(inst, &gpuCount, &physDev); if (err) { SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err); vkDestroyInstance(inst, nullptr); return nullptr; } // query to get the initial queue props size uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr); SkASSERT(queueCount >= 1); SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties)); // now get the actual queue props VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get(); vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps); // iterate to find the graphics queue uint32_t graphicsQueueIndex = queueCount; for (uint32_t i = 0; i < queueCount; i++) { if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { graphicsQueueIndex = i; break; } } SkASSERT(graphicsQueueIndex < queueCount); // iterate to find the present queue, if needed uint32_t presentQueueIndex = graphicsQueueIndex; if (presentQueueIndexPtr && canPresent) { for (uint32_t i = 0; i < queueCount; i++) { if (canPresent(inst, physDev, i)) { presentQueueIndex = i; break; } } SkASSERT(presentQueueIndex < queueCount); *presentQueueIndexPtr = presentQueueIndex; } extensions.initDevice(kGrVkMinimumVersion, inst, physDev); SkTArray<const char*> deviceLayerNames; SkTArray<const char*> deviceExtensionNames; #ifdef ENABLE_VK_LAYERS for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) { if (extensions.hasDeviceLayer(kDebugLayerNames[i])) { deviceLayerNames.push_back(kDebugLayerNames[i]); } } #endif if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); extensionFlags |= kKHR_swapchain_GrVkExtensionFlag; } if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) { deviceExtensionNames.push_back("VK_NV_glsl_shader"); extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag; } // query to get the physical device properties VkPhysicalDeviceFeatures deviceFeatures; vkGetPhysicalDeviceFeatures(physDev, &deviceFeatures); // this looks like it would slow things down, // and we can't depend on it on all platforms deviceFeatures.robustBufferAccess = VK_FALSE; uint32_t featureFlags = 0; if (deviceFeatures.geometryShader) { featureFlags |= kGeometryShader_GrVkFeatureFlag; } if (deviceFeatures.dualSrcBlend) { featureFlags |= kDualSrcBlend_GrVkFeatureFlag; } if (deviceFeatures.sampleRateShading) { featureFlags |= kSampleRateShading_GrVkFeatureFlag; } float queuePriorities[1] = { 0.0 }; // Here we assume no need for swapchain queue // If one is needed, the client will need its own setup code const VkDeviceQueueCreateInfo queueInfo[2] = { { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType nullptr, // pNext 0, // VkDeviceQueueCreateFlags graphicsQueueIndex, // queueFamilyIndex 1, // queueCount queuePriorities, // pQueuePriorities }, { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType nullptr, // pNext 0, // VkDeviceQueueCreateFlags presentQueueIndex, // queueFamilyIndex 1, // queueCount queuePriorities, // pQueuePriorities } }; uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1; const VkDeviceCreateInfo deviceInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType nullptr, // pNext 0, // VkDeviceCreateFlags queueInfoCount, // queueCreateInfoCount queueInfo, // pQueueCreateInfos (uint32_t) deviceLayerNames.count(), // layerCount deviceLayerNames.begin(), // ppEnabledLayerNames (uint32_t) deviceExtensionNames.count(), // extensionCount deviceExtensionNames.begin(), // ppEnabledExtensionNames &deviceFeatures // ppEnabledFeatures }; err = vkCreateDevice(physDev, &deviceInfo, nullptr, &device); if (err) { SkDebugf("CreateDevice failed: %d\n", err); vkDestroyInstance(inst, nullptr); return nullptr; } VkQueue queue; vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue); GrVkBackendContext* ctx = new GrVkBackendContext(); ctx->fInstance = inst; ctx->fPhysicalDevice = physDev; ctx->fDevice = device; ctx->fQueue = queue; ctx->fGraphicsQueueIndex = graphicsQueueIndex; ctx->fMinAPIVersion = kGrVkMinimumVersion; ctx->fExtensions = extensionFlags; ctx->fFeatures = featureFlags; ctx->fInterface.reset(GrVkCreateInterface(inst, device, extensionFlags)); return ctx; }
void VulkanContext::ChooseDevice(int physical_device) { physical_device_ = physical_device; ILOG("Chose physical device %d: %p", physical_device, physical_devices_[physical_device]); GetDeviceLayerProperties(); if (!CheckLayers(device_layer_properties_, device_layer_names_)) { WLOG("CheckLayers for device %d failed", physical_device); } vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, nullptr); assert(queue_count >= 1); queue_props.resize(queue_count); vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, queue_props.data()); assert(queue_count >= 1); // Detect preferred formats, in this order. static const VkFormat depthStencilFormats[] = { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, }; deviceInfo_.preferredDepthStencilFormat = VK_FORMAT_UNDEFINED; for (size_t i = 0; i < ARRAY_SIZE(depthStencilFormats); i++) { VkFormatProperties props; vkGetPhysicalDeviceFormatProperties(physical_devices_[physical_device_], depthStencilFormats[i], &props); if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { deviceInfo_.preferredDepthStencilFormat = depthStencilFormats[i]; break; } } if (deviceInfo_.preferredDepthStencilFormat == VK_FORMAT_UNDEFINED) { // WTF? This is bad. ELOG("Could not find a usable depth stencil format."); } // This is as good a place as any to do this vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties); vkGetPhysicalDeviceProperties(physical_devices_[physical_device_], &gpu_props); // Optional features vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &featuresAvailable_); memset(&featuresEnabled_, 0, sizeof(featuresEnabled_)); // Enable a few safe ones if they are available. if (featuresAvailable_.dualSrcBlend) { featuresEnabled_.dualSrcBlend = true; } if (featuresAvailable_.largePoints) { featuresEnabled_.largePoints = true; } if (featuresAvailable_.wideLines) { featuresEnabled_.wideLines = true; } if (featuresAvailable_.geometryShader) { featuresEnabled_.geometryShader = true; } if (featuresAvailable_.logicOp) { featuresEnabled_.logicOp = true; } if (featuresAvailable_.depthClamp) { featuresEnabled_.depthClamp = true; } if (featuresAvailable_.depthBounds) { featuresEnabled_.depthBounds = true; } if (featuresAvailable_.samplerAnisotropy) { featuresEnabled_.samplerAnisotropy = true; } // For easy wireframe mode, someday. if (featuresEnabled_.fillModeNonSolid) { featuresEnabled_.fillModeNonSolid = true; } GetDeviceLayerExtensionList(nullptr, device_extension_properties_); device_extensions_enabled_.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); }
bool vulkan_check_physical_device(IWindow* window, VkPhysicalDevice physical_device, VkSurfaceKHR presentationSurface, const std::vector<const char*>& extensions, uint32_t& queue_family_index, uint32_t& selected_present_queue_family_index) { Assert(window != nullptr); vulkan_device_check_extensions(extensions, physical_device); VkPhysicalDeviceProperties device_properties; VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties(physical_device, &device_properties); vkGetPhysicalDeviceFeatures(physical_device, &device_features); Assert(device_properties.apiVersion >= VK_MAKE_VERSION(1, 0, 0)); Assert(device_properties.limits.maxImageDimension2D >= 4096); Assert(device_features.shaderClipDistance == VK_TRUE); // This is just checked, not enabled uint32_t queue_families_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, nullptr); Assert(queue_families_count > 0, "device doesn't have any queue families"); if (queue_families_count == 0) return false; std::vector<VkQueueFamilyProperties> queue_family_properties(queue_families_count); std::vector<VkBool32> queue_present_support(queue_families_count); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, &queue_family_properties[0]); uint32_t graphics_queue_family_index = UINT32_MAX; uint32_t present_queue_family_index = UINT32_MAX; for (uint32_t i = 0; i < queue_families_count; ++i) { Assert(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, presentationSurface, &queue_present_support[i]) == VK_SUCCESS); if ((queue_family_properties[i].queueCount > 0) && (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { // Select first queue that supports graphics if (graphics_queue_family_index == UINT32_MAX) graphics_queue_family_index = i; Assert(vulkan_queue_family_has_presentation_support(physical_device, i, window) == (queue_present_support[i] == VK_TRUE), "Queue family presentation support mismatch."); // If there is queue that supports both graphics and present - prefer it if (queue_present_support[i]) { queue_family_index = i; selected_present_queue_family_index = i; return true; } } } // We don't have queue that supports both graphics and present so we have to use separate queues for (uint32_t i = 0; i < queue_families_count; ++i) { if (queue_present_support[i] == VK_TRUE) { present_queue_family_index = i; break; } } Assert(graphics_queue_family_index != UINT32_MAX); Assert(present_queue_family_index != UINT32_MAX); queue_family_index = graphics_queue_family_index; selected_present_queue_family_index = present_queue_family_index; return true; }
bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer) { u32 queue_family_count; vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, nullptr); if (queue_family_count == 0) { ERROR_LOG(VIDEO, "No queue families found on specified vulkan physical device."); return false; } std::vector<VkQueueFamilyProperties> queue_family_properties(queue_family_count); vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, queue_family_properties.data()); INFO_LOG(VIDEO, "%u vulkan queue families", queue_family_count); // Find graphics and present queues. m_graphics_queue_family_index = queue_family_count; m_present_queue_family_index = queue_family_count; for (uint32_t i = 0; i < queue_family_count; i++) { VkBool32 graphics_supported = queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT; if (graphics_supported) { m_graphics_queue_family_index = i; // Quit now, no need for a present queue. if (!surface) { break; } } if (surface) { VkBool32 present_supported; VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(m_physical_device, i, surface, &present_supported); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: "); return false; } if (present_supported) { m_present_queue_family_index = i; } // Prefer one queue family index that does both graphics and present. if (graphics_supported && present_supported) { break; } } } if (m_graphics_queue_family_index == queue_family_count) { ERROR_LOG(VIDEO, "Vulkan: Failed to find an acceptable graphics queue."); return false; } if (surface && m_present_queue_family_index == queue_family_count) { ERROR_LOG(VIDEO, "Vulkan: Failed to find an acceptable present queue."); return false; } VkDeviceCreateInfo device_info = {}; device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_info.pNext = nullptr; device_info.flags = 0; static constexpr float queue_priorities[] = {1.0f}; VkDeviceQueueCreateInfo graphics_queue_info = {}; graphics_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; graphics_queue_info.pNext = nullptr; graphics_queue_info.flags = 0; graphics_queue_info.queueFamilyIndex = m_graphics_queue_family_index; graphics_queue_info.queueCount = 1; graphics_queue_info.pQueuePriorities = queue_priorities; VkDeviceQueueCreateInfo present_queue_info = {}; present_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; present_queue_info.pNext = nullptr; present_queue_info.flags = 0; present_queue_info.queueFamilyIndex = m_present_queue_family_index; present_queue_info.queueCount = 1; present_queue_info.pQueuePriorities = queue_priorities; std::array<VkDeviceQueueCreateInfo, 2> queue_infos = {{ graphics_queue_info, present_queue_info, }}; device_info.queueCreateInfoCount = 1; if (m_graphics_queue_family_index != m_present_queue_family_index) { device_info.queueCreateInfoCount = 2; } device_info.pQueueCreateInfos = queue_infos.data(); ExtensionList enabled_extensions; if (!SelectDeviceExtensions(&enabled_extensions, surface != VK_NULL_HANDLE)) return false; device_info.enabledLayerCount = 0; device_info.ppEnabledLayerNames = nullptr; device_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size()); device_info.ppEnabledExtensionNames = enabled_extensions.data(); // Check for required features before creating. if (!SelectDeviceFeatures()) return false; device_info.pEnabledFeatures = &m_device_features; // Enable debug layer on debug builds if (enable_validation_layer) { static const char* layer_names[] = {"VK_LAYER_LUNARG_standard_validation"}; device_info.enabledLayerCount = 1; device_info.ppEnabledLayerNames = layer_names; } VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateDevice failed: "); return false; } // With the device created, we can fill the remaining entry points. if (!LoadVulkanDeviceFunctions(m_device)) return false; // Grab the graphics and present queues. vkGetDeviceQueue(m_device, m_graphics_queue_family_index, 0, &m_graphics_queue); if (surface) { vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue); } return true; }
static void SetupVulkan(const char** extensions, uint32_t extensions_count) { VkResult err; // Create Vulkan Instance { VkInstanceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; create_info.enabledExtensionCount = extensions_count; create_info.ppEnabledExtensionNames = extensions; #ifdef IMGUI_VULKAN_DEBUG_REPORT // Enabling multiple validation layers grouped as LunarG standard validation const char* layers[] = { "VK_LAYER_LUNARG_standard_validation" }; create_info.enabledLayerCount = 1; create_info.ppEnabledLayerNames = layers; // Enable debug report extension (we need additional storage, so we duplicate the user array to add our new extension to it) const char** extensions_ext = (const char**)malloc(sizeof(const char*) * (extensions_count + 1)); memcpy(extensions_ext, extensions, extensions_count * sizeof(const char*)); extensions_ext[extensions_count] = "VK_EXT_debug_report"; create_info.enabledExtensionCount = extensions_count + 1; create_info.ppEnabledExtensionNames = extensions_ext; // Create Vulkan Instance err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); check_vk_result(err); free(extensions_ext); // Get the function pointer (required for any extensions) auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT"); IM_ASSERT(vkCreateDebugReportCallbackEXT != NULL); // Setup the debug report callback VkDebugReportCallbackCreateInfoEXT debug_report_ci = {}; debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; debug_report_ci.pfnCallback = debug_report; debug_report_ci.pUserData = NULL; err = vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport); check_vk_result(err); #else // Create Vulkan Instance without any debug feature err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); check_vk_result(err); #endif } // Select GPU { uint32_t gpu_count; err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, NULL); check_vk_result(err); VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count); err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus); check_vk_result(err); // If a number >1 of GPUs got reported, you should find the best fit GPU for your purpose // e.g. VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU if available, or with the greatest memory available, etc. // for sake of simplicity we'll just take the first one, assuming it has a graphics queue family. g_PhysicalDevice = gpus[0]; free(gpus); } // Select graphics queue family { uint32_t count; vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, NULL); VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues); for (uint32_t i = 0; i < count; i++) if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { g_QueueFamily = i; break; } free(queues); IM_ASSERT(g_QueueFamily != -1); } // Create Logical Device (with 1 queue) { int device_extension_count = 1; const char* device_extensions[] = { "VK_KHR_swapchain" }; const float queue_priority[] = { 1.0f }; VkDeviceQueueCreateInfo queue_info[1] = {}; queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_info[0].queueFamilyIndex = g_QueueFamily; queue_info[0].queueCount = 1; queue_info[0].pQueuePriorities = queue_priority; VkDeviceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]); create_info.pQueueCreateInfos = queue_info; create_info.enabledExtensionCount = device_extension_count; create_info.ppEnabledExtensionNames = device_extensions; err = vkCreateDevice(g_PhysicalDevice, &create_info, g_Allocator, &g_Device); check_vk_result(err); vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue); } // Create Descriptor Pool { VkDescriptorPoolSize pool_sizes[] = { { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes); pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); check_vk_result(err); } }
int main(){ printf("This code initializes a Vulkan device"); /** Steps required 1. Create Vulkan Instance 2. Enumerate the GPUs 3. Query Queues on the GPU (Queues represent on what 'channels' will the data process, query the queue for COMPUTE type queue or GRAPHICS type queue 4. Create a queue priority 5. Create a device with information from 2, 3 and 4 **/ /** 1. Create Vulkan Instance **/ VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pNext = NULL; appInfo.pApplicationName = APP_SHORT_NAME; appInfo.applicationVersion = 1; appInfo.pEngineName = APP_SHORT_NAME; appInfo.engineVersion = 1; appInfo.apiVersion = VK_API_VERSION; VkInstanceCreateInfo icInfo = {}; icInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; icInfo.pNext = NULL; icInfo.flags = 0; icInfo.pApplicationInfo = & appInfo; icInfo.enabledExtensionCount = 0; icInfo.ppEnabledExtensionNames = NULL; icInfo.enabledLayerCount = 0; icInfo.enabledLayerCount = NULL; VkInstance instance; VkResult res; res = vkCreateInstance(&icInfo, NULL, &instance); if(res == VK_ERROR_INCOMPATIBLE_DRIVER){ printf("Cannot find a Vulkan Compatible ICD\n"); exit(-1); } else if(res){ printf("Some error occured\n"); exit(-1); } printf("Yay! Vulkan is initialized\n"); /** 2. Enumerate the GPUs **/ uint32_t gpuCount = 0; res = vkEnumeratePhysicalDevices(instance, &gpuCount, NULL); printf("found %d gpus\n", gpuCount); VkPhysicalDevice* gpus = new VkPhysicalDevice[gpuCount]; printf("Listing gpus...\n", gpuCount); res = vkEnumeratePhysicalDevices(instance, &gpuCount, gpus); while(++idx < gpuCount){ VkPhysicalDeviceProperties props= {}; vkGetPhysicalDeviceProperties(gpus[idx], &props); printf("%d-%d-%d-%d-%s\n", props.apiVersion, props.driverVersion, props.vendorID, props.deviceID, props.deviceName); } /** 3. Query for the supported queues **/ /** From renderdocs vulkan Command buffers are submitted to a VkQueue. The notion of queues are how work becomes serialised to be passed to the GPU. A VkPhysicalDevice (remember way back? The GPU handle) can report a number of queue families with different capabilities. e.g. a graphics queue family and a compute-only queue family. When you create your device you ask for a certain number of queues from each family, and then you can enumerate them from the device after creation with vkGetDeviceQueue(). **/ uint32_t queue_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(gpus[0], &queue_count, NULL); if(queue_count <= 0){ printf("No Queues found.. aborting\n"); exit(-1); } VkQueueFamilyProperties* queue_props = new VkQueueFamilyProperties[queue_count]; vkGetPhysicalDeviceQueueFamilyProperties(gpus[0], &queue_count, queue_props); float queue_priorities[1] = {0.0}; /** 4. Create a queue priority **/ VkDeviceQueueCreateInfo qi = {}; qi.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; qi.pNext = NULL; qi.queueCount = 1; qi.pQueuePriorities = queue_priorities; idx = -1; while(++idx < queue_count){ if(queue_props[idx].queueFlags & VK_QUEUE_GRAPHICS_BIT){ //Look for a queue that has Graphics capabilities qi.queueFamilyIndex = idx; break; } } /** 5. Create a device with information from 2, 3 and 4 **/ VkDeviceCreateInfo dci = {}; dci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; dci.pNext = NULL; dci.queueCreateInfoCount = 1; dci.pQueueCreateInfos = &qi; dci.enabledExtensionCount = 0; dci.ppEnabledExtensionNames = NULL; dci.enabledLayerCount = 0; dci.ppEnabledLayerNames = NULL; dci.pEnabledFeatures = NULL; VkDevice device; res = vkCreateDevice(gpus[0], &dci, NULL, &device); if(res){ printf("There was a problem creating the device"); exit(-1); } /** All's great, first thing lets create a command buffer **/ VkCommandPoolCreateInfo cpci = {}; cpci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cpci.pNext = NULL; cpci.queueFamilyIndex = qi.queueFamilyIndex; cpci.flags = 0; VkCommandPool cp; res = vkCreateCommandPool(device, &cpci, NULL, &cp); if(res){ printf("There was a problem creating a command pool"); exit(-1); } /** Create a command buffer from the command pool **/ VkCommandBufferAllocateInfo cbai = {}; cbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; cbai.pNext = NULL; cbai.commandPool = cp; cbai.commandBufferCount = 1; cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; VkCommandBuffer* commandBuffer = new VkCommandBuffer[1]; //single command res = vkAllocateCommandBuffers(device, &cbai, commandBuffer); if(res){ printf("There was a problem creating a command buffer"); exit(-1); } /** no, we never leave the crap behind **/ vkFreeCommandBuffers(device, cp, 1, commandBuffer); vkDestroyCommandPool(device, cp, NULL); vkDestroyDevice(device, NULL); printf("Device created"); vkDestroyInstance(instance, NULL); delete[] gpus; return 0; }
int main(int argc, char** argv) { g_validationLayers = std::vector<const char*> { "VK_LAYER_LUNARG_mem_tracker", "VK_LAYER_GOOGLE_unique_objects", }; // Init GLFW { // Handle GLFW errors glfwSetErrorCallback([](int error, const char* description) { std::cout << "GLFW error: " << error << " - " << description << std::endl; }); // Initialize GLFW if (!glfwInit()) error("Cannot initialize GLFW."); // Check Vulkan support if (!glfwVulkanSupported()) error("Cannot find compatible Vulkan client driver."); } // Get Validation layers { uint32_t numInstanceLayers = 0; // Get numInstanceLayers if (vkEnumerateInstanceLayerProperties(&numInstanceLayers, nullptr)) error("Vulkan: Could not enumerate instance layer properties."); if (numInstanceLayers > 0) { std::vector<VkLayerProperties> instanceLayers(numInstanceLayers); if (vkEnumerateInstanceLayerProperties(&numInstanceLayers, instanceLayers.data())) error("Vulkan: Could not enumerate instance layer properties."); // Print layers: std::cout << "Validation layers: " << std::endl; for (int i = 0; i < numInstanceLayers; ++i) { std::cout << "\t" << instanceLayers[i].layerName << std::endl; std::cout << "\t\t" << instanceLayers[i].description << std::endl; std::cout << std::endl; } std::cout << std::endl; } else std::cout << "No validation layers found!" << std::endl; // TODO: Check Layers } // Check instance extensions { int numRequiredExtensions; const char** requiredExtensions; // Get required extensions from GLFW { requiredExtensions = glfwGetRequiredInstanceExtensions((int*)&numRequiredExtensions); if (numRequiredExtensions > 0) { // Write to global g_extensions for (int i = 0; i < numRequiredExtensions; ++i) g_extensions.push_back(requiredExtensions[i]); // Print std::cout << "Required Instance Extensions(GLFW):" << std::endl; for (int i = 0; i < numRequiredExtensions; ++i) { std::cout << "\t" << requiredExtensions[i] << std::endl; } std::cout << std::endl; } // TODO: Check extensions } // Get Instance extensions { VkResult err; uint32_t numInstanceExtensions; err = vkEnumerateInstanceExtensionProperties(nullptr, &numInstanceExtensions, nullptr); if (numInstanceExtensions > 0) { std::vector<VkExtensionProperties> instanceExtensions(numInstanceExtensions); err = vkEnumerateInstanceExtensionProperties(NULL, &numInstanceExtensions, instanceExtensions.data()); // Print std::cout << "Instance Extensions: " << std::endl; for (int i = 0; i < numInstanceExtensions; ++i) { std::cout << "\t" <<instanceExtensions[i].extensionName << std::endl; std::cout << "\t\t" << instanceExtensions[i].specVersion << std::endl; std::cout << std::endl; } std::cout << std::endl; } // TODO: Check instance extensions(with required instance extensions) } } // Create Vulkan Instance { VkApplicationInfo app; { app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app.pNext = nullptr; app.pApplicationName = "Vulkan test 1"; app.applicationVersion = 0; app.pEngineName = "Vulkan test 1"; app.engineVersion = 0; app.apiVersion = VK_API_VERSION; } VkInstanceCreateInfo instanceInfo; { instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceInfo.pNext = nullptr; instanceInfo.pApplicationInfo = &app; instanceInfo.enabledLayerCount = g_validationLayers.size(); instanceInfo.ppEnabledLayerNames = g_validationLayers.data(); instanceInfo.enabledExtensionCount = g_extensions.size(); instanceInfo.ppEnabledExtensionNames = g_extensions.data(); } // TODO: Aligned allocators VkAllocationCallbacks allocator; { allocator.pUserData = nullptr; allocator.pfnAllocation = [](void* pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)->void* { return malloc(size); }; allocator.pfnFree = [](void* pUserData, void* pMemory) { free(pMemory); }; allocator.pfnReallocation = [](void* pUserData, void *pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope) { free(pOriginal); return malloc(size); }; allocator.pfnInternalAllocation = nullptr; allocator.pfnInternalFree = nullptr; allocator.pfnReallocation = nullptr; } // Create vulkan instance VkResult vkError = vkCreateInstance(&instanceInfo, &allocator, &g_vkInstance); // Handle errors switch (vkError) { case VK_ERROR_INCOMPATIBLE_DRIVER: error("Drivers do not support vulkan. Drivers could be outdated."); break; case VK_ERROR_EXTENSION_NOT_PRESENT: error("Cannot find specified extension."); break; case VK_SUCCESS: // Succes! (prevent default from catching success as error) std::cout << "Vulkan instance created!" << std::endl; break; default: error("Could not create vulkan Instance. Drivers could be outdated."); break; } } // Look for GPU device { uint32_t numGPUs; VkResult vkError = vkEnumeratePhysicalDevices(g_vkInstance, &numGPUs, nullptr); if (numGPUs < 0) error("vkEnumeratePhysicalDevices could not find any GPU devices."); if (vkError) error("vkEnumeratePhysicalDevices could not enumerate GPU devices."); if (numGPUs > 0) { std::vector<VkPhysicalDevice> physicalDevices(numGPUs); if (vkEnumeratePhysicalDevices(g_vkInstance, &numGPUs, physicalDevices.data())) error("vkEnumeratePhysicalDevices could not enumerate GPU devices."); g_vkGPU = physicalDevices[0]; std::cout << numGPUs << " GPUs found!" << std::endl; } } // Get queue properties { uint32_t numQueues; vkGetPhysicalDeviceProperties(g_vkGPU, &g_vkGPUProperties); vkGetPhysicalDeviceQueueFamilyProperties(g_vkGPU, &numQueues, nullptr); if (numQueues == 0) error("vkGetPhysicalDeviceQueueFamilyProperties could not find any queues."); g_vkQueueProperties = std::vector<VkQueueFamilyProperties>(numQueues); vkGetPhysicalDeviceQueueFamilyProperties(g_vkGPU, &numQueues, g_vkQueueProperties.data()); } // Look for device layers (Unecessary code that does nothing) { uint32_t numDeviceLayers; if (vkEnumerateDeviceLayerProperties(g_vkGPU, &numDeviceLayers, nullptr)) error("vkEnumerateDeviceLayerProperties failed!"); if (numDeviceLayers > 0) { std::vector<VkLayerProperties> deviceLayers(numDeviceLayers); if (vkEnumerateDeviceLayerProperties(g_vkGPU, &numDeviceLayers, deviceLayers.data())) error("vkEnumerateDeviceLayerProperties failed!"); // TODO: Check device layers. } } // Look for device extensions (swapchain extension) { uint32_t numDeviceExtensions; bool extensionSwapChainFound = false; if (vkEnumerateDeviceExtensionProperties(g_vkGPU, nullptr, &numDeviceExtensions, nullptr)) error("vkEnumerateDeviceExtensionProperties failed!"); if (numDeviceExtensions > 0) { std::vector<VkExtensionProperties> deviceExtensions(numDeviceExtensions); if (vkEnumerateDeviceExtensionProperties(g_vkGPU, nullptr, &numDeviceExtensions, deviceExtensions.data())) error("vkEnumerateDeviceExtensionProperties failed!"); // Search for swapchain extension for (VkExtensionProperties extension : deviceExtensions) { if (!strcmp(extension.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) extensionSwapChainFound = true; } // Print std::cout << std::endl << "Extensions:" << std::endl; for (VkExtensionProperties extension : deviceExtensions) { std::cout << extension.extensionName << "(" << extension.specVersion << ")" << std::endl; } std::cout << std::endl; } if (!extensionSwapChainFound) error("Failed to find the " VK_KHR_SWAPCHAIN_EXTENSION_NAME " extension!"); } // TODO: Validate // Get instance function adresses { GET_INSTANCE_PROC_ADDR(g_vkInstance, GetPhysicalDeviceSurfaceCapabilitiesKHR); GET_INSTANCE_PROC_ADDR(g_vkInstance, GetPhysicalDeviceSurfaceFormatsKHR); GET_INSTANCE_PROC_ADDR(g_vkInstance, GetPhysicalDeviceSurfacePresentModesKHR); GET_INSTANCE_PROC_ADDR(g_vkInstance, GetPhysicalDeviceSurfaceSupportKHR); GET_INSTANCE_PROC_ADDR(g_vkInstance, CreateSwapchainKHR); GET_INSTANCE_PROC_ADDR(g_vkInstance, DestroySwapchainKHR); GET_INSTANCE_PROC_ADDR(g_vkInstance, GetSwapchainImagesKHR); GET_INSTANCE_PROC_ADDR(g_vkInstance, AcquireNextImageKHR); GET_INSTANCE_PROC_ADDR(g_vkInstance, QueuePresentKHR); } // Create window { glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); g_window = glfwCreateWindow(g_width, g_height, "Vulkan test", NULL, NULL); if (!g_window) error("Could not create window!"); glfwSetWindowRefreshCallback(g_window, [](GLFWwindow* window) { // TODO: draw(); }); glfwSetFramebufferSizeCallback(g_window, [](GLFWwindow* window, int width, int height) { g_width = width; g_height = height; // TODO: resize(); }); } // Init swapchain { glfwCreateWindowSurface(g_vkInstance, g_window, nullptr, &g_vkSurface); std::vector<VkBool32> supportsPresent(g_vkQueueProperties.size()); for (uint32_t i = 0; i < g_vkQueueProperties.size(); ++i) g_vkFPGetPhysicalDeviceSurfaceSupportKHR(g_vkGPU, i, g_vkSurface, &supportsPresent[i]); uint32_t graphicsQueueNodeIndex = UINT32_MAX; uint32_t presentQueueNodeIndex = UINT32_MAX; for (uint32_t i = 0; i < g_vkQueueProperties.size(); ++i) { if (graphicsQueueNodeIndex == UINT32_MAX) { graphicsQueueNodeIndex = i; } if (supportsPresent[i] == VK_TRUE) { graphicsQueueNodeIndex = i; presentQueueNodeIndex = i; break; } } //if (presentQueueNodeIndex == UINT32_MAX) { // for (uint32_t i = 0; i < g_vkQueueProperties.size(); ++i) { // if (supportsPresent[i] == VK_TRUE) { // presentQueueNodeIndex = i; // } // } //} if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) error("Could not find a graphics and a present queue."); if (graphicsQueueNodeIndex != presentQueueNodeIndex) error("Could not find a common graphics and present queue."); g_vkGraphicsQueueNodeIndex = graphicsQueueNodeIndex; //TODO: init device { float queuePriotities = 0.f; VkDeviceQueueCreateInfo queue; { queue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue.pNext = NULL; queue.queueFamilyIndex = g_vkGraphicsQueueNodeIndex; queue.queueCount = 1; queue.pQueuePriorities = &queuePriotities; } } //vkGetDeviceQueue(g_vkDevice, g_vkGraphicsQueueNodeIndex, 0, g_vkQueue); } std::cin.get(); return 0; }
int XdevLSwapChainVulkan::createSurface(IPXdevLWindow window) { Display* display = static_cast<Display*>(window->getInternal(XdevLInternalName("X11_DISPLAY"))); if(nullptr == display) { XDEVL_MODULEX_ERROR(XdevLSwapChainVulkan, "Could not get native X11 display information.\n"); return RET_FAILED; } Window x11window = (Window)(window->getInternal(XdevLInternalName("X11_WINDOW"))); if(None == x11window) { XDEVL_MODULEX_ERROR(XdevLSwapChainVulkan, "Could not get native X11 window information.\n"); return RET_FAILED; } // // Get the Surface extensions. // VkResult result; #if defined(_WIN32) VkWin32SurfaceCreateInfoKHR surfaceCreateInfo; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = (HINSTANCE)platformHandle; // provided by the platform code surfaceCreateInfo.hwnd = (HWND)platformWindow; // provided by the platform code result = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &m_surface); #elif defined(__ANDROID__) VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.window = window; // provided by the platform code result = vkCreateAndroidSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &m_surface); #else VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, nullptr, 0, XGetXCBConnection(display), (xcb_window_t)x11window }; result = vkCreateXcbSurfaceKHR(m_instance, &surfaceCreateInfo, nullptr, &m_surface); #endif if(result != VK_SUCCESS) { std::cerr << "Failed to create Vulkan surface: " << vkVkResultToString(result) << std::endl; return 1; } uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueCount, nullptr); std::vector<VkQueueFamilyProperties> queueProps(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueCount, queueProps.data()); // Will be used to present the swap chain images to the windowing system std::vector<VkBool32> supportsPresent(queueCount); for(uint32_t i = 0; i < queueCount; i++) { fpGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &supportsPresent[i]); } // Search for a graphics and a present queue in the array of queue // families, try to find one that supports both uint32_t graphicsQueueNodeIndex = UINT32_MAX; uint32_t presentQueueNodeIndex = UINT32_MAX; for(uint32_t i = 0; i < queueCount; i++) { if((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { if(graphicsQueueNodeIndex == UINT32_MAX) { graphicsQueueNodeIndex = i; } if(supportsPresent[i] == VK_TRUE) { graphicsQueueNodeIndex = i; presentQueueNodeIndex = i; break; } } } if(presentQueueNodeIndex == UINT32_MAX) { // If there's no queue that supports both present and graphics // try to find a separate present queue for(uint32_t i = 0; i < queueCount; ++i) { if(supportsPresent[i] == VK_TRUE) { presentQueueNodeIndex = i; break; } } } // Exit if either a graphics or a presenting queue hasn't been found if(graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) { return 1; } // todo : Add support for separate graphics and presenting queue if(graphicsQueueNodeIndex != presentQueueNodeIndex) { return 1; } m_queueNodeIndex = graphicsQueueNodeIndex; // Get list of supported surface formats uint32_t formatCount; result = vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr); if(VK_SUCCESS != result) { std::cerr << "vkGetPhysicalDeviceSurfaceFormatsKHR failed: " << vkVkResultToString(result) << std::endl; return 1; } assert(formatCount > 0); std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount); result = vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, surfaceFormats.data()); assert(!result); // If the surface format list only includes one entry with VK_FORMAT_UNDEFINED, // there is no preferered format, so we assume VK_FORMAT_B8G8R8A8_UNORM if((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED)) { m_colorFormat = VK_FORMAT_B8G8R8A8_UNORM; } else { // Always select the first available color format // If you need a specific format (e.g. SRGB) you'd need to // iterate over the list of available surface format and // check for it's presence m_colorFormat = surfaceFormats[0].format; } m_colorSpace = surfaceFormats[0].colorSpace; return 0; }
// Devices void Renderer::_InitDevice() { { uint32_t gpu_count = 0; // Read number of GPU's vkEnumeratePhysicalDevices(_instance, &gpu_count, nullptr); std::vector<VkPhysicalDevice> gpu_list(gpu_count); // Populate list vkEnumeratePhysicalDevices(_instance, &gpu_count, gpu_list.data()); _gpu = gpu_list[0]; // Get the first available list vkGetPhysicalDeviceProperties(_gpu, &_gpu_properties); vkGetPhysicalDeviceMemoryProperties(_gpu, &_gpu_memory_properties); } { uint32_t family_count = 0; // Read number of GPU queue family properties vkGetPhysicalDeviceQueueFamilyProperties(_gpu, &family_count, nullptr); std::vector<VkQueueFamilyProperties> family_property_list(family_count); // Populate list vkGetPhysicalDeviceQueueFamilyProperties(_gpu, &family_count, family_property_list.data()); // Find the graphics family bool found = false; for (uint32_t i = 0; i < family_count; ++i) { if (family_property_list[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { found = true; _graphics_family_index = i; } } if (!found) { assert(0 && "Vulkan ERROR: Queue family supporting graphics not found."); std::exit(-1); } } // Instance Layers { uint32_t layer_count = 0; // Read the number of layers vkEnumerateInstanceLayerProperties(&layer_count, nullptr); std::vector<VkLayerProperties> layer_property_list(layer_count); // Populate list vkEnumerateInstanceLayerProperties(&layer_count, layer_property_list.data()); #if BUILD_ENABLE_VULKAN_RUNTIME_DEBUG std::cout << "Instance layers: \n"; for (auto &i : layer_property_list) { std::cout << " " << i.layerName << "\t\t | " << i.description << std::endl; } std::cout << std::endl; #endif } // Instance Extensions { uint32_t extension_count = 0; // Read the number of extensions vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr); std::vector<VkExtensionProperties> extension_property_list(extension_count); // Populate list vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_property_list.data()); #if BUILD_ENABLE_VULKAN_RUNTIME_DEBUG std::cout << "Instance extensions: \n"; for (auto &i : extension_property_list) { std::cout << " " << i.extensionName << "\t\t | " << i.specVersion << std::endl; } std::cout << std::endl; #endif } // Device Layers { uint32_t layer_count = 0; // Read the number of layers vkEnumerateDeviceLayerProperties(_gpu, &layer_count, nullptr); std::vector<VkLayerProperties> layer_property_list(layer_count); // Populate list vkEnumerateDeviceLayerProperties(_gpu, &layer_count, layer_property_list.data()); #if BUILD_ENABLE_VULKAN_RUNTIME_DEBUG std::cout << "Device layers: \n"; for (auto &i : layer_property_list) { std::cout << " " << i.layerName << "\t\t | " << i.description << std::endl; } std::cout << std::endl; #endif } // Device Extensions { uint32_t extension_count = 0; // Read the number of extensions vkEnumerateDeviceExtensionProperties(_gpu, nullptr, &extension_count, nullptr); std::vector<VkExtensionProperties> extension_property_list(extension_count); // Populate list vkEnumerateDeviceExtensionProperties(_gpu, nullptr, &extension_count, extension_property_list.data()); #if BUILD_ENABLE_VULKAN_RUNTIME_DEBUG std::cout << "Device extensions: \n"; for (auto &i : extension_property_list) { std::cout << " " << i.extensionName << "\t\t | " << i.specVersion << std::endl; } std::cout << std::endl; #endif } float queue_priorities[] {1.0f}; VkDeviceQueueCreateInfo device_queue_create_info {}; device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; device_queue_create_info.queueFamilyIndex = _graphics_family_index; device_queue_create_info.queueCount = 1; device_queue_create_info.pQueuePriorities = queue_priorities; VkDeviceCreateInfo device_create_info = {}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.queueCreateInfoCount = 1; device_create_info.pQueueCreateInfos = &device_queue_create_info; device_create_info.enabledLayerCount = (uint32_t) _device_layer_list.size(); device_create_info.ppEnabledLayerNames = _device_layer_list.data(); device_create_info.enabledExtensionCount = (uint32_t) _device_extension_list.size(); device_create_info.ppEnabledExtensionNames = _device_extension_list.data(); ErrorCheck(vkCreateDevice(_gpu, &device_create_info, nullptr, &_device)); vkGetDeviceQueue(_device, _graphics_family_index, 0, &_queue); }