aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar jvanverth <jvanverth@google.com>2016-03-18 12:39:05 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-03-18 12:39:05 -0700
commitd2497f35ce9e9e70ab6c7acd82b212c80cb86d3a (patch)
treef66fe30164e8edc3a8979b0d105d23f45849c3f6
parente820dfebbc652bfc4a653f07a29f5fe371eb019b (diff)
Enable extension support and debug layer.
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--include/gpu/vk/GrVkInterface.h21
-rw-r--r--src/gpu/vk/GrVkExtensions.cpp252
-rw-r--r--src/gpu/vk/GrVkExtensions.h92
-rw-r--r--src/gpu/vk/GrVkGpu.cpp178
-rw-r--r--src/gpu/vk/GrVkGpu.h9
-rw-r--r--src/gpu/vk/GrVkInterface.cpp30
-rw-r--r--src/gpu/vk/GrVkUtil.h3
8 files changed, 579 insertions, 8 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 2b5f9cd8d3..40def5acb7 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -447,6 +447,8 @@
'<(skia_src_path)/gpu/vk/GrVkCommandBuffer.h',
'<(skia_src_path)/gpu/vk/GrVkDescriptorPool.cpp',
'<(skia_src_path)/gpu/vk/GrVkDescriptorPool.h',
+ '<(skia_src_path)/gpu/vk/GrVkExtensions.cpp',
+ '<(skia_src_path)/gpu/vk/GrVkExtensions.h',
'<(skia_src_path)/gpu/vk/GrVkFramebuffer.cpp',
'<(skia_src_path)/gpu/vk/GrVkFramebuffer.h',
'<(skia_src_path)/gpu/vk/GrVkGpu.cpp',
diff --git a/include/gpu/vk/GrVkInterface.h b/include/gpu/vk/GrVkInterface.h
index 5676b86e3a..a6cfba73ab 100644
--- a/include/gpu/vk/GrVkInterface.h
+++ b/include/gpu/vk/GrVkInterface.h
@@ -10,6 +10,8 @@
#include "SkRefCnt.h"
+#include "GrVkExtensions.h"
+
#include "vulkan/vulkan.h"
////////////////////////////////////////////////////////////////////////////////
@@ -54,6 +56,21 @@ public:
// function pointers have been initialized for Vulkan version.
bool validate() const;
+ GrVkExtensions fExtensions;
+
+ bool hasInstanceExtension(const char ext[]) const {
+ return fExtensions.hasInstanceExtension(ext);
+ }
+ bool hasDeviceExtension(const char ext[]) const {
+ return fExtensions.hasDeviceExtension(ext);
+ }
+ bool hasInstanceLayer(const char ext[]) const {
+ return fExtensions.hasInstanceLayer(ext);
+ }
+ bool hasDeviceLayer(const char ext[]) const {
+ return fExtensions.hasDeviceLayer(ext);
+ }
+
/**
* The function pointers are in a struct so that we can have a compiler generated assignment
* operator.
@@ -212,7 +229,11 @@ public:
VkPtr<PFN_vkGetDisplayPlaneCapabilitiesKHR> fGetDisplayPlaneCapabilitiesKHR;
VkPtr<PFN_vkCreateDisplayPlaneSurfaceKHR> fCreateDisplayPlaneSurfaceKHR;
VkPtr<PFN_vkCreateSharedSwapchainsKHR> fCreateSharedSwapchainsKHR;
+ VkPtr<PFN_vkCreateDebugReportCallbackEXT> fCreateDebugReportCallbackEXT;
+ VkPtr<PFN_vkDebugReportMessageEXT> fDebugReportMessageEXT;
+ VkPtr<PFN_vkDestroyDebugReportCallbackEXT> fDestroyDebugReportCallbackEXT;
} fFunctions;
+
};
#endif
diff --git a/src/gpu/vk/GrVkExtensions.cpp b/src/gpu/vk/GrVkExtensions.cpp
new file mode 100644
index 0000000000..8fa99cf9fc
--- /dev/null
+++ b/src/gpu/vk/GrVkExtensions.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "vk/GrVkExtensions.h"
+#include "vk/GrVkUtil.h"
+
+#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()) {
+ return -1;
+ }
+ SkString extensionStr(ext);
+ int idx = SkTSearch<SkString, extension_compare>(&strings.front(),
+ strings.count(),
+ extensionStr,
+ sizeof(SkString));
+ return idx;
+}
+
+GrVkExtensions::GrVkExtensions(const GrVkExtensions& that)
+ : fInstanceExtensionStrings(new SkTArray<SkString>)
+ , fDeviceExtensionStrings(new SkTArray<SkString>)
+ , fInstanceLayerStrings(new SkTArray<SkString>)
+ , fDeviceLayerStrings(new SkTArray<SkString>) {
+ *this = that;
+}
+
+GrVkExtensions& GrVkExtensions::operator=(const GrVkExtensions& that) {
+ *fInstanceExtensionStrings = *that.fInstanceExtensionStrings;
+ *fDeviceExtensionStrings = *that.fDeviceExtensionStrings;
+ *fInstanceLayerStrings = *that.fInstanceLayerStrings;
+ *fDeviceLayerStrings = *that.fDeviceLayerStrings;
+
+ fInitialized = that.fInitialized;
+ return *this;
+}
+
+bool GrVkExtensions::init(
+ uint32_t specVersion,
+ PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties,
+ PFN_vkEnumerateDeviceExtensionProperties enumerateDeviceExtensionProperties,
+ PFN_vkEnumerateInstanceLayerProperties enumerateInstanceLayerProperties,
+ PFN_vkEnumerateDeviceLayerProperties enumerateDeviceLayerProperties) {
+ fInitialized = false;
+ this->reset();
+
+ if (!enumerateInstanceExtensionProperties ||
+ !enumerateDeviceExtensionProperties ||
+ !enumerateInstanceLayerProperties ||
+ !enumerateDeviceLayerProperties) {
+ return false;
+ }
+
+ // instance extensions
+ uint32_t extensionCount = 0;
+ VkResult res = enumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
+
+ VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+ res = enumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
+
+ fInstanceExtensionStrings->push_back_n(extensionCount);
+ for (uint32_t i = 0; i < extensionCount; ++i) {
+ if (specVersion >= extensions[i].specVersion) {
+ (*fInstanceExtensionStrings)[i] = extensions[i].extensionName;
+ }
+ }
+ delete [] extensions;
+
+ if (!fInstanceExtensionStrings->empty()) {
+ SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
+ SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(), cmp);
+ }
+
+ fInitialized = true;
+ return true;
+}
+
+
+bool GrVkExtensions::hasInstanceExtension(const char ext[]) const {
+ SkASSERT(fInitialized);
+
+ return find_string(*fInstanceExtensionStrings, ext) >= 0;
+}
+
+bool GrVkExtensions::hasDeviceExtension(const char ext[]) const {
+ SkASSERT(fInitialized);
+
+ return find_string(*fDeviceExtensionStrings, ext) >= 0;
+}
+
+bool GrVkExtensions::hasInstanceLayer(const char ext[]) const {
+ SkASSERT(fInitialized);
+
+ return find_string(*fInstanceLayerStrings, ext) >= 0;
+}
+
+bool GrVkExtensions::hasDeviceLayer(const char ext[]) const {
+ SkASSERT(fInitialized);
+
+ return find_string(*fDeviceLayerStrings, ext) >= 0;
+}
+
+
+bool GrVkExtensions::removeInstanceExtension(const char ext[]) {
+ SkASSERT(fInitialized);
+ int idx = find_string(*fInstanceExtensionStrings, ext);
+ if (idx >= 0) {
+ // This is not terribly effecient but we really only expect this function to be called at
+ // most a handful of times when our test programs start.
+ SkAutoTDelete< SkTArray<SkString> > oldStrings(fInstanceExtensionStrings.release());
+ fInstanceExtensionStrings.reset(new SkTArray<SkString>(oldStrings->count() - 1));
+ fInstanceExtensionStrings->push_back_n(idx, &oldStrings->front());
+ fInstanceExtensionStrings->push_back_n(oldStrings->count() - idx-1, &(*oldStrings)[idx]+1);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool GrVkExtensions::removeDeviceExtension(const char ext[]) {
+ SkASSERT(fInitialized);
+ int idx = find_string(*fDeviceExtensionStrings, ext);
+ if (idx >= 0) {
+ // This is not terribly effecient but we really only expect this function to be called at
+ // most a handful of times when our test programs start.
+ SkAutoTDelete< SkTArray<SkString> > oldStrings(fDeviceExtensionStrings.release());
+ fDeviceExtensionStrings.reset(new SkTArray<SkString>(oldStrings->count() - 1));
+ fDeviceExtensionStrings->push_back_n(idx, &oldStrings->front());
+ fDeviceExtensionStrings->push_back_n(oldStrings->count() - idx-1, &(*oldStrings)[idx] + 1);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool GrVkExtensions::removeInstanceLayer(const char ext[]) {
+ SkASSERT(fInitialized);
+ int idx = find_string(*fInstanceLayerStrings, ext);
+ if (idx >= 0) {
+ // This is not terribly effecient but we really only expect this function to be called at
+ // most a handful of times when our test programs start.
+ SkAutoTDelete< SkTArray<SkString> > oldStrings(fInstanceLayerStrings.release());
+ fInstanceLayerStrings.reset(new SkTArray<SkString>(oldStrings->count() - 1));
+ fInstanceLayerStrings->push_back_n(idx, &oldStrings->front());
+ fInstanceLayerStrings->push_back_n(oldStrings->count() - idx - 1, &(*oldStrings)[idx] + 1);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool GrVkExtensions::removeDeviceLayer(const char ext[]) {
+ SkASSERT(fInitialized);
+ int idx = find_string(*fDeviceLayerStrings, ext);
+ if (idx >= 0) {
+ // This is not terribly effecient but we really only expect this function to be called at
+ // most a handful of times when our test programs start.
+ SkAutoTDelete< SkTArray<SkString> > oldStrings(fDeviceLayerStrings.release());
+ fDeviceLayerStrings.reset(new SkTArray<SkString>(oldStrings->count() - 1));
+ fDeviceLayerStrings->push_back_n(idx, &oldStrings->front());
+ fDeviceLayerStrings->push_back_n(oldStrings->count() - idx - 1, &(*oldStrings)[idx] + 1);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+void GrVkExtensions::addInstanceExtension(const char ext[]) {
+ int idx = find_string(*fInstanceExtensionStrings, ext);
+ if (idx < 0) {
+ // This is not the most effecient approach since we end up doing a full sort of the
+ // extensions after the add
+ fInstanceExtensionStrings->push_back().set(ext);
+ SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
+ SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(), cmp);
+ }
+}
+
+void GrVkExtensions::addDeviceExtension(const char ext[]) {
+ int idx = find_string(*fDeviceExtensionStrings, ext);
+ if (idx < 0) {
+ // This is not the most effecient approach since we end up doing a full sort of the
+ // extensions after the add
+ fDeviceExtensionStrings->push_back().set(ext);
+ SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
+ SkTQSort(&fDeviceExtensionStrings->front(), &fDeviceExtensionStrings->back(), cmp);
+ }
+}
+
+void GrVkExtensions::addInstanceLayer(const char ext[]) {
+ int idx = find_string(*fInstanceLayerStrings, ext);
+ if (idx < 0) {
+ // This is not the most effecient approach since we end up doing a full sort of the
+ // extensions after the add
+ fInstanceLayerStrings->push_back().set(ext);
+ SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
+ SkTQSort(&fInstanceLayerStrings->front(), &fInstanceLayerStrings->back(), cmp);
+ }
+}
+
+void GrVkExtensions::addDeviceLayer(const char ext[]) {
+ int idx = find_string(*fDeviceLayerStrings, ext);
+ if (idx < 0) {
+ // This is not the most effecient approach since we end up doing a full sort of the
+ // extensions after the add
+ fDeviceLayerStrings->push_back().set(ext);
+ SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
+ SkTQSort(&fDeviceLayerStrings->front(), &fDeviceLayerStrings->back(), cmp);
+ }
+}
+
+void GrVkExtensions::print(const char* sep) const {
+ if (nullptr == sep) {
+ sep = " ";
+ }
+ int cnt = fInstanceExtensionStrings->count();
+ SkDebugf("Instance Extensions: ");
+ for (int i = 0; i < cnt; ++i) {
+ SkDebugf("%s%s", (*fInstanceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
+ }
+ cnt = fDeviceExtensionStrings->count();
+ SkDebugf("\nDevice Extensions: ");
+ for (int i = 0; i < cnt; ++i) {
+ SkDebugf("%s%s", (*fDeviceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
+ }
+ cnt = fInstanceLayerStrings->count();
+ SkDebugf("\nInstance Layers: ");
+ for (int i = 0; i < cnt; ++i) {
+ SkDebugf("%s%s", (*fInstanceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
+ }
+ cnt = fDeviceLayerStrings->count();
+ SkDebugf("\nDevice Layers: ");
+ for (int i = 0; i < cnt; ++i) {
+ SkDebugf("%s%s", (*fDeviceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
+ }
+}
diff --git a/src/gpu/vk/GrVkExtensions.h b/src/gpu/vk/GrVkExtensions.h
new file mode 100644
index 0000000000..d1d57e424a
--- /dev/null
+++ b/src/gpu/vk/GrVkExtensions.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrVkExtensions_DEFINED
+#define GrVkExtensions_DEFINED
+
+#include "../../private/SkTArray.h"
+#include "SkString.h"
+#include "vulkan/vulkan.h"
+
+/**
+ * This helper queries the current Vulkan context for its extensions and layers, remembers them,
+ * and can be queried. It supports queries for both instance and device extensions and layers.
+ */
+class SK_API GrVkExtensions {
+public:
+ GrVkExtensions() : fInitialized(false)
+ , fInstanceExtensionStrings(new SkTArray<SkString>)
+ , fDeviceExtensionStrings(new SkTArray<SkString>)
+ , fInstanceLayerStrings(new SkTArray<SkString>)
+ , fDeviceLayerStrings(new SkTArray<SkString>) {}
+
+ GrVkExtensions(const GrVkExtensions&);
+
+ GrVkExtensions& operator=(const GrVkExtensions&);
+
+ void swap(GrVkExtensions* that) {
+ fInstanceExtensionStrings.swap(that->fInstanceExtensionStrings);
+ fDeviceExtensionStrings.swap(that->fDeviceExtensionStrings);
+ fInstanceLayerStrings.swap(that->fInstanceLayerStrings);
+ fDeviceLayerStrings.swap(that->fDeviceLayerStrings);
+
+ SkTSwap(fInitialized, that->fInitialized);
+ }
+
+ /**
+ * We sometimes need to use this class without having yet created a GrVkInterface.
+ */
+ bool init(uint32_t specVersion,
+ PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties,
+ PFN_vkEnumerateDeviceExtensionProperties enumerateDeviceExtensionProperties,
+ PFN_vkEnumerateInstanceLayerProperties enumerateInstanceLayerProperties,
+ PFN_vkEnumerateDeviceLayerProperties enumerateDeviceLayerProperties);
+
+ bool isInitialized() const { return fInitialized; }
+
+ /**
+ * Queries whether an extension or layer is present. Will fail if init() has not been called.
+ */
+ bool hasInstanceExtension(const char[]) const;
+ bool hasDeviceExtension(const char[]) const;
+ bool hasInstanceLayer(const char[]) const;
+ bool hasDeviceLayer(const char[]) const;
+
+ /**
+ * Removes an extension or layer if present. Returns true if it was present before the call.
+ */
+ bool removeInstanceExtension(const char[]);
+ bool removeDeviceExtension(const char[]);
+ bool removeInstanceLayer(const char[]);
+ bool removeDeviceLayer(const char[]);
+
+ /**
+ * Adds an extension or layer to list
+ */
+ void addInstanceExtension(const char[]);
+ void addDeviceExtension(const char[]);
+ void addInstanceLayer(const char[]);
+ void addDeviceLayer(const char[]);
+
+ void reset() {
+ fInstanceExtensionStrings->reset();
+ fDeviceExtensionStrings->reset();
+ fInstanceLayerStrings->reset();
+ fDeviceLayerStrings->reset();
+ }
+
+ void print(const char* sep = "\n") const;
+
+private:
+ bool fInitialized;
+ SkAutoTDelete<SkTArray<SkString> > fInstanceExtensionStrings;
+ SkAutoTDelete<SkTArray<SkString> > fDeviceExtensionStrings;
+ SkAutoTDelete<SkTArray<SkString> > fInstanceLayerStrings;
+ SkAutoTDelete<SkTArray<SkString> > fDeviceLayerStrings;
+};
+
+#endif
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 16526f6613..ee87f49b07 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -43,6 +43,124 @@
////////////////////////////////////////////////////////////////////////////////
// Stuff used to set up a GrVkGpu secrectly for now.
+
+#ifdef ENABLE_VK_LAYERS
+VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objectType,
+ uint64_t object,
+ size_t location,
+ int32_t messageCode,
+ const char* pLayerPrefix,
+ const char* pMessage,
+ void* pUserData) {
+ if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
+ SkDebugf("Vulkan error [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
+ } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
+ SkDebugf("Vulkan warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
+ } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
+ SkDebugf("Vulkan perf warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
+ } else {
+ SkDebugf("Vulkan info/debug [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
+ }
+ return VK_FALSE;
+}
+
+const char* kEnabledLayerNames[] = {
+ // elements of VK_LAYER_LUNARG_standard_validation
+ "VK_LAYER_LUNARG_threading",
+ "VK_LAYER_LUNARG_param_checker",
+ "VK_LAYER_LUNARG_device_limits",
+ "VK_LAYER_LUNARG_object_tracker",
+ "VK_LAYER_LUNARG_image",
+ "VK_LAYER_LUNARG_mem_tracker",
+ "VK_LAYER_LUNARG_draw_state",
+ "VK_LAYER_LUNARG_swapchain",
+ "VK_LAYER_GOOGLE_unique_objects",
+ // not included in standard_validation
+ //"VK_LAYER_LUNARG_api_dump",
+};
+const char* kEnabledInstanceExtensionNames[] = {
+ VK_EXT_DEBUG_REPORT_EXTENSION_NAME
+};
+
+bool verify_instance_layers() {
+ // make sure we can actually use the extensions and layers above
+ uint32_t extensionCount;
+ VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+ VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+ res = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+ int instanceExtensionsFound = 0;
+ for (uint32_t j = 0; j < ARRAYSIZE(kEnabledInstanceExtensionNames); ++j) {
+ for (uint32_t i = 0; i < extensionCount; ++i) {
+ if (!strncmp(extensions[i].extensionName, kEnabledInstanceExtensionNames[j],
+ strlen(kEnabledInstanceExtensionNames[j]))) {
+ ++instanceExtensionsFound;
+ break;
+ }
+ }
+ }
+ delete[] extensions;
+
+ uint32_t layerCount;
+ res = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+ VkLayerProperties* layers = new VkLayerProperties[layerCount];
+ res = vkEnumerateInstanceLayerProperties(&layerCount, layers);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+ int instanceLayersFound = 0;
+ for (uint32_t j = 0; j < ARRAYSIZE(kEnabledLayerNames); ++j) {
+ for (uint32_t i = 0; i < layerCount; ++i) {
+ if (!strncmp(layers[i].layerName, kEnabledLayerNames[j],
+ strlen(kEnabledLayerNames[j]))) {
+ ++instanceLayersFound;
+ break;
+ }
+ }
+ }
+ delete[] layers;
+
+ return instanceExtensionsFound == ARRAYSIZE(kEnabledInstanceExtensionNames) &&
+ instanceLayersFound == ARRAYSIZE(kEnabledLayerNames);
+}
+
+bool verify_device_layers(VkPhysicalDevice physDev) {
+ uint32_t layerCount;
+ VkResult res = vkEnumerateDeviceLayerProperties(physDev, &layerCount, nullptr);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+ VkLayerProperties* layers = new VkLayerProperties[layerCount];
+ res = vkEnumerateDeviceLayerProperties(physDev, &layerCount, layers);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+ int deviceLayersFound = 0;
+ for (uint32_t j = 0; j < ARRAYSIZE(kEnabledLayerNames); ++j) {
+ for (uint32_t i = 0; i < layerCount; ++i) {
+ if (!strncmp(layers[i].layerName, kEnabledLayerNames[j],
+ strlen(kEnabledLayerNames[j]))) {
+ ++deviceLayersFound;
+ break;
+ }
+ }
+ }
+ delete[] layers;
+
+ return deviceLayersFound == ARRAYSIZE(kEnabledLayerNames);
+}
+#endif
+
// For now the VkGpuCreate is using the same signature as GL. This is mostly for ease of
// hiding this code from offical skia. In the end the VkGpuCreate will not take a GrBackendContext
// and mostly likely would take an optional device and queues to use.
@@ -62,18 +180,33 @@ GrGpu* vk_gpu_create(GrBackendContext backendContext, const GrContextOptions& op
0, // applicationVersion
"vktest", // pEngineName
0, // engineVerison
- VK_API_VERSION, // apiVersion
+ kGrVkMinimumVersion, // apiVersion
};
+
+ const char** enabledLayerNames = nullptr;
+ int enabledLayerCount = 0;
+ const char** enabledInstanceExtensionNames = nullptr;
+ int enabledInstanceExtensionCount = 0;
+#ifdef ENABLE_VK_LAYERS
+ if (verify_instance_layers()) {
+ enabledLayerNames = kEnabledLayerNames;
+ enabledLayerCount = ARRAYSIZE(kEnabledLayerNames);
+ enabledInstanceExtensionNames = kEnabledInstanceExtensionNames;
+ enabledInstanceExtensionCount = ARRAYSIZE(kEnabledInstanceExtensionNames);
+ }
+#endif
+
const VkInstanceCreateInfo instance_create = {
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
nullptr, // pNext
0, // flags
&app_info, // pApplicationInfo
- 0, // enabledLayerNameCount
- nullptr, // ppEnabledLayerNames
- 0, // enabledExtensionNameCount
- nullptr, // ppEnabledExtensionNames
+ enabledLayerCount, // enabledLayerNameCount
+ enabledLayerNames, // ppEnabledLayerNames
+ enabledInstanceExtensionCount, // enabledExtensionNameCount
+ enabledInstanceExtensionNames, // ppEnabledExtensionNames
};
+
err = vkCreateInstance(&instance_create, nullptr, &inst);
if (err < 0) {
SkDebugf("vkCreateInstanced failed: %d\n", err);
@@ -116,6 +249,14 @@ GrGpu* vk_gpu_create(GrBackendContext backendContext, const GrContextOptions& op
}
SkASSERT(graphicsQueueIndex < queueCount);
+#ifdef ENABLE_VK_LAYERS
+ // unlikely that the device will have different layers than the instance, but good to check
+ if (!verify_device_layers(physDev)) {
+ enabledLayerNames = nullptr;
+ enabledLayerCount = 0;
+ }
+#endif
+
float queuePriorities[1] = { 0.0 };
const VkDeviceQueueCreateInfo queueInfo = {
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
@@ -131,8 +272,8 @@ GrGpu* vk_gpu_create(GrBackendContext backendContext, const GrContextOptions& op
0, // VkDeviceCreateFlags
1, // queueCreateInfoCount
&queueInfo, // pQueueCreateInfos
- 0, // layerCount
- nullptr, // ppEnabledLayerNames
+ enabledLayerCount, // layerCount
+ enabledLayerNames, // ppEnabledLayerNames
0, // extensionCount
nullptr, // ppEnabledExtensionNames
nullptr // ppEnabledFeatures
@@ -188,6 +329,25 @@ GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
fCurrentCmdBuffer->begin(this);
VK_CALL(GetPhysicalDeviceMemoryProperties(physDev, &fPhysDevMemProps));
+#ifdef ENABLE_VK_LAYERS
+ if (fInterface->hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
+ /* Setup callback creation information */
+ VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
+ callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
+ callbackCreateInfo.pNext = nullptr;
+ callbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT |
+ VK_DEBUG_REPORT_WARNING_BIT_EXT |
+ //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
+ //VK_DEBUG_REPORT_DEBUG_BIT_EXT |
+ VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
+ callbackCreateInfo.pfnCallback = &DebugReportCallback;
+ callbackCreateInfo.pUserData = nullptr;
+
+ /* Register the callback */
+ GR_VK_CALL_ERRCHECK(fInterface, CreateDebugReportCallbackEXT(inst, &callbackCreateInfo,
+ nullptr, &fCallback));
+ }
+#endif
}
GrVkGpu::~GrVkGpu() {
@@ -202,6 +362,10 @@ GrVkGpu::~GrVkGpu() {
// must call this just before we destroy the VkDevice
fResourceProvider.destroyResources();
+#ifdef SK_DEBUG
+ VK_CALL(DestroyDebugReportCallbackEXT(fVkInstance, fCallback, nullptr));
+#endif
+
VK_CALL(DestroyCommandPool(fDevice, fCmdPool, nullptr));
VK_CALL(DestroyDevice(fDevice, nullptr));
VK_CALL(DestroyInstance(fVkInstance, nullptr));
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 3785b15af1..c39973a4e7 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -30,6 +30,10 @@ class GrVkRenderPass;
class GrVkTexture;
struct GrVkInterface;
+#ifdef SK_DEBUG
+#define ENABLE_VK_LAYERS
+#endif
+
class GrVkGpu : public GrGpu {
public:
// Currently passing in the inst so that we can properly delete it when we are done.
@@ -218,6 +222,11 @@ private:
GrVkCommandBuffer* fCurrentCmdBuffer;
GrVkResourceProvider fResourceProvider;
+#ifdef ENABLE_VK_LAYERS
+ // For reporting validation layer errors
+ VkDebugReportCallbackEXT fCallback;
+#endif
+
// Shaderc compiler used for compiling glsl in spirv. We only want to create the compiler once
// since there is significant overhead to the first compile of any compiler.
shaderc_compiler_t fCompiler;
diff --git a/src/gpu/vk/GrVkInterface.cpp b/src/gpu/vk/GrVkInterface.cpp
index 07e85fcd5b..4b12e13f0c 100644
--- a/src/gpu/vk/GrVkInterface.cpp
+++ b/src/gpu/vk/GrVkInterface.cpp
@@ -6,14 +6,30 @@
*/
#include "vk/GrVkInterface.h"
+#include "vk/GrVkUtil.h"
GrVkInterface::GrVkInterface() {
}
#define GET_PROC(F) functions->f ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F)
+#define GET_PROC_LOCAL(inst, F) PFN_vk ## F F = (PFN_vk ## F) vkGetInstanceProcAddr(inst, "vk" #F)
const GrVkInterface* GrVkCreateInterface(VkInstance instance) {
+ GET_PROC_LOCAL(nullptr, EnumerateInstanceExtensionProperties);
+ GET_PROC_LOCAL(instance, EnumerateDeviceExtensionProperties);
+ GET_PROC_LOCAL(nullptr, EnumerateInstanceLayerProperties);
+ GET_PROC_LOCAL(instance, EnumerateDeviceLayerProperties);
+
+ GrVkExtensions extensions;
+ if (!extensions.init(kGrVkMinimumVersion,
+ EnumerateInstanceExtensionProperties,
+ EnumerateDeviceExtensionProperties,
+ EnumerateInstanceLayerProperties,
+ EnumerateDeviceLayerProperties)) {
+ return nullptr;
+ }
+
GrVkInterface* interface = new GrVkInterface();
GrVkInterface::Functions* functions = &interface->fFunctions;
@@ -152,6 +168,7 @@ const GrVkInterface* GrVkCreateInterface(VkInstance instance) {
GET_PROC(CmdNextSubpass);
GET_PROC(CmdEndRenderPass);
GET_PROC(CmdExecuteCommands);
+ // TODO: break these out with extension checks
GET_PROC(DestroySurfaceKHR);
GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
@@ -171,6 +188,14 @@ const GrVkInterface* GrVkCreateInterface(VkInstance instance) {
GET_PROC(CreateDisplayPlaneSurfaceKHR);
GET_PROC(CreateSharedSwapchainsKHR);
+ if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
+ GET_PROC(CreateDebugReportCallbackEXT);
+ GET_PROC(DebugReportMessageEXT);
+ GET_PROC(DestroyDebugReportCallbackEXT);
+ }
+
+ interface->fExtensions.swap(&extensions);
+
return interface;
}
@@ -332,7 +357,10 @@ bool GrVkInterface::validate() const {
NULL == fFunctions.fCreateDisplayModeKHR ||
NULL == fFunctions.fGetDisplayPlaneCapabilitiesKHR ||
NULL == fFunctions.fCreateDisplayPlaneSurfaceKHR ||
- NULL == fFunctions.fCreateSharedSwapchainsKHR) {
+ NULL == fFunctions.fCreateSharedSwapchainsKHR ||
+ NULL == fFunctions.fCreateDebugReportCallbackEXT ||
+ NULL == fFunctions.fDebugReportMessageEXT ||
+ NULL == fFunctions.fDestroyDebugReportCallbackEXT) {
return false;
}
return true;
diff --git a/src/gpu/vk/GrVkUtil.h b/src/gpu/vk/GrVkUtil.h
index 4fee31046d..0b760cabe2 100644
--- a/src/gpu/vk/GrVkUtil.h
+++ b/src/gpu/vk/GrVkUtil.h
@@ -14,6 +14,9 @@
#include "vulkan/vulkan.h"
+// the minimum version of Vulkan supported
+const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 3);
+
// makes a Vk call on the interface
#define GR_VK_CALL(IFACE, X) (IFACE)->fFunctions.f##X;
// same as GR_VK_CALL but checks for success