diff --git a/discover/gpu.go b/discover/gpu.go index f6152bf0d..2cb77e1e5 100644 --- a/discover/gpu.go +++ b/discover/gpu.go @@ -466,6 +466,15 @@ func GetGPUInfo() GpuInfoList { continue } + if C.vk_device_is_supported(*vHandles.vulkan, C.int(i)) == 0 { + unsupportedGPUs = append(unsupportedGPUs, + UnsupportedGPUInfo{ + GpuInfo: gpuInfo.GpuInfo, + }) + slog.Info(fmt.Sprintf("[%d] Vulkan GPU does not support required Vulkan features. (StorageBuffer16BitAccess)", i)) + continue + } + gpuInfo.TotalMemory = uint64(memInfo.total) gpuInfo.FreeMemory = uint64(memInfo.free) gpuInfo.ID = C.GoString(&memInfo.gpu_id[0]) diff --git a/discover/gpu_info_vulkan.c b/discover/gpu_info_vulkan.c index 65033ad8a..7179ec9a3 100644 --- a/discover/gpu_info_vulkan.c +++ b/discover/gpu_info_vulkan.c @@ -48,6 +48,7 @@ void vk_init(char* vk_lib_path, vk_init_resp_t *resp) { {"vkEnumeratePhysicalDevices", (void *)&resp->ch.vkEnumeratePhysicalDevices}, {"vkGetPhysicalDeviceMemoryProperties2", (void *)&resp->ch.vkGetPhysicalDeviceMemoryProperties2}, {"vkDestroyInstance", (void *)&resp->ch.vkDestroyInstance}, + {"vkGetPhysicalDeviceFeatures2", (void *)&resp->ch.vkGetPhysicalDeviceFeatures2}, {NULL, NULL}, }; @@ -117,6 +118,38 @@ void vk_init(char* vk_lib_path, vk_init_resp_t *resp) { resp->num_devices = deviceCount; } +int vk_device_is_supported(vk_handle_t rh, int i) { + VkInstance instance = rh.vk; + uint32_t deviceCount = rh.num_devices; + + VkPhysicalDevice* devices = malloc(deviceCount * sizeof(VkPhysicalDevice)); + if (devices == NULL) { + return 0; + } + + VkResult result = (*rh.vkEnumeratePhysicalDevices)(instance, &deviceCount, devices); + if (result != VK_SUCCESS) { + free(devices); + return 0; + } + + VkPhysicalDeviceVulkan11Features vk11_features = {}; + vk11_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; + vk11_features.pNext = NULL; + + VkPhysicalDeviceFeatures2 device_features2 = {}; + device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + device_features2.pNext = &vk11_features; + + // make sure you have the right function pointer from your loader + (*rh.vkGetPhysicalDeviceFeatures2)(devices[i], &device_features2); + + int supported = vk11_features.storageBuffer16BitAccess ? 1 : 0; + + free(devices); + return supported; +} + int vk_check_flash_attention(vk_handle_t rh, int i) { VkInstance instance = rh.vk; uint32_t deviceCount = rh.num_devices; diff --git a/discover/gpu_info_vulkan.h b/discover/gpu_info_vulkan.h index 42e4b1610..26d00d601 100644 --- a/discover/gpu_info_vulkan.h +++ b/discover/gpu_info_vulkan.h @@ -95,6 +95,8 @@ typedef enum VkResult { typedef enum VkStructureType { VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES = 49, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, @@ -284,6 +286,87 @@ typedef struct VkPhysicalDeviceIDProperties { VkBool32 deviceLUIDValid; } VkPhysicalDeviceIDProperties; +typedef struct VkPhysicalDeviceFeatures { + VkBool32 robustBufferAccess; + VkBool32 fullDrawIndexUint32; + VkBool32 imageCubeArray; + VkBool32 independentBlend; + VkBool32 geometryShader; + VkBool32 tessellationShader; + VkBool32 sampleRateShading; + VkBool32 dualSrcBlend; + VkBool32 logicOp; + VkBool32 multiDrawIndirect; + VkBool32 drawIndirectFirstInstance; + VkBool32 depthClamp; + VkBool32 depthBiasClamp; + VkBool32 fillModeNonSolid; + VkBool32 depthBounds; + VkBool32 wideLines; + VkBool32 largePoints; + VkBool32 alphaToOne; + VkBool32 multiViewport; + VkBool32 samplerAnisotropy; + VkBool32 textureCompressionETC2; + VkBool32 textureCompressionASTC_LDR; + VkBool32 textureCompressionBC; + VkBool32 occlusionQueryPrecise; + VkBool32 pipelineStatisticsQuery; + VkBool32 vertexPipelineStoresAndAtomics; + VkBool32 fragmentStoresAndAtomics; + VkBool32 shaderTessellationAndGeometryPointSize; + VkBool32 shaderImageGatherExtended; + VkBool32 shaderStorageImageExtendedFormats; + VkBool32 shaderStorageImageMultisample; + VkBool32 shaderStorageImageReadWithoutFormat; + VkBool32 shaderStorageImageWriteWithoutFormat; + VkBool32 shaderUniformBufferArrayDynamicIndexing; + VkBool32 shaderSampledImageArrayDynamicIndexing; + VkBool32 shaderStorageBufferArrayDynamicIndexing; + VkBool32 shaderStorageImageArrayDynamicIndexing; + VkBool32 shaderClipDistance; + VkBool32 shaderCullDistance; + VkBool32 shaderFloat64; + VkBool32 shaderInt64; + VkBool32 shaderInt16; + VkBool32 shaderResourceResidency; + VkBool32 shaderResourceMinLod; + VkBool32 sparseBinding; + VkBool32 sparseResidencyBuffer; + VkBool32 sparseResidencyImage2D; + VkBool32 sparseResidencyImage3D; + VkBool32 sparseResidency2Samples; + VkBool32 sparseResidency4Samples; + VkBool32 sparseResidency8Samples; + VkBool32 sparseResidency16Samples; + VkBool32 sparseResidencyAliased; + VkBool32 variableMultisampleRate; + VkBool32 inheritedQueries; +} VkPhysicalDeviceFeatures; + +typedef struct VkPhysicalDeviceFeatures2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceFeatures features; +} VkPhysicalDeviceFeatures2; + +typedef struct VkPhysicalDeviceVulkan11Features { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; + VkBool32 protectedMemory; + VkBool32 samplerYcbcrConversion; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceVulkan11Features; + typedef struct VkMemoryType { VkMemoryPropertyFlags propertyFlags; uint32_t heapIndex; @@ -376,6 +459,9 @@ typedef struct { void (*vkDestroyInstance)( VkInstance instance, const VkAllocationCallbacks* pAllocator); + void (*vkGetPhysicalDeviceFeatures2)( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2* pFeatures); } vk_handle_t; typedef struct vk_init_resp @@ -388,6 +474,7 @@ typedef struct vk_init_resp void vk_init(char* vk_lib_path, vk_init_resp_t *resp); void vk_check_vram(vk_handle_t rh, int i, mem_info_t *resp); int vk_check_flash_attention(vk_handle_t rh, int i); +int vk_device_is_supported(vk_handle_t rh, int i); void vk_release(vk_handle_t rh); #endif