Make sure we check the version number of Vulkan Extensions.

Bug: skia:
Change-Id: Iff02911491cc61e39f94370c644b6666e5f9118f
Reviewed-on: https://skia-review.googlesource.com/137881
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/vk/GrVkExtensions.cpp b/src/gpu/vk/GrVkExtensions.cpp
index 6cc20e6..4d7fc11 100644
--- a/src/gpu/vk/GrVkExtensions.cpp
+++ b/src/gpu/vk/GrVkExtensions.cpp
@@ -13,50 +13,119 @@
 #include "SkTSearch.h"
 #include "SkTSort.h"
 
-namespace { // This cannot be static because it is used as a template parameter.
-inline bool extension_compare(const SkString& a, const SkString& b) {
-    return strcmp(a.c_str(), b.c_str()) < 0;
-}
-}
-
-// finds the index of ext in strings or a negative result if ext is not found.
-static int find_string(const SkTArray<SkString>& strings, const char ext[]) {
-    if (strings.empty()) {
+// finds the index of ext in infos or a negative result if ext is not found.
+static int find_info(const SkTArray<GrVkExtensions::Info>& infos, const char ext[]) {
+    if (infos.empty()) {
         return -1;
     }
     SkString extensionStr(ext);
-    int idx = SkTSearch<SkString, extension_compare>(&strings.front(),
-                                                     strings.count(),
-                                                     extensionStr,
-                                                     sizeof(SkString));
+    GrVkExtensions::Info::Less less;
+    int idx = SkTSearch<GrVkExtensions::Info, SkString, GrVkExtensions::Info::Less>(
+            &infos.front(), infos.count(), extensionStr, sizeof(GrVkExtensions::Info),
+            less);
     return idx;
 }
 
-void GrVkExtensions::init(uint32_t instanceExtensionCount,
+namespace { // This cannot be static because it is used as a template parameter.
+inline bool extension_compare(const GrVkExtensions::Info& a, const GrVkExtensions::Info& b) {
+    return strcmp(a.fName.c_str(), b.fName.c_str()) < 0;
+}
+}
+
+void GrVkExtensions::init(GrVkGetProc getProc,
+                          VkInstance instance,
+                          VkPhysicalDevice physDev,
+                          uint32_t instanceExtensionCount,
                           const char* const* instanceExtensions,
                           uint32_t deviceExtensionCount,
                           const char* const* deviceExtensions) {
-    SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
+    SkTLessFunctionToFunctorAdaptor<GrVkExtensions::Info, extension_compare> cmp;
 
     for (uint32_t i = 0; i < instanceExtensionCount; ++i) {
         const char* extension = instanceExtensions[i];
         // if not already in the list, add it
-        if (find_string(fExtensionStrings, extension) < 0) {
-            fExtensionStrings.push_back() = extension;
-            SkTQSort(&fExtensionStrings.front(), &fExtensionStrings.back(), cmp);
+        if (find_info(fExtensions, extension) < 0) {
+            fExtensions.push_back() = Info(extension);
+            SkTQSort(&fExtensions.front(), &fExtensions.back(), cmp);
         }
     }
     for (uint32_t i = 0; i < deviceExtensionCount; ++i) {
         const char* extension = deviceExtensions[i];
         // if not already in the list, add it
-        if (find_string(fExtensionStrings, extension) < 0) {
-            fExtensionStrings.push_back() = extension;
-            SkTQSort(&fExtensionStrings.front(), &fExtensionStrings.back(), cmp);
+        if (find_info(fExtensions, extension) < 0) {
+            fExtensions.push_back() = Info(extension);
+            SkTQSort(&fExtensions.front(), &fExtensions.back(), cmp);
         }
     }
+    this->getSpecVersions(getProc, instance, physDev);
 }
 
-bool GrVkExtensions::hasExtension(const char ext[]) const {
-    return find_string(fExtensionStrings, ext) >= 0;
+#define GET_PROC(F, inst)                                                        \
+        PFN_vk##F grVk##F = (PFN_vk ## F) getProc("vk" #F, inst, VK_NULL_HANDLE)
+
+void GrVkExtensions::getSpecVersions(GrVkGetProc getProc, VkInstance instance,
+                                     VkPhysicalDevice physDevice) {
+    // We grab all the extensions for the VkInstance and VkDevice so we can look up what spec
+    // version each of the supported extensions are. We do not grab the extensions for layers
+    // because we don't know what layers the client has enabled and in general we don't do anything
+    // special for those extensions.
+
+    if (instance == VK_NULL_HANDLE) {
+        return;
+    }
+    GET_PROC(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE);
+    SkASSERT(grVkEnumerateInstanceExtensionProperties);
+
+    VkResult res;
+    // instance extensions
+    uint32_t extensionCount = 0;
+    res = grVkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return;
+    }
+    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+    res = grVkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
+    if (VK_SUCCESS != res) {
+        delete[] extensions;
+        return;
+    }
+    for (uint32_t i = 0; i < extensionCount; ++i) {
+        int idx = find_info(fExtensions, extensions[i].extensionName);
+        if (idx >= 0) {
+            fExtensions[idx].fSpecVersion = extensions[i].specVersion;
+        }
+    }
+    delete[] extensions;
+
+    if (physDevice == VK_NULL_HANDLE) {
+        return;
+    }
+    GET_PROC(EnumerateDeviceExtensionProperties, instance);
+    SkASSERT(grVkEnumerateDeviceExtensionProperties);
+
+    // device extensions
+    extensionCount = 0;
+    res = grVkEnumerateDeviceExtensionProperties(physDevice, nullptr, &extensionCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return;
+    }
+    extensions = new VkExtensionProperties[extensionCount];
+    res = grVkEnumerateDeviceExtensionProperties(physDevice, nullptr, &extensionCount, extensions);
+    if (VK_SUCCESS != res) {
+        delete[] extensions;
+        return;
+    }
+    for (uint32_t i = 0; i < extensionCount; ++i) {
+        int idx = find_info(fExtensions, extensions[i].extensionName);
+        if (idx >= 0) {
+            fExtensions[idx].fSpecVersion = extensions[i].specVersion;
+        }
+    }
+    delete[] extensions;
+}
+
+bool GrVkExtensions::hasExtension(const char ext[], uint32_t minVersion) const {
+    int idx = find_info(fExtensions, ext);
+    return  idx >= 0 && fExtensions[idx].fSpecVersion >= minVersion;
 }
 
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 5a19713..6a37c27 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -37,6 +37,7 @@
 #include "SkSLCompiler.h"
 #include "SkTo.h"
 
+#include "vk/GrVkExtensions.h"
 #include "vk/GrVkTypes.h"
 
 #include <utility>
diff --git a/src/gpu/vk/GrVkInterface.cpp b/src/gpu/vk/GrVkInterface.cpp
index 7ffa8c0..bbdb873 100644
--- a/src/gpu/vk/GrVkInterface.cpp
+++ b/src/gpu/vk/GrVkInterface.cpp
@@ -7,6 +7,7 @@
 
 #include "GrVkInterface.h"
 #include "vk/GrVkBackendContext.h"
+#include "vk/GrVkExtensions.h"
 #include "vk/GrVkUtil.h"
 
 #define ACQUIRE_PROC(name, instance, device) fFunctions.f##name = \
@@ -39,13 +40,6 @@
     ACQUIRE_PROC(EnumerateDeviceExtensionProperties, instance, VK_NULL_HANDLE);
     ACQUIRE_PROC(EnumerateDeviceLayerProperties, instance, VK_NULL_HANDLE);
 
-    if (extensions->hasExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
-        // Also instance Procs.
-        ACQUIRE_PROC(CreateDebugReportCallbackEXT, instance, VK_NULL_HANDLE);
-        ACQUIRE_PROC(DebugReportMessageEXT, instance, VK_NULL_HANDLE);
-        ACQUIRE_PROC(DestroyDebugReportCallbackEXT, instance, VK_NULL_HANDLE);
-    }
-
     // Device Procs.
     ACQUIRE_PROC(GetDeviceQueue, VK_NULL_HANDLE, device);
     ACQUIRE_PROC(QueueSubmit, VK_NULL_HANDLE, device);
@@ -318,13 +312,6 @@
         RETURN_FALSE_INTERFACE
     }
 
-    if (extensions->hasExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
-        if (nullptr == fFunctions.fCreateDebugReportCallbackEXT ||
-            nullptr == fFunctions.fDebugReportMessageEXT ||
-            nullptr == fFunctions.fDestroyDebugReportCallbackEXT) {
-            RETURN_FALSE_INTERFACE
-        }
-    }
     return true;
 }
 
diff --git a/src/gpu/vk/GrVkInterface.h b/src/gpu/vk/GrVkInterface.h
index 22991ac..3345831 100644
--- a/src/gpu/vk/GrVkInterface.h
+++ b/src/gpu/vk/GrVkInterface.h
@@ -12,7 +12,9 @@
 
 #include "vk/GrVkBackendContext.h"
 #include "vk/GrVkTypes.h"
-#include "vk/GrVkExtensions.h"
+#include "vk/GrVkDefines.h"
+
+class GrVkExtensions;
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -22,7 +24,7 @@
  * available based on the Vulkan's version must be non-NULL or GrContext creation
  * will fail. This can be tested with the validate() method.
  */
-struct SK_API GrVkInterface : public SkRefCnt {
+struct GrVkInterface : public SkRefCnt {
 private:
     // simple wrapper class that exists only to initialize a pointer to NULL
     template <typename FNPTR_TYPE> class VkPtr {
@@ -186,10 +188,6 @@
         VkPtr<PFN_vkCmdNextSubpass> fCmdNextSubpass;
         VkPtr<PFN_vkCmdEndRenderPass> fCmdEndRenderPass;
         VkPtr<PFN_vkCmdExecuteCommands> fCmdExecuteCommands;
-
-        VkPtr<PFN_vkCreateDebugReportCallbackEXT> fCreateDebugReportCallbackEXT;
-        VkPtr<PFN_vkDebugReportMessageEXT> fDebugReportMessageEXT;
-        VkPtr<PFN_vkDestroyDebugReportCallbackEXT> fDestroyDebugReportCallbackEXT;
     } fFunctions;
 };