Home | History | Annotate | Download | only in vk
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkAutoMalloc.h"
      9 #include "vk/GrVkBackendContext.h"
     10 #include "vk/GrVkExtensions.h"
     11 #include "vk/GrVkInterface.h"
     12 #include "vk/GrVkUtil.h"
     13 
     14 ////////////////////////////////////////////////////////////////////////////////
     15 // Helper code to set up Vulkan context objects
     16 
     17 #ifdef SK_ENABLE_VK_LAYERS
     18 const char* kDebugLayerNames[] = {
     19     // elements of VK_LAYER_LUNARG_standard_validation
     20     "VK_LAYER_GOOGLE_threading",
     21     "VK_LAYER_LUNARG_parameter_validation",
     22     "VK_LAYER_LUNARG_object_tracker",
     23     "VK_LAYER_LUNARG_image",
     24     "VK_LAYER_LUNARG_core_validation",
     25     "VK_LAYER_LUNARG_swapchain",
     26     "VK_LAYER_GOOGLE_unique_objects",
     27     // not included in standard_validation
     28     //"VK_LAYER_LUNARG_api_dump",
     29     //"VK_LAYER_LUNARG_vktrace",
     30     //"VK_LAYER_LUNARG_screenshot",
     31 };
     32 #endif
     33 
     34 // the minimum version of Vulkan supported
     35 #ifdef SK_BUILD_FOR_ANDROID
     36 const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 3);
     37 #else
     38 const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 8);
     39 #endif
     40 
     41 #define ACQUIRE_VK_PROC(name, instance, device)                                \
     42     PFN_vk##name grVk##name =                                                  \
     43         reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
     44     if (grVk##name == nullptr) {                                               \
     45         SkDebugf("Function ptr for vk%s could not be acquired\n", #name);      \
     46         return nullptr;                                                        \
     47     }
     48 
     49 // Create the base Vulkan objects needed by the GrVkGpu object
     50 const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndexPtr,
     51                                                      CanPresentFn canPresent,
     52                                                      GrVkInterface::GetProc getProc) {
     53     if (!getProc) {
     54         return nullptr;
     55     }
     56     SkASSERT(getProc);
     57 
     58     VkPhysicalDevice physDev;
     59     VkDevice device;
     60     VkInstance inst;
     61     VkResult err;
     62 
     63     const VkApplicationInfo app_info = {
     64         VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
     65         nullptr,                            // pNext
     66         "vktest",                           // pApplicationName
     67         0,                                  // applicationVersion
     68         "vktest",                           // pEngineName
     69         0,                                  // engineVerison
     70         kGrVkMinimumVersion,                // apiVersion
     71     };
     72 
     73     GrVkExtensions extensions(getProc);
     74     extensions.initInstance(kGrVkMinimumVersion);
     75 
     76     SkTArray<const char*> instanceLayerNames;
     77     SkTArray<const char*> instanceExtensionNames;
     78     uint32_t extensionFlags = 0;
     79 #ifdef SK_ENABLE_VK_LAYERS
     80     for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
     81         if (extensions.hasInstanceLayer(kDebugLayerNames[i])) {
     82             instanceLayerNames.push_back(kDebugLayerNames[i]);
     83         }
     84     }
     85     if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
     86         instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
     87         extensionFlags |= kEXT_debug_report_GrVkExtensionFlag;
     88     }
     89 #endif
     90 
     91     if (extensions.hasInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME)) {
     92         instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
     93         extensionFlags |= kKHR_surface_GrVkExtensionFlag;
     94     }
     95     if (extensions.hasInstanceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
     96         instanceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
     97         extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
     98     }
     99 #ifdef SK_BUILD_FOR_WIN
    100     if (extensions.hasInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) {
    101         instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
    102         extensionFlags |= kKHR_win32_surface_GrVkExtensionFlag;
    103     }
    104 #elif defined(SK_BUILD_FOR_ANDROID)
    105     if (extensions.hasInstanceExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
    106         instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
    107         extensionFlags |= kKHR_android_surface_GrVkExtensionFlag;
    108     }
    109 #elif defined(SK_BUILD_FOR_UNIX) && !defined(__Fuchsia__)
    110     if (extensions.hasInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) {
    111         instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
    112         extensionFlags |= kKHR_xcb_surface_GrVkExtensionFlag;
    113     }
    114 #endif
    115 
    116     const VkInstanceCreateInfo instance_create = {
    117         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,    // sType
    118         nullptr,                                   // pNext
    119         0,                                         // flags
    120         &app_info,                                 // pApplicationInfo
    121         (uint32_t) instanceLayerNames.count(),     // enabledLayerNameCount
    122         instanceLayerNames.begin(),                // ppEnabledLayerNames
    123         (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
    124         instanceExtensionNames.begin(),            // ppEnabledExtensionNames
    125     };
    126 
    127     ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
    128     err = grVkCreateInstance(&instance_create, nullptr, &inst);
    129     if (err < 0) {
    130         SkDebugf("vkCreateInstance failed: %d\n", err);
    131         return nullptr;
    132     }
    133 
    134     ACQUIRE_VK_PROC(DestroyInstance, inst, VK_NULL_HANDLE);
    135     ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE);
    136     ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE);
    137     ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE);
    138     ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE);
    139     ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE);
    140     ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE);
    141     ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE);
    142 
    143     uint32_t gpuCount;
    144     err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
    145     if (err) {
    146         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
    147         grVkDestroyInstance(inst, nullptr);
    148         return nullptr;
    149     }
    150     if (!gpuCount) {
    151         SkDebugf("vkEnumeratePhysicalDevices returned no supported devices.\n");
    152         grVkDestroyInstance(inst, nullptr);
    153         return nullptr;
    154     }
    155     // Just returning the first physical device instead of getting the whole array.
    156     // TODO: find best match for our needs
    157     gpuCount = 1;
    158     err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
    159     if (err) {
    160         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
    161         grVkDestroyInstance(inst, nullptr);
    162         return nullptr;
    163     }
    164 
    165     // query to get the initial queue props size
    166     uint32_t queueCount;
    167     grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
    168     if (!queueCount) {
    169         SkDebugf("vkGetPhysicalDeviceQueueFamilyProperties returned no queues.\n");
    170         grVkDestroyInstance(inst, nullptr);
    171         return nullptr;
    172     }
    173 
    174     SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
    175     // now get the actual queue props
    176     VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
    177 
    178     grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
    179 
    180     // iterate to find the graphics queue
    181     uint32_t graphicsQueueIndex = queueCount;
    182     for (uint32_t i = 0; i < queueCount; i++) {
    183         if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
    184             graphicsQueueIndex = i;
    185             break;
    186         }
    187     }
    188     if (graphicsQueueIndex == queueCount) {
    189         SkDebugf("Could not find any supported graphics queues.\n");
    190         grVkDestroyInstance(inst, nullptr);
    191         return nullptr;
    192     }
    193 
    194     // iterate to find the present queue, if needed
    195     uint32_t presentQueueIndex = queueCount;
    196     if (presentQueueIndexPtr && canPresent) {
    197         for (uint32_t i = 0; i < queueCount; i++) {
    198             if (canPresent(inst, physDev, i)) {
    199                 presentQueueIndex = i;
    200                 break;
    201             }
    202         }
    203         if (presentQueueIndex == queueCount) {
    204             SkDebugf("Could not find any supported present queues.\n");
    205             grVkDestroyInstance(inst, nullptr);
    206             return nullptr;
    207         }
    208         *presentQueueIndexPtr = presentQueueIndex;
    209     } else {
    210         // Just setting this so we end up make a single queue for graphics since there was no
    211         // request for a present queue.
    212         presentQueueIndex = graphicsQueueIndex;
    213     }
    214 
    215     extensions.initDevice(kGrVkMinimumVersion, inst, physDev);
    216 
    217     SkTArray<const char*> deviceLayerNames;
    218     SkTArray<const char*> deviceExtensionNames;
    219 #ifdef SK_ENABLE_VK_LAYERS
    220     for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
    221         if (extensions.hasDeviceLayer(kDebugLayerNames[i])) {
    222             deviceLayerNames.push_back(kDebugLayerNames[i]);
    223         }
    224     }
    225 #endif
    226     if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
    227         deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
    228         extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
    229     }
    230     if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) {
    231         deviceExtensionNames.push_back("VK_NV_glsl_shader");
    232         extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag;
    233     }
    234 
    235     // query to get the physical device properties
    236     VkPhysicalDeviceFeatures deviceFeatures;
    237     grVkGetPhysicalDeviceFeatures(physDev, &deviceFeatures);
    238     // this looks like it would slow things down,
    239     // and we can't depend on it on all platforms
    240     deviceFeatures.robustBufferAccess = VK_FALSE;
    241 
    242     uint32_t featureFlags = 0;
    243     if (deviceFeatures.geometryShader) {
    244         featureFlags |= kGeometryShader_GrVkFeatureFlag;
    245     }
    246     if (deviceFeatures.dualSrcBlend) {
    247         featureFlags |= kDualSrcBlend_GrVkFeatureFlag;
    248     }
    249     if (deviceFeatures.sampleRateShading) {
    250         featureFlags |= kSampleRateShading_GrVkFeatureFlag;
    251     }
    252 
    253     float queuePriorities[1] = { 0.0 };
    254     // Here we assume no need for swapchain queue
    255     // If one is needed, the client will need its own setup code
    256     const VkDeviceQueueCreateInfo queueInfo[2] = {
    257         {
    258             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
    259             nullptr,                                    // pNext
    260             0,                                          // VkDeviceQueueCreateFlags
    261             graphicsQueueIndex,                         // queueFamilyIndex
    262             1,                                          // queueCount
    263             queuePriorities,                            // pQueuePriorities
    264         },
    265         {
    266             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
    267             nullptr,                                    // pNext
    268             0,                                          // VkDeviceQueueCreateFlags
    269             presentQueueIndex,                          // queueFamilyIndex
    270             1,                                          // queueCount
    271             queuePriorities,                            // pQueuePriorities
    272         }
    273     };
    274     uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
    275 
    276     const VkDeviceCreateInfo deviceInfo = {
    277         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,    // sType
    278         nullptr,                                 // pNext
    279         0,                                       // VkDeviceCreateFlags
    280         queueInfoCount,                          // queueCreateInfoCount
    281         queueInfo,                               // pQueueCreateInfos
    282         (uint32_t) deviceLayerNames.count(),     // layerCount
    283         deviceLayerNames.begin(),                // ppEnabledLayerNames
    284         (uint32_t) deviceExtensionNames.count(), // extensionCount
    285         deviceExtensionNames.begin(),            // ppEnabledExtensionNames
    286         &deviceFeatures                          // ppEnabledFeatures
    287     };
    288 
    289     err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
    290     if (err) {
    291         SkDebugf("CreateDevice failed: %d\n", err);
    292         grVkDestroyInstance(inst, nullptr);
    293         return nullptr;
    294     }
    295 
    296     auto interface =
    297         sk_make_sp<GrVkInterface>(getProc, inst, device, extensionFlags);
    298     if (!interface->validate(extensionFlags)) {
    299         SkDebugf("Vulkan interface validation failed\n");
    300         grVkDeviceWaitIdle(device);
    301         grVkDestroyDevice(device, nullptr);
    302         grVkDestroyInstance(inst, nullptr);
    303         return nullptr;
    304     }
    305 
    306     VkQueue queue;
    307     grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
    308 
    309     GrVkBackendContext* ctx = new GrVkBackendContext();
    310     ctx->fInstance = inst;
    311     ctx->fPhysicalDevice = physDev;
    312     ctx->fDevice = device;
    313     ctx->fQueue = queue;
    314     ctx->fGraphicsQueueIndex = graphicsQueueIndex;
    315     ctx->fMinAPIVersion = kGrVkMinimumVersion;
    316     ctx->fExtensions = extensionFlags;
    317     ctx->fFeatures = featureFlags;
    318     ctx->fInterface.reset(interface.release());
    319     ctx->fOwnsInstanceAndDevice = true;
    320 
    321     return ctx;
    322 }
    323 
    324 GrVkBackendContext::~GrVkBackendContext() {
    325     if (fInterface == nullptr || !fOwnsInstanceAndDevice) {
    326         return;
    327     }
    328 
    329     fInterface->fFunctions.fDeviceWaitIdle(fDevice);
    330     fInterface->fFunctions.fDestroyDevice(fDevice, nullptr);
    331     fDevice = VK_NULL_HANDLE;
    332     fInterface->fFunctions.fDestroyInstance(fInstance, nullptr);
    333     fInstance = VK_NULL_HANDLE;
    334 }
    335