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 // Create the base Vulkan objects needed by the GrVkGpu object
     42 const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndexPtr,
     43                                                      CanPresentFn canPresent) {
     44     VkPhysicalDevice physDev;
     45     VkDevice device;
     46     VkInstance inst;
     47     VkResult err;
     48 
     49     const VkApplicationInfo app_info = {
     50         VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
     51         nullptr,                            // pNext
     52         "vktest",                           // pApplicationName
     53         0,                                  // applicationVersion
     54         "vktest",                           // pEngineName
     55         0,                                  // engineVerison
     56         kGrVkMinimumVersion,                // apiVersion
     57     };
     58 
     59     GrVkExtensions extensions;
     60     extensions.initInstance(kGrVkMinimumVersion);
     61 
     62     SkTArray<const char*> instanceLayerNames;
     63     SkTArray<const char*> instanceExtensionNames;
     64     uint32_t extensionFlags = 0;
     65 #ifdef SK_ENABLE_VK_LAYERS
     66     for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
     67         if (extensions.hasInstanceLayer(kDebugLayerNames[i])) {
     68             instanceLayerNames.push_back(kDebugLayerNames[i]);
     69         }
     70     }
     71     if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
     72         instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
     73         extensionFlags |= kEXT_debug_report_GrVkExtensionFlag;
     74     }
     75 #endif
     76 
     77     if (extensions.hasInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME)) {
     78         instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
     79         extensionFlags |= kKHR_surface_GrVkExtensionFlag;
     80     }
     81     if (extensions.hasInstanceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
     82         instanceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
     83         extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
     84     }
     85 #ifdef SK_BUILD_FOR_WIN
     86     if (extensions.hasInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) {
     87         instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
     88         extensionFlags |= kKHR_win32_surface_GrVkExtensionFlag;
     89     }
     90 #elif defined(SK_BUILD_FOR_ANDROID)
     91     if (extensions.hasInstanceExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
     92         instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
     93         extensionFlags |= kKHR_android_surface_GrVkExtensionFlag;
     94     }
     95 #elif defined(SK_BUILD_FOR_UNIX)
     96     if (extensions.hasInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) {
     97         instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
     98         extensionFlags |= kKHR_xcb_surface_GrVkExtensionFlag;
     99     }
    100 #endif
    101 
    102     const VkInstanceCreateInfo instance_create = {
    103         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,    // sType
    104         nullptr,                                   // pNext
    105         0,                                         // flags
    106         &app_info,                                 // pApplicationInfo
    107         (uint32_t) instanceLayerNames.count(),     // enabledLayerNameCount
    108         instanceLayerNames.begin(),                // ppEnabledLayerNames
    109         (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
    110         instanceExtensionNames.begin(),            // ppEnabledExtensionNames
    111     };
    112 
    113     err = vkCreateInstance(&instance_create, nullptr, &inst);
    114     if (err < 0) {
    115         SkDebugf("vkCreateInstance failed: %d\n", err);
    116         return nullptr;
    117     }
    118 
    119     uint32_t gpuCount;
    120     err = vkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
    121     if (err) {
    122         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
    123         vkDestroyInstance(inst, nullptr);
    124         return nullptr;
    125     }
    126     SkASSERT(gpuCount > 0);
    127     // Just returning the first physical device instead of getting the whole array.
    128     // TODO: find best match for our needs
    129     gpuCount = 1;
    130     err = vkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
    131     if (err) {
    132         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
    133         vkDestroyInstance(inst, nullptr);
    134         return nullptr;
    135     }
    136 
    137     // query to get the initial queue props size
    138     uint32_t queueCount;
    139     vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
    140     SkASSERT(queueCount >= 1);
    141 
    142     SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
    143     // now get the actual queue props
    144     VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
    145 
    146     vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
    147 
    148     // iterate to find the graphics queue
    149     uint32_t graphicsQueueIndex = queueCount;
    150     for (uint32_t i = 0; i < queueCount; i++) {
    151         if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
    152             graphicsQueueIndex = i;
    153             break;
    154         }
    155     }
    156     SkASSERT(graphicsQueueIndex < queueCount);
    157 
    158     // iterate to find the present queue, if needed
    159     uint32_t presentQueueIndex = graphicsQueueIndex;
    160     if (presentQueueIndexPtr && canPresent) {
    161         for (uint32_t i = 0; i < queueCount; i++) {
    162             if (canPresent(inst, physDev, i)) {
    163                 presentQueueIndex = i;
    164                 break;
    165             }
    166         }
    167         SkASSERT(presentQueueIndex < queueCount);
    168         *presentQueueIndexPtr = presentQueueIndex;
    169     }
    170 
    171     extensions.initDevice(kGrVkMinimumVersion, inst, physDev);
    172 
    173     SkTArray<const char*> deviceLayerNames;
    174     SkTArray<const char*> deviceExtensionNames;
    175 #ifdef SK_ENABLE_VK_LAYERS
    176     for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
    177         if (extensions.hasDeviceLayer(kDebugLayerNames[i])) {
    178             deviceLayerNames.push_back(kDebugLayerNames[i]);
    179         }
    180     }
    181 #endif
    182     if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
    183         deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
    184         extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
    185     }
    186     if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) {
    187         deviceExtensionNames.push_back("VK_NV_glsl_shader");
    188         extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag;
    189     }
    190 
    191     // query to get the physical device properties
    192     VkPhysicalDeviceFeatures deviceFeatures;
    193     vkGetPhysicalDeviceFeatures(physDev, &deviceFeatures);
    194     // this looks like it would slow things down,
    195     // and we can't depend on it on all platforms
    196     deviceFeatures.robustBufferAccess = VK_FALSE;
    197 
    198     uint32_t featureFlags = 0;
    199     if (deviceFeatures.geometryShader) {
    200         featureFlags |= kGeometryShader_GrVkFeatureFlag;
    201     }
    202     if (deviceFeatures.dualSrcBlend) {
    203         featureFlags |= kDualSrcBlend_GrVkFeatureFlag;
    204     }
    205     if (deviceFeatures.sampleRateShading) {
    206         featureFlags |= kSampleRateShading_GrVkFeatureFlag;
    207     }
    208 
    209     float queuePriorities[1] = { 0.0 };
    210     // Here we assume no need for swapchain queue
    211     // If one is needed, the client will need its own setup code
    212     const VkDeviceQueueCreateInfo queueInfo[2] = {
    213         {
    214             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
    215             nullptr,                                    // pNext
    216             0,                                          // VkDeviceQueueCreateFlags
    217             graphicsQueueIndex,                         // queueFamilyIndex
    218             1,                                          // queueCount
    219             queuePriorities,                            // pQueuePriorities
    220         },
    221         {
    222             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
    223             nullptr,                                    // pNext
    224             0,                                          // VkDeviceQueueCreateFlags
    225             presentQueueIndex,                          // queueFamilyIndex
    226             1,                                          // queueCount
    227             queuePriorities,                            // pQueuePriorities
    228         }
    229     };
    230     uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
    231 
    232     const VkDeviceCreateInfo deviceInfo = {
    233         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,    // sType
    234         nullptr,                                 // pNext
    235         0,                                       // VkDeviceCreateFlags
    236         queueInfoCount,                          // queueCreateInfoCount
    237         queueInfo,                               // pQueueCreateInfos
    238         (uint32_t) deviceLayerNames.count(),     // layerCount
    239         deviceLayerNames.begin(),                // ppEnabledLayerNames
    240         (uint32_t) deviceExtensionNames.count(), // extensionCount
    241         deviceExtensionNames.begin(),            // ppEnabledExtensionNames
    242         &deviceFeatures                          // ppEnabledFeatures
    243     };
    244 
    245     err = vkCreateDevice(physDev, &deviceInfo, nullptr, &device);
    246     if (err) {
    247         SkDebugf("CreateDevice failed: %d\n", err);
    248         vkDestroyInstance(inst, nullptr);
    249         return nullptr;
    250     }
    251 
    252     VkQueue queue;
    253     vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
    254 
    255     GrVkBackendContext* ctx = new GrVkBackendContext();
    256     ctx->fInstance = inst;
    257     ctx->fPhysicalDevice = physDev;
    258     ctx->fDevice = device;
    259     ctx->fQueue = queue;
    260     ctx->fGraphicsQueueIndex = graphicsQueueIndex;
    261     ctx->fMinAPIVersion = kGrVkMinimumVersion;
    262     ctx->fExtensions = extensionFlags;
    263     ctx->fFeatures = featureFlags;
    264     ctx->fInterface.reset(GrVkCreateInterface(inst, device, extensionFlags));
    265 
    266     return ctx;
    267 }
    268 
    269 GrVkBackendContext::~GrVkBackendContext() {
    270     vkDeviceWaitIdle(fDevice);
    271     vkDestroyDevice(fDevice, nullptr);
    272     fDevice = VK_NULL_HANDLE;
    273     vkDestroyInstance(fInstance, nullptr);
    274     fInstance = VK_NULL_HANDLE;
    275 }
    276