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/include/gpu/vk/GrVkBackendContext.h b/include/gpu/vk/GrVkBackendContext.h
index eb4f43d..67ed5f0 100644
--- a/include/gpu/vk/GrVkBackendContext.h
+++ b/include/gpu/vk/GrVkBackendContext.h
@@ -8,7 +8,6 @@
#ifndef GrVkBackendContext_DEFINED
#define GrVkBackendContext_DEFINED
-#include <functional>
#include "GrVkTypes.h"
#include "SkRefCnt.h"
#include "vk/GrVkMemoryAllocator.h"
@@ -31,12 +30,6 @@
kSampleRateShading_GrVkFeatureFlag = 0x0004,
};
-using GrVkGetProc = std::function<PFN_vkVoidFunction(
- const char*, // function name
- VkInstance, // instance or VK_NULL_HANDLE
- VkDevice // device or VK_NULL_HANDLE
- )>;
-
// The BackendContext contains all of the base Vulkan objects needed by the GrVkGpu. The assumption
// is that the client will set these up and pass them to the GrVkGpu constructor. The VkDevice
// created must support at least one graphics queue, which is passed in as well.
diff --git a/include/gpu/vk/GrVkExtensions.h b/include/gpu/vk/GrVkExtensions.h
index 2a133ab..08bed50 100644
--- a/include/gpu/vk/GrVkExtensions.h
+++ b/include/gpu/vk/GrVkExtensions.h
@@ -8,24 +8,45 @@
#ifndef GrVkExtensions_DEFINED
#define GrVkExtensions_DEFINED
-#include "../private/SkTArray.h"
+#include "../../private/SkTArray.h"
#include "SkString.h"
+#include "vk/GrVkTypes.h"
/**
* Helper class that eats in an array of extensions strings for instance and device and allows for
* quicker querying if an extension is present.
*/
-class GrVkExtensions {
+class SK_API GrVkExtensions {
public:
GrVkExtensions() {}
- void init(uint32_t instanceExtensionCount, const char* const* instanceExtensions,
+ void init(GrVkGetProc, VkInstance, VkPhysicalDevice,
+ uint32_t instanceExtensionCount, const char* const* instanceExtensions,
uint32_t deviceExtensionCount, const char* const* deviceExtensions);
- bool hasExtension(const char[]) const;
+ bool hasExtension(const char[], uint32_t minVersion) const;
+
+ struct Info {
+ Info() {}
+ Info(const char* name) : fName(name), fSpecVersion(0) {}
+
+ SkString fName;
+ uint32_t fSpecVersion;
+
+ struct Less {
+ bool operator() (const Info& a, const SkString& b) {
+ return strcmp(a.fName.c_str(), b.c_str()) < 0;
+ }
+ bool operator() (const SkString& a, const GrVkExtensions::Info& b) {
+ return strcmp(a.c_str(), b.fName.c_str()) < 0;
+ }
+ };
+ };
private:
- SkTArray<SkString> fExtensionStrings;
+ void getSpecVersions(GrVkGetProc getProc, VkInstance, VkPhysicalDevice);
+
+ SkTArray<Info> fExtensions;
};
#endif
diff --git a/include/gpu/vk/GrVkTypes.h b/include/gpu/vk/GrVkTypes.h
index d734c2b..7f9258d 100644
--- a/include/gpu/vk/GrVkTypes.h
+++ b/include/gpu/vk/GrVkTypes.h
@@ -9,24 +9,10 @@
#ifndef GrVkTypes_DEFINED
#define GrVkTypes_DEFINED
+#include <functional>
#include "GrTypes.h"
#include "GrVkDefines.h"
-/**
- * KHR_debug
- */
-/*typedef void (GR_GL_FUNCTION_TYPE* GrVkDEBUGPROC)(GrVkenum source,
- GrVkenum type,
- GrVkuint id,
- GrVkenum severity,
- GrVksizei length,
- const GrVkchar* message,
- const void* userParam);*/
-
-
-
-///////////////////////////////////////////////////////////////////////////////
-
typedef intptr_t GrVkBackendMemory;
/**
@@ -115,4 +101,11 @@
}
};
+using GrVkGetProc = std::function<PFN_vkVoidFunction(
+ const char*, // function name
+ VkInstance, // instance or VK_NULL_HANDLE
+ VkDevice // device or VK_NULL_HANDLE
+ )>;
+
+
#endif
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;
};
diff --git a/tools/gpu/vk/VkTestContext.cpp b/tools/gpu/vk/VkTestContext.cpp
index 9d3bdc5..db78e85 100644
--- a/tools/gpu/vk/VkTestContext.cpp
+++ b/tools/gpu/vk/VkTestContext.cpp
@@ -153,6 +153,7 @@
GrVkExtensions* extensions;
bool ownsContext = true;
VkDebugReportCallbackEXT debugCallback = VK_NULL_HANDLE;
+ PFN_vkDestroyDebugReportCallbackEXT destroyCallback = nullptr;
if (sharedContext) {
backendContext = sharedContext->getVkBackendContext();
extensions = const_cast<GrVkExtensions*>(sharedContext->getVkExtensions());
@@ -177,8 +178,13 @@
&debugCallback)) {
return nullptr;
}
+ if (debugCallback != VK_NULL_HANDLE) {
+ destroyCallback = (PFN_vkDestroyDebugReportCallbackEXT) instProc(
+ backendContext.fInstance, "vkDestroyDebugReportCallbackEXT");
+ }
}
- return new VkTestContextImpl(backendContext, extensions, ownsContext, debugCallback);
+ return new VkTestContextImpl(backendContext, extensions, ownsContext, debugCallback,
+ destroyCallback);
}
~VkTestContextImpl() override { this->teardown(); }
@@ -225,8 +231,10 @@
private:
VkTestContextImpl(const GrVkBackendContext& backendContext, const GrVkExtensions* extensions,
- bool ownsContext, VkDebugReportCallbackEXT debugCallback)
- : VkTestContext(backendContext, extensions, ownsContext, debugCallback) {
+ bool ownsContext, VkDebugReportCallbackEXT debugCallback,
+ PFN_vkDestroyDebugReportCallbackEXT destroyCallback)
+ : VkTestContext(backendContext, extensions, ownsContext, debugCallback,
+ destroyCallback) {
fFenceSync.reset(new VkFenceSync(fVk.fGetProc, fVk.fDevice, fVk.fQueue,
fVk.fGraphicsQueueIndex));
}
diff --git a/tools/gpu/vk/VkTestContext.h b/tools/gpu/vk/VkTestContext.h
index 17c4215..426dd6f 100644
--- a/tools/gpu/vk/VkTestContext.h
+++ b/tools/gpu/vk/VkTestContext.h
@@ -32,16 +32,19 @@
protected:
VkTestContext(const GrVkBackendContext& vk, const GrVkExtensions* extensions, bool ownsContext,
- VkDebugReportCallbackEXT debugCallback)
+ VkDebugReportCallbackEXT debugCallback,
+ PFN_vkDestroyDebugReportCallbackEXT destroyCallback)
: fVk(vk)
, fExtensions(extensions)
, fOwnsContext(ownsContext)
- , fDebugCallback(debugCallback) {}
+ , fDebugCallback(debugCallback)
+ , fDestroyDebugReportCallbackEXT(destroyCallback) {}
- GrVkBackendContext fVk;
- const GrVkExtensions* fExtensions;
- bool fOwnsContext;
- VkDebugReportCallbackEXT fDebugCallback = VK_NULL_HANDLE;
+ GrVkBackendContext fVk;
+ const GrVkExtensions* fExtensions;
+ bool fOwnsContext;
+ VkDebugReportCallbackEXT fDebugCallback = VK_NULL_HANDLE;
+ PFN_vkDestroyDebugReportCallbackEXT fDestroyDebugReportCallbackEXT = nullptr;
private:
typedef TestContext INHERITED;
diff --git a/tools/gpu/vk/VkTestUtils.cpp b/tools/gpu/vk/VkTestUtils.cpp
index b3a3665..faf7e90 100644
--- a/tools/gpu/vk/VkTestUtils.cpp
+++ b/tools/gpu/vk/VkTestUtils.cpp
@@ -571,7 +571,8 @@
VkQueue queue;
grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
- extensions->init((uint32_t) instanceExtensionNames.count(),
+ extensions->init(getProc, inst, physDev,
+ (uint32_t) instanceExtensionNames.count(),
instanceExtensionNames.begin(),
(uint32_t) deviceExtensionNames.count(),
deviceExtensionNames.begin());
diff --git a/tools/sk_app/VulkanWindowContext.cpp b/tools/sk_app/VulkanWindowContext.cpp
index db5cc1e..01129bc 100644
--- a/tools/sk_app/VulkanWindowContext.cpp
+++ b/tools/sk_app/VulkanWindowContext.cpp
@@ -14,8 +14,8 @@
#include "vk/GrVkExtensions.h"
#include "vk/GrVkImage.h"
-#include "vk/GrVkUtil.h"
#include "vk/GrVkTypes.h"
+#include "vk/GrVkUtil.h"
#ifdef VK_USE_PLATFORM_WIN32_KHR
// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
@@ -66,8 +66,8 @@
return;
}
- if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME) ||
- !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
+ if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) ||
+ !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) {
return;
}
@@ -80,6 +80,9 @@
&extensions));
GET_PROC(DestroyInstance);
+ if (fDebugCallback != VK_NULL_HANDLE) {
+ GET_PROC(DestroyDebugReportCallbackEXT);
+ }
GET_PROC(DestroySurfaceKHR);
GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
@@ -453,8 +456,7 @@
#ifdef SK_ENABLE_VK_LAYERS
if (fDebugCallback != VK_NULL_HANDLE) {
- GR_VK_CALL(fInterface, DestroyDebugReportCallbackEXT(fInstance, fDebugCallback,
- nullptr));
+ fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr);
}
#endif
diff --git a/tools/sk_app/VulkanWindowContext.h b/tools/sk_app/VulkanWindowContext.h
index 2e01e29..0b4d5ce 100644
--- a/tools/sk_app/VulkanWindowContext.h
+++ b/tools/sk_app/VulkanWindowContext.h
@@ -93,6 +93,7 @@
PFN_vkDestroyInstance fDestroyInstance = nullptr;
PFN_vkDeviceWaitIdle fDeviceWaitIdle = nullptr;
+ PFN_vkDestroyDebugReportCallbackEXT fDestroyDebugReportCallbackEXT = nullptr;
PFN_vkQueueWaitIdle fQueueWaitIdle = nullptr;
PFN_vkDestroyDevice fDestroyDevice = nullptr;
PFN_vkGetDeviceQueue fGetDeviceQueue = nullptr;