Merge "Split bugreport identifier into id and pid." into nyc-dev
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index 8515a01..a4b5ff1 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -18,7 +18,7 @@
# ZipArchive support, the order matters here to get all symbols.
LOCAL_STATIC_LIBRARIES := libziparchive libz libbase libmincrypt
LOCAL_HAL_STATIC_LIBRARIES := libdumpstate
-LOCAL_CFLAGS += -Wall -Wno-unused-parameter -std=gnu99
+LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter -std=gnu99
LOCAL_INIT_RC := dumpstate.rc
include $(BUILD_EXECUTABLE)
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 6917c21..462cf7d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -145,7 +145,7 @@
mount_points.clear();
DurationReporter duration_reporter(title, NULL);
for_each_pid(do_mountinfo, NULL);
- MYLOGD("%s: %lu entries added to zip file\n", title, mount_points.size());
+ MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
}
static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
@@ -578,7 +578,7 @@
return true;
}
-static void dumpstate(const std::string& screenshot_path) {
+static void dumpstate(const std::string& screenshot_path, const std::string& version) {
DurationReporter duration_reporter("DUMPSTATE");
unsigned long timeout;
@@ -615,6 +615,7 @@
run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
+ for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
if (!screenshot_path.empty()) {
MYLOGI("taking late screenshot\n");
@@ -848,7 +849,12 @@
/* the full dumpsys is starting to take a long time, so we need
to increase its timeout. we really need to do the timeouts in
dumpsys itself... */
- run_command("DUMPSYS", 60, "dumpsys", NULL);
+ if (version == VERSION_DUMPSYS_SPLIT) {
+ // Skipping meminfo and cpuinfo services.
+ run_command("DUMPSYS", 60, "dumpsys", "--skip", "meminfo,cpuinfo", NULL);
+ } else {
+ run_command("DUMPSYS", 60, "dumpsys", NULL);
+ }
printf("========================================================\n");
printf("== Checkins\n");
@@ -1182,7 +1188,7 @@
if (do_update_progress) {
std::vector<std::string> am_args = {
- "--receiver-permission", "android.permission.DUMP",
+ "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
"--es", "android.intent.extra.NAME", suffix,
"--ei", "android.intent.extra.ID", std::to_string(id),
"--ei", "android.intent.extra.PID", std::to_string(getpid()),
@@ -1229,18 +1235,6 @@
}
}
- /* collect stack traces from Dalvik and native processes (needs root) */
- dump_traces_path = dump_traces();
-
- /* Get the tombstone fds, recovery files, and mount info here while we are running as root. */
- get_tombstone_fds(tombstone_data);
- add_dir(RECOVERY_DIR, true);
- add_mountinfo();
-
- if (!drop_root()) {
- return -1;
- }
-
if (is_redirecting) {
redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
/* TODO: rather than generating a text file now and zipping it later,
@@ -1253,7 +1247,26 @@
// duration is logged into MYLOG instead.
print_header(version);
- dumpstate(do_early_screenshot ? "": screenshot_path);
+ if (version == VERSION_DUMPSYS_SPLIT) {
+ // Invoking the following dumpsys calls before dump_traces() to try and
+ // keep the system stats as close to its initial state as possible.
+ run_command("DUMPSYS MEMINFO", 30, SU_PATH, "shell", "dumpsys", "meminfo", "-a", NULL);
+ run_command("DUMPSYS CPUINFO", 30, SU_PATH, "shell", "dumpsys", "cpuinfo", "-a", NULL);
+ }
+
+ /* collect stack traces from Dalvik and native processes (needs root) */
+ dump_traces_path = dump_traces();
+
+ /* Get the tombstone fds, recovery files, and mount info here while we are running as root. */
+ get_tombstone_fds(tombstone_data);
+ add_dir(RECOVERY_DIR, true);
+ add_mountinfo();
+
+ if (!drop_root()) {
+ return -1;
+ }
+
+ dumpstate(do_early_screenshot ? "": screenshot_path, version);
/* done */
if (vibrator) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 5a93f8c..a8aea42 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -30,15 +30,15 @@
#endif
#ifndef MYLOGD
-#define MYLOGD(fmt...) fprintf(stderr, fmt); ALOGD(fmt);
+#define MYLOGD(...) fprintf(stderr, __VA_ARGS__); ALOGD(__VA_ARGS__);
#endif
#ifndef MYLOGI
-#define MYLOGI(fmt...) fprintf(stderr, fmt); ALOGI(fmt);
+#define MYLOGI(...) fprintf(stderr, __VA_ARGS__); ALOGI(__VA_ARGS__);
#endif
#ifndef MYLOGE
-#define MYLOGE(fmt...) fprintf(stderr, fmt); ALOGE(fmt);
+#define MYLOGE(...) fprintf(stderr, __VA_ARGS__); ALOGE(__VA_ARGS__);
#endif
#include <time.h>
@@ -138,6 +138,9 @@
/* Displays a blocked processes in-kernel wait channel */
void show_wchan(int pid, int tid, const char *name);
+/* Displays a processes times */
+void show_showtime(int pid, const char *name);
+
/* Runs "showmap" for a process */
void do_showmap(int pid, const char *name);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 683091f..9d42939 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -27,6 +27,7 @@
#include <string.h>
#include <sys/inotify.h>
#include <sys/stat.h>
+#include <sys/sysconf.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/klog.h>
@@ -133,13 +134,32 @@
continue;
}
- sprintf(cmdpath,"/proc/%d/cmdline", pid);
memset(cmdline, 0, sizeof(cmdline));
- if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) < 0) {
- strcpy(cmdline, "N/A");
- } else {
- read(fd, cmdline, sizeof(cmdline) - 1);
+
+ snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid);
+ if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
+ TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2));
close(fd);
+ if (cmdline[0]) {
+ helper(pid, cmdline, arg);
+ continue;
+ }
+ }
+
+ // if no cmdline, a kernel thread has comm
+ snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid);
+ if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) {
+ TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4));
+ close(fd);
+ if (cmdline[1]) {
+ cmdline[0] = '[';
+ size_t len = strcspn(cmdline, "\f\b\r\n");
+ cmdline[len] = ']';
+ cmdline[len+1] = '\0';
+ }
+ }
+ if (!cmdline[0]) {
+ strcpy(cmdline, "N/A");
}
helper(pid, cmdline, arg);
}
@@ -191,7 +211,7 @@
strcpy(comm, "N/A");
} else {
char *c;
- read(fd, comm, sizeof(comm) - 1);
+ TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2));
close(fd);
c = strrchr(comm, '\n');
@@ -214,7 +234,7 @@
ON_DRY_RUN_RETURN();
char path[255];
char buffer[255];
- int fd;
+ int fd, ret, save_errno;
char name_buffer[255];
memset(buffer, 0, sizeof(buffer));
@@ -225,9 +245,13 @@
return;
}
- if (read(fd, buffer, sizeof(buffer)) < 0) {
- printf("Failed to read '%s' (%s)\n", path, strerror(errno));
- goto out_close;
+ ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
+ save_errno = errno;
+ close(fd);
+
+ if (ret < 0) {
+ printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
+ return;
}
snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
@@ -235,8 +259,103 @@
printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
-out_close:
+ return;
+}
+
+// print time in centiseconds
+static void snprcent(char *buffer, size_t len, size_t spc,
+ unsigned long long time) {
+ static long hz; // cache discovered hz
+
+ if (hz <= 0) {
+ hz = sysconf(_SC_CLK_TCK);
+ if (hz <= 0) {
+ hz = 1000;
+ }
+ }
+
+ // convert to centiseconds
+ time = (time * 100 + (hz / 2)) / hz;
+
+ char str[16];
+
+ snprintf(str, sizeof(str), " %llu.%02u",
+ time / 100, (unsigned)(time % 100));
+ size_t offset = strlen(buffer);
+ snprintf(buffer + offset, (len > offset) ? len - offset : 0,
+ "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
+}
+
+// print permille as a percent
+static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) {
+ char str[16];
+
+ snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10);
+ size_t offset = strlen(buffer);
+ snprintf(buffer + offset, (len > offset) ? len - offset : 0,
+ "%*s", (spc > offset) ? (int)(spc - offset) : 0, str);
+}
+
+void show_showtime(int pid, const char *name) {
+ ON_DRY_RUN_RETURN();
+ char path[255];
+ char buffer[1023];
+ int fd, ret, save_errno;
+
+ memset(buffer, 0, sizeof(buffer));
+
+ sprintf(path, "/proc/%d/stat", pid);
+ if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
+ printf("Failed to open '%s' (%s)\n", path, strerror(errno));
+ return;
+ }
+
+ ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
+ save_errno = errno;
close(fd);
+
+ if (ret < 0) {
+ printf("Failed to read '%s' (%s)\n", path, strerror(save_errno));
+ return;
+ }
+
+ // field 14 is utime
+ // field 15 is stime
+ // field 42 is iotime
+ unsigned long long utime = 0, stime = 0, iotime = 0;
+ if (sscanf(buffer,
+ "%*llu %*s %*s %*lld %*lld %*lld %*lld %*lld %*lld %*lld %*lld "
+ "%*lld %*lld %llu %llu %*lld %*lld %*lld %*lld %*lld %*lld "
+ "%*lld %*lld %*lld %*lld %*lld %*lld %*lld %*lld %*lld %*lld "
+ "%*lld %*lld %*lld %*lld %*lld %*lld %*lld %*lld %*lld %llu ",
+ &utime, &stime, &iotime) != 3) {
+ return;
+ }
+
+ unsigned long long total = utime + stime;
+ if (!total) {
+ return;
+ }
+
+ unsigned permille = (iotime * 1000 + (total / 2)) / total;
+ if (permille > 1000) {
+ permille = 1000;
+ }
+
+ // try to beautify and stabilize columns at <80 characters
+ snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name);
+ if ((name[0] != '[') || utime) {
+ snprcent(buffer, sizeof(buffer), 57, utime);
+ }
+ snprcent(buffer, sizeof(buffer), 65, stime);
+ if ((name[0] != '[') || iotime) {
+ snprcent(buffer, sizeof(buffer), 73, iotime);
+ }
+ if (iotime) {
+ snprdec(buffer, sizeof(buffer), 79, permille);
+ }
+ puts(buffer); // adds a trailing newline
+
return;
}
@@ -586,9 +705,9 @@
fprintf(stderr, "send_broadcast: too many arguments (%d)\n", (int) args.size());
return;
}
- const char *am_args[1024] = { "/system/bin/am", "broadcast",
+ const char *am_args[1024] = { SU_PATH, "shell", "/system/bin/am", "broadcast",
"--user", "0", "-a", action.c_str() };
- size_t am_index = 5; // Starts at the index of last initial value above.
+ size_t am_index = 7; // Starts at the index of last initial value above.
for (const std::string& arg : args) {
am_args[++am_index] = arg.c_str();
}
@@ -658,7 +777,7 @@
}
void create_parent_dirs(const char *path) {
- char *chp = (char*) path;
+ char *chp = const_cast<char *> (path);
/* skip initial slash */
if (chp[0] == '/')
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9d42464..136a14a 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -222,9 +222,9 @@
if (mCore->mFreeSlots.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
- auto slot = mCore->mFreeSlots.begin();
+ int slot = *(mCore->mFreeSlots.begin());
mCore->mFreeSlots.erase(slot);
- return *slot;
+ return slot;
}
status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d39075f..28e5e43 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1000,8 +1000,9 @@
// Signal our end of the sync point and then dispose of it
mRemoteSyncPoints.front()->setTransactionApplied();
mRemoteSyncPoints.pop_front();
+ } else {
+ break;
}
- break;
} else {
popPendingState();
stateUpdateAvailable = true;
@@ -1240,6 +1241,8 @@
// request without any other state updates shouldn't actually induce a delay
mCurrentState.modified = true;
pushPendingState();
+ mCurrentState.handle = nullptr;
+ mCurrentState.frameNumber = 0;
mCurrentState.modified = false;
}
diff --git a/vulkan/include/vulkan/vk_layer_interface.h b/vulkan/include/vulkan/vk_layer_interface.h
new file mode 100644
index 0000000..8aef495
--- /dev/null
+++ b/vulkan/include/vulkan/vk_layer_interface.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015-2016 The Khronos Group Inc.
+ * Copyright (c) 2015-2016 Valve Corporation
+ * Copyright (c) 2015-2016 LunarG, Inc.
+ * Copyright (c) 2016 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and/or associated documentation files (the "Materials"), to
+ * deal in the Materials without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Materials, and to permit persons to whom the Materials are
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included in
+ * all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the Khronos
+ * Membership Agreement until designated non-confidential by Khronos, at which
+ * point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
+ * USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ */
+#pragma once
+
+#include <vulkan/vulkan.h>
+#include <vulkan/vk_ext_debug_report.h>
+
+// ------------------------------------------------------------------------------------------------
+// CreateInstance and CreateDevice support structures
+
+typedef enum VkLayerFunction_ {
+ VK_LAYER_FUNCTION_LINK = 0,
+ VK_LAYER_FUNCTION_DEVICE = 1,
+ VK_LAYER_FUNCTION_INSTANCE = 2
+} VkLayerFunction;
+
+/*
+ * When creating the device chain the loader needs to pass
+ * down information about it's device structure needed at
+ * the end of the chain. Passing the data via the
+ * VkLayerInstanceInfo avoids issues with finding the
+ * exact instance being used.
+ */
+typedef struct VkLayerInstanceInfo_ {
+ void* instance_info;
+ PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
+} VkLayerInstanceInfo;
+
+typedef struct VkLayerInstanceLink_ {
+ struct VkLayerInstanceLink_* pNext;
+ PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
+} VkLayerInstanceLink;
+
+/*
+ * When creating the device chain the loader needs to pass
+ * down information about it's device structure needed at
+ * the end of the chain. Passing the data via the
+ * VkLayerDeviceInfo avoids issues with finding the
+ * exact instance being used.
+ */
+typedef struct VkLayerDeviceInfo_ {
+ void* device_info;
+ PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
+} VkLayerDeviceInfo;
+
+typedef struct {
+ VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
+ const void* pNext;
+ VkLayerFunction function;
+ union {
+ VkLayerInstanceLink* pLayerInfo;
+ VkLayerInstanceInfo instanceInfo;
+ } u;
+} VkLayerInstanceCreateInfo;
+
+typedef struct VkLayerDeviceLink_ {
+ struct VkLayerDeviceLink_* pNext;
+ PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
+ PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr;
+} VkLayerDeviceLink;
+
+typedef struct {
+ VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
+ const void* pNext;
+ VkLayerFunction function;
+ union {
+ VkLayerDeviceLink* pLayerInfo;
+ VkLayerDeviceInfo deviceInfo;
+ } u;
+} VkLayerDeviceCreateInfo;
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index a196a36..779fedf 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -20,15 +20,16 @@
-std=c99 -fvisibility=hidden -fstrict-aliasing \
-Weverything -Werror \
-Wno-padded \
+ -Wno-switch-enum \
-Wno-undef
#LOCAL_CFLAGS += -DLOG_NDEBUG=0
LOCAL_CPPFLAGS := -std=c++14 \
-fexceptions \
+ -Wno-c99-extensions \
-Wno-c++98-compat-pedantic \
-Wno-exit-time-destructors \
- -Wno-c99-extensions \
- -Wno-zero-length-array \
- -Wno-global-constructors
+ -Wno-global-constructors \
+ -Wno-zero-length-array
LOCAL_C_INCLUDES := \
frameworks/native/vulkan/include \
diff --git a/vulkan/libvulkan/debug_report.cpp b/vulkan/libvulkan/debug_report.cpp
index fea9f18..41b6040 100644
--- a/vulkan/libvulkan/debug_report.cpp
+++ b/vulkan/libvulkan/debug_report.cpp
@@ -23,11 +23,16 @@
const VkDebugReportCallbackCreateInfoEXT* create_info,
const VkAllocationCallbacks* allocator,
VkDebugReportCallbackEXT* callback) {
- VkDebugReportCallbackEXT driver_callback;
- VkResult result = GetDriverDispatch(instance).CreateDebugReportCallbackEXT(
- GetDriverInstance(instance), create_info, allocator, &driver_callback);
- if (result != VK_SUCCESS)
- return result;
+ VkDebugReportCallbackEXT driver_callback = VK_NULL_HANDLE;
+
+ if (GetDriverDispatch(instance).CreateDebugReportCallbackEXT) {
+ VkResult result =
+ GetDriverDispatch(instance).CreateDebugReportCallbackEXT(
+ GetDriverInstance(instance), create_info, allocator,
+ &driver_callback);
+ if (result != VK_SUCCESS)
+ return result;
+ }
const VkAllocationCallbacks* alloc =
allocator ? allocator : GetAllocator(instance);
@@ -35,8 +40,10 @@
alloc->pfnAllocation(alloc->pUserData, sizeof(Node), alignof(Node),
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!mem) {
- GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
- GetDriverInstance(instance), driver_callback, allocator);
+ if (GetDriverDispatch(instance).DestroyDebugReportCallbackEXT) {
+ GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
+ GetDriverInstance(instance), driver_callback, allocator);
+ }
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
@@ -61,8 +68,10 @@
prev->next = node->next;
lock.unlock();
- GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
- GetDriverInstance(instance), node->driver_callback, allocator);
+ if (GetDriverDispatch(instance).DestroyDebugReportCallbackEXT) {
+ GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
+ GetDriverInstance(instance), node->driver_callback, allocator);
+ }
const VkAllocationCallbacks* alloc =
allocator ? allocator : GetAllocator(instance);
@@ -112,9 +121,11 @@
int32_t message_code,
const char* layer_prefix,
const char* message) {
- GetDriverDispatch(instance).DebugReportMessageEXT(
- GetDriverInstance(instance), flags, object_type, object, location,
- message_code, layer_prefix, message);
+ if (GetDriverDispatch(instance).DebugReportMessageEXT) {
+ GetDriverDispatch(instance).DebugReportMessageEXT(
+ GetDriverInstance(instance), flags, object_type, object, location,
+ message_code, layer_prefix, message);
+ }
GetDebugReportCallbacks(instance).Message(flags, object_type, object,
location, message_code,
layer_prefix, message);
diff --git a/vulkan/libvulkan/dispatch.tmpl b/vulkan/libvulkan/dispatch.tmpl
index 054a235..1a584e3 100644
--- a/vulkan/libvulkan/dispatch.tmpl
+++ b/vulkan/libvulkan/dispatch.tmpl
@@ -560,6 +560,7 @@
objects */}}
{{else if eq $.Name "vkGetDeviceQueue"}}true
{{else if eq $.Name "vkAllocateCommandBuffers"}}true
+ {{else if eq $.Name "vkCreateDevice"}}true
{{/* vkDestroy for dispatchable objects needs to handle VK_NULL_HANDLE;
trying to dispatch through that would crash. */}}
diff --git a/vulkan/libvulkan/dispatch_gen.cpp b/vulkan/libvulkan/dispatch_gen.cpp
index 0d2d605..9028c3f 100644
--- a/vulkan/libvulkan/dispatch_gen.cpp
+++ b/vulkan/libvulkan/dispatch_gen.cpp
@@ -211,6 +211,7 @@
const NameProc kLoaderTopProcs[] = {
// clang-format off
{"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateCommandBuffers>(AllocateCommandBuffers_Top))},
+ {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDevice>(CreateDevice_Top))},
{"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateInstance>(CreateInstance_Top))},
{"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDevice>(DestroyDevice_Top))},
{"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyInstance>(DestroyInstance_Top))},
@@ -1401,7 +1402,7 @@
__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) {
- return GetDispatchTable(physicalDevice).CreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
+ return CreateDevice_Top(physicalDevice, pCreateInfo, pAllocator, pDevice);
}
__attribute__((visibility("default")))
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 287e69b..e77952a 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -394,6 +394,14 @@
}
}
+const char* LayerRef::GetName() {
+ return layer_->properties.layerName;
+}
+
+uint32_t LayerRef::GetSpecVersion() {
+ return layer_->properties.specVersion;
+}
+
LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {
other.layer_ = nullptr;
}
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 939f3b9..a0c142e 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -36,6 +36,7 @@
#include <hardware/hwvulkan.h>
#include <log/log.h>
#include <vulkan/vulkan_loader_data.h>
+#include <vulkan/vk_layer_interface.h>
// #define ENABLE_ALLOC_CALLSTACKS 1
#if ENABLE_ALLOC_CALLSTACKS
@@ -59,16 +60,6 @@
namespace {
-// These definitions are taken from the LunarG Vulkan Loader. They are used to
-// enforce compatability between the Loader and Layers.
-typedef void* (*PFN_vkGetProcAddr)(void* obj, const char* pName);
-
-typedef struct VkLayerLinkedListElem_ {
- PFN_vkGetProcAddr get_proc_addr;
- void* next_element;
- void* base_object;
-} VkLayerLinkedListElem;
-
// ----------------------------------------------------------------------------
// Standard-library allocator that delegates to VkAllocationCallbacks.
@@ -521,6 +512,41 @@
return VK_SUCCESS;
}
+/*
+ * This function will return the pNext pointer of any
+ * CreateInfo extensions that are not loader extensions.
+ * This is used to skip past the loader extensions prepended
+ * to the list during CreateInstance and CreateDevice.
+ */
+void* StripCreateExtensions(const void* pNext) {
+ VkLayerInstanceCreateInfo* create_info =
+ const_cast<VkLayerInstanceCreateInfo*>(
+ static_cast<const VkLayerInstanceCreateInfo*>(pNext));
+
+ while (
+ create_info &&
+ (create_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO ||
+ create_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)) {
+ create_info = const_cast<VkLayerInstanceCreateInfo*>(
+ static_cast<const VkLayerInstanceCreateInfo*>(create_info->pNext));
+ }
+
+ return create_info;
+}
+
+// Separate out cleaning up the layers and instance storage
+// to avoid code duplication in the many failure cases in
+// in CreateInstance_Top
+void TeardownInstance(
+ VkInstance vkinstance,
+ const VkAllocationCallbacks* /* allocator */) {
+ Instance& instance = GetDispatchParent(vkinstance);
+ instance.active_layers.clear();
+ const VkAllocationCallbacks* alloc = instance.alloc;
+ instance.~Instance();
+ alloc->pfnFree(alloc->pUserData, &instance);
+}
+
} // anonymous namespace
namespace vulkan {
@@ -532,9 +558,23 @@
VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info,
const VkAllocationCallbacks* allocator,
VkInstance* vkinstance) {
- Instance& instance = GetDispatchParent(*vkinstance);
VkResult result;
+ VkLayerInstanceCreateInfo* chain_info =
+ const_cast<VkLayerInstanceCreateInfo*>(
+ static_cast<const VkLayerInstanceCreateInfo*>(create_info->pNext));
+ while (
+ chain_info &&
+ !(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&
+ chain_info->function == VK_LAYER_FUNCTION_INSTANCE)) {
+ chain_info = const_cast<VkLayerInstanceCreateInfo*>(
+ static_cast<const VkLayerInstanceCreateInfo*>(chain_info->pNext));
+ }
+ ALOG_ASSERT(chain_info != nullptr, "Missing initialization chain info!");
+
+ Instance& instance = GetDispatchParent(
+ static_cast<VkInstance>(chain_info->u.instanceInfo.instance_info));
+
// Check that all enabled extensions are supported
InstanceExtensionSet enabled_extensions;
uint32_t num_driver_extensions = 0;
@@ -547,11 +587,14 @@
enabled_extensions.set(id);
continue;
}
- if (id == kKHR_surface || id == kKHR_android_surface ||
- id == kEXT_debug_report) {
+ if (id == kKHR_surface || id == kKHR_android_surface) {
enabled_extensions.set(id);
continue;
}
+ // The loader natively supports debug report.
+ if (id == kEXT_debug_report) {
+ continue;
+ }
}
bool supported = false;
for (const auto& layer : instance.active_layers) {
@@ -569,6 +612,7 @@
}
VkInstanceCreateInfo driver_create_info = *create_info;
+ driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
driver_create_info.enabledLayerCount = 0;
driver_create_info.ppEnabledLayerNames = nullptr;
driver_create_info.enabledExtensionCount = 0;
@@ -602,15 +646,14 @@
hwvulkan_dispatch_t* drv_dispatch =
reinterpret_cast<hwvulkan_dispatch_t*>(instance.drv.instance);
- if (drv_dispatch->magic == HWVULKAN_DISPATCH_MAGIC) {
- // Skip setting drv_dispatch->vtbl, since we never call through it;
- // we go through instance.drv.dispatch instead.
- } else {
+ if (drv_dispatch->magic != HWVULKAN_DISPATCH_MAGIC) {
ALOGE("invalid VkInstance dispatch magic: 0x%" PRIxPTR,
drv_dispatch->magic);
DestroyInstance_Bottom(instance.handle, allocator);
return VK_ERROR_INITIALIZATION_FAILED;
}
+ // Skip setting drv_dispatch->vtbl, since we never call through it;
+ // we go through instance.drv.dispatch instead.
if (!LoadDriverDispatchTable(instance.drv.instance,
g_hwdevice->GetInstanceProcAddr,
@@ -689,6 +732,8 @@
instance.drv.num_physical_devices = num_physical_devices;
instance.num_physical_devices = instance.drv.num_physical_devices;
+ *vkinstance = instance.handle;
+
return VK_SUCCESS;
}
@@ -832,31 +877,28 @@
const VkDeviceCreateInfo* create_info,
const VkAllocationCallbacks* allocator,
VkDevice* device_out) {
- Instance& instance = GetDispatchParent(gpu);
- VkResult result;
-
- // FIXME(jessehall): We don't have good conventions or infrastructure yet to
- // do better than just using the instance allocator and scope for
- // everything. See b/26732122.
- if (true /*!allocator*/)
- allocator = instance.alloc;
-
- void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Device),
- alignof(Device),
- VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
- if (!mem)
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- Device* device = new (mem) Device(&instance);
-
- result = ActivateAllLayers(create_info, &instance, device);
- if (result != VK_SUCCESS) {
- DestroyDevice(device);
- return result;
+ VkLayerDeviceCreateInfo* chain_info = const_cast<VkLayerDeviceCreateInfo*>(
+ static_cast<const VkLayerDeviceCreateInfo*>(create_info->pNext));
+ while (chain_info &&
+ !(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&
+ chain_info->function == VK_LAYER_FUNCTION_DEVICE)) {
+ chain_info = const_cast<VkLayerDeviceCreateInfo*>(
+ static_cast<const VkLayerDeviceCreateInfo*>(chain_info->pNext));
}
+ ALOG_ASSERT(chain_info != nullptr, "Missing initialization chain info!");
+ Instance& instance = GetDispatchParent(gpu);
size_t gpu_idx = 0;
while (instance.physical_devices[gpu_idx] != gpu)
gpu_idx++;
+ Device* device = static_cast<Device*>(chain_info->u.deviceInfo.device_info);
+ PFN_vkGetInstanceProcAddr get_instance_proc_addr =
+ chain_info->u.deviceInfo.pfnNextGetInstanceProcAddr;
+
+ VkDeviceCreateInfo driver_create_info = *create_info;
+ driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
+ driver_create_info.enabledLayerCount = 0;
+ driver_create_info.ppEnabledLayerNames = nullptr;
uint32_t num_driver_extensions = 0;
const char** driver_extensions = static_cast<const char**>(
@@ -869,6 +911,8 @@
driver_extensions[num_driver_extensions++] = name;
continue;
}
+ // Add the VK_ANDROID_native_buffer extension to the list iff
+ // the VK_KHR_swapchain extension was requested
if (id == kKHR_swapchain &&
instance.physical_device_driver_extensions
[gpu_idx][kANDROID_native_buffer]) {
@@ -887,28 +931,17 @@
"requested device extension '%s' not supported by loader, "
"driver, or any active layers",
name);
- DestroyDevice(device);
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
}
- VkDeviceCreateInfo driver_create_info = *create_info;
- driver_create_info.enabledLayerCount = 0;
- driver_create_info.ppEnabledLayerNames = nullptr;
- // TODO(jessehall): As soon as we enumerate device extensions supported by
- // the driver, we need to filter the requested extension list to those
- // supported by the driver here. Also, add the VK_ANDROID_native_buffer
- // extension to the list iff the VK_KHR_swapchain extension was requested,
- // instead of adding it unconditionally like we do now.
driver_create_info.enabledExtensionCount = num_driver_extensions;
driver_create_info.ppEnabledExtensionNames = driver_extensions;
-
VkDevice drv_device;
- result = instance.drv.dispatch.CreateDevice(gpu, &driver_create_info,
- allocator, &drv_device);
+ VkResult result = instance.drv.dispatch.CreateDevice(
+ gpu, &driver_create_info, allocator, &drv_device);
if (result != VK_SUCCESS) {
- DestroyDevice(device);
- return result;
+ return VK_ERROR_INITIALIZATION_FAILED;
}
hwvulkan_dispatch_t* drv_dispatch =
@@ -921,68 +954,15 @@
instance.drv.dispatch.GetDeviceProcAddr(drv_device,
"vkDestroyDevice"));
destroy_device(drv_device, allocator);
- DestroyDevice(device);
return VK_ERROR_INITIALIZATION_FAILED;
}
+
+ // Set dispatch table for newly created Device
+ // CreateDevice_Top will fill in the details
drv_dispatch->vtbl = &device->dispatch;
device->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
instance.drv.dispatch.GetDeviceProcAddr(drv_device,
"vkGetDeviceProcAddr"));
-
- void* base_object = static_cast<void*>(drv_device);
- void* next_object = base_object;
- VkLayerLinkedListElem* next_element;
- PFN_vkGetDeviceProcAddr next_get_proc_addr = GetDeviceProcAddr_Bottom;
- Vector<VkLayerLinkedListElem> elem_list(
- CallbackAllocator<VkLayerLinkedListElem>(instance.alloc));
- try {
- elem_list.resize(device->active_layers.size());
- } catch (std::bad_alloc&) {
- ALOGE("device creation failed: out of memory");
- PFN_vkDestroyDevice destroy_device =
- reinterpret_cast<PFN_vkDestroyDevice>(
- instance.drv.dispatch.GetDeviceProcAddr(drv_device,
- "vkDestroyDevice"));
- destroy_device(drv_device, allocator);
- DestroyDevice(device);
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
-
- for (size_t i = elem_list.size(); i > 0; i--) {
- size_t idx = i - 1;
- next_element = &elem_list[idx];
- next_element->get_proc_addr =
- reinterpret_cast<PFN_vkGetProcAddr>(next_get_proc_addr);
- next_element->base_object = base_object;
- next_element->next_element = next_object;
- next_object = static_cast<void*>(next_element);
-
- next_get_proc_addr = device->active_layers[idx].GetGetDeviceProcAddr();
- if (!next_get_proc_addr) {
- next_object = next_element->next_element;
- next_get_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
- next_element->get_proc_addr);
- }
- }
-
- // This is the magic call that initializes all the layer devices and
- // allows them to create their device_handle -> device_data mapping.
- next_get_proc_addr(static_cast<VkDevice>(next_object),
- "vkGetDeviceProcAddr");
-
- // We must create all the layer devices *before* retrieving the device
- // procaddrs, so that the layers know which extensions are enabled and
- // therefore which functions to return procaddrs for.
- PFN_vkCreateDevice create_device = reinterpret_cast<PFN_vkCreateDevice>(
- next_get_proc_addr(drv_device, "vkCreateDevice"));
- create_device(gpu, create_info, allocator, &drv_device);
-
- if (!LoadDeviceDispatchTable(static_cast<VkDevice>(base_object),
- next_get_proc_addr, device->dispatch)) {
- DestroyDevice(device);
- return VK_ERROR_INITIALIZATION_FAILED;
- }
-
*device_out = drv_device;
return VK_SUCCESS;
}
@@ -1006,25 +986,12 @@
"vkDestroyDebugReportCallbackEXT"));
destroy_debug_report_callback(vkinstance, instance.message, allocator);
}
- instance.active_layers.clear();
- const VkAllocationCallbacks* alloc = instance.alloc;
- instance.~Instance();
- alloc->pfnFree(alloc->pUserData, &instance);
}
PFN_vkVoidFunction GetDeviceProcAddr_Bottom(VkDevice vkdevice,
const char* name) {
if (strcmp(name, "vkCreateDevice") == 0) {
- // TODO(jessehall): Blegh, having this here is disgusting. The current
- // layer init process can't call through the instance dispatch table's
- // vkCreateDevice, because that goes through the instance layers rather
- // than through the device layers. So we need to be able to get the
- // vkCreateDevice pointer through the *device* layer chain.
- //
- // Because we've already created the driver device before calling
- // through the layer vkCreateDevice functions, the loader bottom proc
- // is a no-op.
- return reinterpret_cast<PFN_vkVoidFunction>(Noop);
+ return reinterpret_cast<PFN_vkVoidFunction>(CreateDevice_Bottom);
}
// VK_ANDROID_native_buffer should be hidden from applications and layers.
@@ -1118,51 +1085,97 @@
result = ActivateAllLayers(create_info, instance, instance);
if (result != VK_SUCCESS) {
DestroyInstance_Bottom(instance->handle, allocator);
+ TeardownInstance(instance->handle, allocator);
return result;
}
- void* base_object = static_cast<void*>(instance->handle);
- void* next_object = base_object;
- VkLayerLinkedListElem* next_element;
- PFN_vkGetInstanceProcAddr next_get_proc_addr = GetInstanceProcAddr_Bottom;
- Vector<VkLayerLinkedListElem> elem_list(
- CallbackAllocator<VkLayerLinkedListElem>(instance->alloc));
- try {
- elem_list.resize(instance->active_layers.size());
- } catch (std::bad_alloc&) {
- ALOGE("instance creation failed: out of memory");
- DestroyInstance_Bottom(instance->handle, allocator);
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
+ uint32_t activated_layers = 0;
+ VkLayerInstanceCreateInfo chain_info;
+ VkLayerInstanceLink* layer_instance_link_info = nullptr;
+ PFN_vkGetInstanceProcAddr next_gipa = GetInstanceProcAddr_Bottom;
+ VkInstance local_instance = nullptr;
- for (size_t i = elem_list.size(); i > 0; i--) {
- size_t idx = i - 1;
- next_element = &elem_list[idx];
- next_element->get_proc_addr =
- reinterpret_cast<PFN_vkGetProcAddr>(next_get_proc_addr);
- next_element->base_object = base_object;
- next_element->next_element = next_object;
- next_object = static_cast<void*>(next_element);
+ if (instance->active_layers.size() > 0) {
+ chain_info.u.pLayerInfo = nullptr;
+ chain_info.pNext = create_info->pNext;
+ chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
+ chain_info.function = VK_LAYER_FUNCTION_LINK;
+ local_create_info.pNext = &chain_info;
- next_get_proc_addr =
- instance->active_layers[idx].GetGetInstanceProcAddr();
- if (!next_get_proc_addr) {
- next_object = next_element->next_element;
- next_get_proc_addr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
- next_element->get_proc_addr);
+ layer_instance_link_info = static_cast<VkLayerInstanceLink*>(alloca(
+ sizeof(VkLayerInstanceLink) * instance->active_layers.size()));
+ if (!layer_instance_link_info) {
+ ALOGE("Failed to alloc Instance objects for layers");
+ DestroyInstance_Bottom(instance->handle, allocator);
+ TeardownInstance(instance->handle, allocator);
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+ /* Create instance chain of enabled layers */
+ for (auto rit = instance->active_layers.rbegin();
+ rit != instance->active_layers.rend(); ++rit) {
+ LayerRef& layer = *rit;
+ layer_instance_link_info[activated_layers].pNext =
+ chain_info.u.pLayerInfo;
+ layer_instance_link_info[activated_layers]
+ .pfnNextGetInstanceProcAddr = next_gipa;
+ chain_info.u.pLayerInfo =
+ &layer_instance_link_info[activated_layers];
+ next_gipa = layer.GetGetInstanceProcAddr();
+
+ ALOGV("Insert instance layer %s (v%u)", layer.GetName(),
+ layer.GetSpecVersion());
+
+ activated_layers++;
}
}
- // This is the magic call that initializes all the layer instances and
- // allows them to create their instance_handle -> instance_data mapping.
- next_get_proc_addr(static_cast<VkInstance>(next_object),
- "vkGetInstanceProcAddr");
-
- if (!LoadInstanceDispatchTable(static_cast<VkInstance>(base_object),
- next_get_proc_addr, instance->dispatch)) {
+ PFN_vkCreateInstance create_instance =
+ reinterpret_cast<PFN_vkCreateInstance>(
+ next_gipa(VK_NULL_HANDLE, "vkCreateInstance"));
+ if (!create_instance) {
DestroyInstance_Bottom(instance->handle, allocator);
+ TeardownInstance(instance->handle, allocator);
return VK_ERROR_INITIALIZATION_FAILED;
}
+ VkLayerInstanceCreateInfo instance_create_info;
+
+ instance_create_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
+ instance_create_info.function = VK_LAYER_FUNCTION_INSTANCE;
+
+ instance_create_info.u.instanceInfo.instance_info = instance;
+ instance_create_info.u.instanceInfo.pfnNextGetInstanceProcAddr = next_gipa;
+
+ instance_create_info.pNext = local_create_info.pNext;
+ local_create_info.pNext = &instance_create_info;
+
+ result = create_instance(&local_create_info, allocator, &local_instance);
+
+ if (result != VK_SUCCESS) {
+ DestroyInstance_Bottom(instance->handle, allocator);
+ TeardownInstance(instance->handle, allocator);
+ return result;
+ }
+
+ const InstanceDispatchTable& instance_dispatch =
+ GetDispatchTable(local_instance);
+ if (!LoadInstanceDispatchTable(
+ local_instance, next_gipa,
+ const_cast<InstanceDispatchTable&>(instance_dispatch))) {
+ ALOGV("Failed to initialize instance dispatch table");
+ PFN_vkDestroyInstance destroy_instance =
+ reinterpret_cast<PFN_vkDestroyInstance>(
+ next_gipa(VK_NULL_HANDLE, "vkDestroyInstance"));
+ if (!destroy_instance) {
+ ALOGD("Loader unable to find DestroyInstance");
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ destroy_instance(local_instance, allocator);
+ DestroyInstance_Bottom(instance->handle, allocator);
+ TeardownInstance(instance->handle, allocator);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ *instance_out = local_instance;
// Force enable callback extension if required
bool enable_callback = false;
@@ -1177,30 +1190,6 @@
}
}
- VkInstance handle = instance->handle;
- PFN_vkCreateInstance create_instance =
- reinterpret_cast<PFN_vkCreateInstance>(
- next_get_proc_addr(instance->handle, "vkCreateInstance"));
- result = create_instance(create_info, allocator, &handle);
- if (enable_callback)
- FreeAllocatedCreateInfo(local_create_info, instance->alloc);
- if (result >= 0) {
- *instance_out = instance->handle;
- } else {
- // For every layer, including the loader top and bottom layers:
- // - If a call to the next CreateInstance fails, the layer must clean
- // up anything it has successfully done so far, and propagate the
- // error upwards.
- // - If a layer successfully calls the next layer's CreateInstance, and
- // afterwards must fail for some reason, it must call the next layer's
- // DestroyInstance before returning.
- // - The layer must not call the next layer's DestroyInstance if that
- // layer's CreateInstance wasn't called, or returned failure.
-
- // On failure, CreateInstance_Bottom frees the instance struct, so it's
- // already gone at this point. Nothing to do.
- }
-
if (enable_logging) {
const VkDebugReportCallbackCreateInfoEXT callback_create_info = {
.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
@@ -1240,11 +1229,138 @@
return GetLoaderExportProcAddr(name);
}
-void DestroyInstance_Top(VkInstance instance,
+void DestroyInstance_Top(VkInstance vkinstance,
const VkAllocationCallbacks* allocator) {
- if (!instance)
+ if (!vkinstance)
return;
- GetDispatchTable(instance).DestroyInstance(instance, allocator);
+ GetDispatchTable(vkinstance).DestroyInstance(vkinstance, allocator);
+
+ TeardownInstance(vkinstance, allocator);
+}
+
+VKAPI_ATTR
+VkResult CreateDevice_Top(VkPhysicalDevice gpu,
+ const VkDeviceCreateInfo* create_info,
+ const VkAllocationCallbacks* allocator,
+ VkDevice* device_out) {
+ Instance& instance = GetDispatchParent(gpu);
+ VkResult result;
+
+ // FIXME(jessehall): We don't have good conventions or infrastructure yet to
+ // do better than just using the instance allocator and scope for
+ // everything. See b/26732122.
+ if (true /*!allocator*/)
+ allocator = instance.alloc;
+
+ void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Device),
+ alignof(Device),
+ VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
+ if (!mem)
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ Device* device = new (mem) Device(&instance);
+
+ result = ActivateAllLayers(create_info, &instance, device);
+ if (result != VK_SUCCESS) {
+ DestroyDevice(device);
+ return result;
+ }
+
+ size_t gpu_idx = 0;
+ while (instance.physical_devices[gpu_idx] != gpu)
+ gpu_idx++;
+
+ uint32_t activated_layers = 0;
+ VkLayerDeviceCreateInfo chain_info;
+ VkLayerDeviceLink* layer_device_link_info = nullptr;
+ PFN_vkGetInstanceProcAddr next_gipa = GetInstanceProcAddr_Bottom;
+ PFN_vkGetDeviceProcAddr next_gdpa = GetDeviceProcAddr_Bottom;
+ VkDeviceCreateInfo local_create_info = *create_info;
+ VkDevice local_device = nullptr;
+
+ if (device->active_layers.size() > 0) {
+ chain_info.u.pLayerInfo = nullptr;
+ chain_info.pNext = local_create_info.pNext;
+ chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
+ chain_info.function = VK_LAYER_FUNCTION_LINK;
+ local_create_info.pNext = &chain_info;
+
+ layer_device_link_info = static_cast<VkLayerDeviceLink*>(
+ alloca(sizeof(VkLayerDeviceLink) * device->active_layers.size()));
+ if (!layer_device_link_info) {
+ ALOGE("Failed to alloc Device objects for layers");
+ DestroyDevice(device);
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+ /* Create device chain of enabled layers */
+ for (auto rit = device->active_layers.rbegin();
+ rit != device->active_layers.rend(); ++rit) {
+ LayerRef& layer = *rit;
+ layer_device_link_info[activated_layers].pNext =
+ chain_info.u.pLayerInfo;
+ layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr =
+ next_gdpa;
+ layer_device_link_info[activated_layers]
+ .pfnNextGetInstanceProcAddr = next_gipa;
+ chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
+
+ next_gipa = layer.GetGetInstanceProcAddr();
+ next_gdpa = layer.GetGetDeviceProcAddr();
+
+ ALOGV("Insert device layer %s (v%u)", layer.GetName(),
+ layer.GetSpecVersion());
+
+ activated_layers++;
+ }
+ }
+
+ PFN_vkCreateDevice create_device = reinterpret_cast<PFN_vkCreateDevice>(
+ next_gipa(VK_NULL_HANDLE, "vkCreateDevice"));
+ if (!create_device) {
+ ALOGE("Unable to find vkCreateDevice for driver");
+ DestroyDevice(device);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ VkLayerDeviceCreateInfo device_create_info;
+
+ device_create_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
+ device_create_info.function = VK_LAYER_FUNCTION_DEVICE;
+
+ device_create_info.u.deviceInfo.device_info = device;
+ device_create_info.u.deviceInfo.pfnNextGetInstanceProcAddr = next_gipa;
+
+ device_create_info.pNext = local_create_info.pNext;
+ local_create_info.pNext = &device_create_info;
+
+ result = create_device(gpu, &local_create_info, allocator, &local_device);
+
+ if (result != VK_SUCCESS) {
+ DestroyDevice(device);
+ return result;
+ }
+
+ // Set dispatch table for newly created Device
+ hwvulkan_dispatch_t* vulkan_dispatch =
+ reinterpret_cast<hwvulkan_dispatch_t*>(local_device);
+ vulkan_dispatch->vtbl = &device->dispatch;
+
+ const DeviceDispatchTable& device_dispatch = GetDispatchTable(local_device);
+ if (!LoadDeviceDispatchTable(
+ local_device, next_gdpa,
+ const_cast<DeviceDispatchTable&>(device_dispatch))) {
+ ALOGV("Failed to initialize device dispatch table");
+ PFN_vkDestroyDevice destroy_device =
+ reinterpret_cast<PFN_vkDestroyDevice>(
+ next_gipa(VK_NULL_HANDLE, "vkDestroyDevice"));
+ ALOG_ASSERT(destroy_device != nullptr,
+ "Loader unable to find DestroyDevice");
+ destroy_device(local_device, allocator);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ *device_out = local_device;
+
+ return VK_SUCCESS;
}
PFN_vkVoidFunction GetDeviceProcAddr_Top(VkDevice device, const char* name) {
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index 3e2d1c4..8081c0e 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -94,6 +94,7 @@
VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr_Top(VkDevice drv_device, const char* name);
VKAPI_ATTR void GetDeviceQueue_Top(VkDevice drv_device, uint32_t family, uint32_t index, VkQueue* out_queue);
VKAPI_ATTR VkResult AllocateCommandBuffers_Top(VkDevice device, const VkCommandBufferAllocateInfo* alloc_info, VkCommandBuffer* cmdbufs);
+VKAPI_ATTR VkResult CreateDevice_Top(VkPhysicalDevice pdev, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* device_out);
VKAPI_ATTR void DestroyDevice_Top(VkDevice drv_device, const VkAllocationCallbacks* allocator);
VKAPI_ATTR VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* vkinstance);
@@ -150,6 +151,9 @@
LayerRef(const LayerRef&) = delete;
LayerRef& operator=(const LayerRef&) = delete;
+ const char* GetName();
+ uint32_t GetSpecVersion();
+
// provides bool-like behavior
operator const Layer*() const { return layer_; }
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index bab5a59..f8de675 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -238,18 +238,20 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
- capabilities->currentExtent =
- VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
-
// TODO(jessehall): Figure out what the min/max values should be.
capabilities->minImageCount = 2;
capabilities->maxImageCount = 3;
+ capabilities->currentExtent =
+ VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
+
// TODO(jessehall): Figure out what the max extent should be. Maximum
// texture dimension maybe?
capabilities->minImageExtent = VkExtent2D{1, 1};
capabilities->maxImageExtent = VkExtent2D{4096, 4096};
+ capabilities->maxImageArrayLayers = 1;
+
// TODO(jessehall): We can support all transforms, fix this once
// implemented.
capabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
@@ -257,7 +259,9 @@
// TODO(jessehall): Implement based on NATIVE_WINDOW_TRANSFORM_HINT.
capabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- capabilities->maxImageArrayLayers = 1;
+ // On Android, window composition is a WindowManager property, not something
+ // associated with the bufferqueue. It can't be changed from here.
+ capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
// TODO(jessehall): I think these are right, but haven't thought hard about
// it. Do we need to query the driver for support of any of these?
@@ -289,6 +293,7 @@
const VkSurfaceFormatKHR kFormats[] = {
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
+ {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
};
const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
@@ -338,22 +343,53 @@
"Swapchain imageArrayLayers (%u) != 1 not supported",
create_info->imageArrayLayers);
- ALOGE_IF(create_info->imageFormat != VK_FORMAT_R8G8B8A8_UNORM,
- "swapchain formats other than R8G8B8A8_UNORM not yet implemented");
ALOGE_IF(create_info->imageColorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR,
"color spaces other than SRGB_NONLINEAR not yet implemented");
ALOGE_IF(create_info->oldSwapchain,
"swapchain re-creation not yet implemented");
ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
"swapchain preTransform not yet implemented");
- ALOGE_IF(create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR,
- "present modes other than FIFO are not yet implemented");
+ ALOGW_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
+ create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
+ "swapchain present mode %d not supported",
+ create_info->presentMode);
// -- Configure the native window --
Surface& surface = *SurfaceFromHandle(create_info->surface);
const DriverDispatchTable& dispatch = GetDriverDispatch(device);
+ int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
+ switch (create_info->imageFormat) {
+ case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ native_format = HAL_PIXEL_FORMAT_RGBA_8888;
+ break;
+ case VK_FORMAT_R5G6B5_UNORM_PACK16:
+ native_format = HAL_PIXEL_FORMAT_RGB_565;
+ break;
+ default:
+ ALOGE("unsupported swapchain format %d", create_info->imageFormat);
+ break;
+ }
+ err = native_window_set_buffers_format(surface.window.get(), native_format);
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
+ native_format, strerror(-err), err);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ err = native_window_set_buffers_data_space(surface.window.get(),
+ HAL_DATASPACE_SRGB_LINEAR);
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
+ HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
err = native_window_set_buffers_dimensions(
surface.window.get(), static_cast<int>(create_info->imageExtent.width),
static_cast<int>(create_info->imageExtent.height));
@@ -386,6 +422,13 @@
ALOGE("window->query failed: %s (%d)", strerror(-err), err);
return VK_ERROR_INITIALIZATION_FAILED;
}
+ // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
+ // async mode or not, and assumes not. But in async mode, the BufferQueue
+ // requires an extra undequeued buffer.
+ // See BufferQueueCore::getMinUndequeuedBufferCountLocked().
+ if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
+ min_undequeued_buffers += 1;
+
uint32_t num_images =
(create_info->minImageCount - 1) + min_undequeued_buffers;
err = native_window_set_buffer_count(surface.window.get(), num_images);
@@ -418,6 +461,17 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
+ err = surface.window->setSwapInterval(
+ surface.window.get(),
+ create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1);
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ ALOGE("native_window->setSwapInterval failed: %s (%d)", strerror(-err),
+ err);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
// -- Allocate our Swapchain object --
// After this point, we must deallocate the swapchain on error.
@@ -442,7 +496,7 @@
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = &image_native_buffer,
.imageType = VK_IMAGE_TYPE_2D,
- .format = VK_FORMAT_R8G8B8A8_UNORM, // TODO(jessehall)
+ .format = create_info->imageFormat,
.extent = {0, 0, 1},
.mipLevels = 1,
.arrayLayers = 1,
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 8f47bd1..cd61e86 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -89,7 +89,7 @@
};
} // namespace HandleType
-const VkDeviceSize kMaxDeviceMemory = VkDeviceSize(INTPTR_MAX) + 1;
+const VkDeviceSize kMaxDeviceMemory = 0x10000000; // 256 MiB, arbitrary
} // anonymous namespace
@@ -346,6 +346,121 @@
strcpy(properties->deviceName, "Android Vulkan Null Driver");
memset(properties->pipelineCacheUUID, 0,
sizeof(properties->pipelineCacheUUID));
+ properties->limits = VkPhysicalDeviceLimits{
+ 4096, // maxImageDimension1D
+ 4096, // maxImageDimension2D
+ 256, // maxImageDimension3D
+ 4096, // maxImageDimensionCube
+ 256, // maxImageArrayLayers
+ 65536, // maxTexelBufferElements
+ 16384, // maxUniformBufferRange
+ 1 << 27, // maxStorageBufferRange
+ 128, // maxPushConstantsSize
+ 4096, // maxMemoryAllocationCount
+ 4000, // maxSamplerAllocationCount
+ 1, // bufferImageGranularity
+ 0, // sparseAddressSpaceSize
+ 4, // maxBoundDescriptorSets
+ 16, // maxPerStageDescriptorSamplers
+ 12, // maxPerStageDescriptorUniformBuffers
+ 4, // maxPerStageDescriptorStorageBuffers
+ 16, // maxPerStageDescriptorSampledImages
+ 4, // maxPerStageDescriptorStorageImages
+ 4, // maxPerStageDescriptorInputAttachments
+ 128, // maxPerStageResources
+ 96, // maxDescriptorSetSamplers
+ 72, // maxDescriptorSetUniformBuffers
+ 8, // maxDescriptorSetUniformBuffersDynamic
+ 24, // maxDescriptorSetStorageBuffers
+ 4, // maxDescriptorSetStorageBuffersDynamic
+ 96, // maxDescriptorSetSampledImages
+ 24, // maxDescriptorSetStorageImages
+ 4, // maxDescriptorSetInputAttachments
+ 16, // maxVertexInputAttributes
+ 16, // maxVertexInputBindings
+ 2047, // maxVertexInputAttributeOffset
+ 2048, // maxVertexInputBindingStride
+ 64, // maxVertexOutputComponents
+ 0, // maxTessellationGenerationLevel
+ 0, // maxTessellationPatchSize
+ 0, // maxTessellationControlPerVertexInputComponents
+ 0, // maxTessellationControlPerVertexOutputComponents
+ 0, // maxTessellationControlPerPatchOutputComponents
+ 0, // maxTessellationControlTotalOutputComponents
+ 0, // maxTessellationEvaluationInputComponents
+ 0, // maxTessellationEvaluationOutputComponents
+ 0, // maxGeometryShaderInvocations
+ 0, // maxGeometryInputComponents
+ 0, // maxGeometryOutputComponents
+ 0, // maxGeometryOutputVertices
+ 0, // maxGeometryTotalOutputComponents
+ 64, // maxFragmentInputComponents
+ 4, // maxFragmentOutputAttachments
+ 0, // maxFragmentDualSrcAttachments
+ 4, // maxFragmentCombinedOutputResources
+ 16384, // maxComputeSharedMemorySize
+ {65536, 65536, 65536}, // maxComputeWorkGroupCount[3]
+ 128, // maxComputeWorkGroupInvocations
+ {128, 128, 64}, // maxComputeWorkGroupSize[3]
+ 4, // subPixelPrecisionBits
+ 4, // subTexelPrecisionBits
+ 4, // mipmapPrecisionBits
+ UINT32_MAX, // maxDrawIndexedIndexValue
+ 1, // maxDrawIndirectCount
+ 2, // maxSamplerLodBias
+ 1, // maxSamplerAnisotropy
+ 1, // maxViewports
+ {4096, 4096}, // maxViewportDimensions[2]
+ {-8192.0f, 8191.0f}, // viewportBoundsRange[2]
+ 0, // viewportSubPixelBits
+ 64, // minMemoryMapAlignment
+ 256, // minTexelBufferOffsetAlignment
+ 256, // minUniformBufferOffsetAlignment
+ 256, // minStorageBufferOffsetAlignment
+ -8, // minTexelOffset
+ 7, // maxTexelOffset
+ 0, // minTexelGatherOffset
+ 0, // maxTexelGatherOffset
+ 0.0f, // minInterpolationOffset
+ 0.0f, // maxInterpolationOffset
+ 0, // subPixelInterpolationOffsetBits
+ 4096, // maxFramebufferWidth
+ 4096, // maxFramebufferHeight
+ 256, // maxFramebufferLayers
+ VK_SAMPLE_COUNT_1_BIT |
+ VK_SAMPLE_COUNT_4_BIT, // framebufferColorSampleCounts
+ VK_SAMPLE_COUNT_1_BIT |
+ VK_SAMPLE_COUNT_4_BIT, // framebufferDepthSampleCounts
+ VK_SAMPLE_COUNT_1_BIT |
+ VK_SAMPLE_COUNT_4_BIT, // framebufferStencilSampleCounts
+ VK_SAMPLE_COUNT_1_BIT |
+ VK_SAMPLE_COUNT_4_BIT, // framebufferNoAttachmentsSampleCounts
+ 4, // maxColorAttachments
+ VK_SAMPLE_COUNT_1_BIT |
+ VK_SAMPLE_COUNT_4_BIT, // sampledImageColorSampleCounts
+ VK_SAMPLE_COUNT_1_BIT, // sampledImageIntegerSampleCounts
+ VK_SAMPLE_COUNT_1_BIT |
+ VK_SAMPLE_COUNT_4_BIT, // sampledImageDepthSampleCounts
+ VK_SAMPLE_COUNT_1_BIT |
+ VK_SAMPLE_COUNT_4_BIT, // sampledImageStencilSampleCounts
+ VK_SAMPLE_COUNT_1_BIT, // storageImageSampleCounts
+ 1, // maxSampleMaskWords
+ VK_TRUE, // timestampComputeAndGraphics
+ 1, // timestampPeriod
+ 0, // maxClipDistances
+ 0, // maxCullDistances
+ 0, // maxCombinedClipAndCullDistances
+ 2, // discreteQueuePriorities
+ {1.0f, 1.0f}, // pointSizeRange[2]
+ {1.0f, 1.0f}, // lineWidthRange[2]
+ 0.0f, // pointSizeGranularity
+ 0.0f, // lineWidthGranularity
+ VK_TRUE, // strictLines
+ VK_TRUE, // standardSampleLocations
+ 1, // optimalBufferCopyOffsetAlignment
+ 1, // optimalBufferCopyRowPitchAlignment
+ 64, // nonCoherentAtomSize
+ };
}
void GetPhysicalDeviceQueueFamilyProperties(
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
index 6a63667..42bdb9d 100644
--- a/vulkan/tools/vkinfo.cpp
+++ b/vulkan/tools/vkinfo.cpp
@@ -161,10 +161,12 @@
}
VkDevice device;
+ float queue_priorities[] = {0.0};
const VkDeviceQueueCreateInfo queue_create_info = {
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.queueFamilyIndex = 0,
.queueCount = 1,
+ queue_priorities
};
const VkDeviceCreateInfo create_info = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
@@ -247,6 +249,25 @@
// ----------------------------------------------------------------------------
+struct Options {
+ bool layer_description;
+ bool layer_extensions;
+};
+
+const size_t kMaxIndent = 8;
+const size_t kIndentSize = 3;
+std::array<char, kMaxIndent * kIndentSize + 1> kIndent;
+const char* Indent(size_t n) {
+ static bool initialized = false;
+ if (!initialized) {
+ kIndent.fill(' ');
+ kIndent.back() = '\0';
+ initialized = true;
+ }
+ return kIndent.data() +
+ (kIndent.size() - (kIndentSize * std::min(n, kMaxIndent) + 1));
+}
+
uint32_t ExtractMajorVersion(uint32_t version) {
return (version >> 22) & 0x3FF;
}
@@ -274,51 +295,41 @@
}
}
-const char* VkQueueFlagBitStr(VkQueueFlagBits bit) {
- switch (bit) {
- case VK_QUEUE_GRAPHICS_BIT:
- return "GRAPHICS";
- case VK_QUEUE_COMPUTE_BIT:
- return "COMPUTE";
- case VK_QUEUE_TRANSFER_BIT:
- return "TRANSFER";
- case VK_QUEUE_SPARSE_BINDING_BIT:
- return "SPARSE";
- }
-}
-
void PrintExtensions(const std::vector<VkExtensionProperties>& extensions,
- const char* prefix) {
+ const Options& /*options*/,
+ size_t indent) {
for (const auto& e : extensions)
- printf("%s%s (v%u)\n", prefix, e.extensionName, e.specVersion);
+ printf("%s%s (v%u)\n", Indent(indent), e.extensionName, e.specVersion);
}
void PrintLayers(
const std::vector<VkLayerProperties>& layers,
const std::vector<std::vector<VkExtensionProperties>> extensions,
- const char* prefix) {
- std::string ext_prefix(prefix);
- ext_prefix.append(" ");
+ const Options& options,
+ size_t indent) {
for (size_t i = 0; i < layers.size(); i++) {
- printf(
- "%s%s %u.%u.%u/%u\n"
- "%s %s\n",
- prefix, layers[i].layerName,
- ExtractMajorVersion(layers[i].specVersion),
- ExtractMinorVersion(layers[i].specVersion),
- ExtractPatchVersion(layers[i].specVersion),
- layers[i].implementationVersion, prefix, layers[i].description);
- if (!extensions[i].empty())
- printf("%s Extensions [%zu]:\n", prefix, extensions[i].size());
- PrintExtensions(extensions[i], ext_prefix.c_str());
+ printf("%s%s %u.%u.%u/%u\n", Indent(indent), layers[i].layerName,
+ ExtractMajorVersion(layers[i].specVersion),
+ ExtractMinorVersion(layers[i].specVersion),
+ ExtractPatchVersion(layers[i].specVersion),
+ layers[i].implementationVersion);
+ if (options.layer_description)
+ printf("%s%s\n", Indent(indent + 1), layers[i].description);
+ if (options.layer_extensions && !extensions[i].empty()) {
+ if (!extensions[i].empty()) {
+ printf("%sExtensions [%zu]:\n", Indent(indent + 1),
+ extensions[i].size());
+ PrintExtensions(extensions[i], options, indent + 2);
+ }
+ }
}
}
-void PrintGpuInfo(const GpuInfo& info) {
+void PrintGpuInfo(const GpuInfo& info, const Options& options, size_t indent) {
VkResult result;
std::ostringstream strbuf;
- printf(" \"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n",
+ printf("%s\"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n", Indent(indent),
info.properties.deviceName,
VkPhysicalDeviceTypeStr(info.properties.deviceType),
ExtractMajorVersion(info.properties.apiVersion),
@@ -331,8 +342,9 @@
if ((info.memory.memoryHeaps[heap].flags &
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
strbuf << "DEVICE_LOCAL";
- printf(" Heap %u: %" PRIu64 " MiB (0x%" PRIx64 " B) %s\n", heap,
- info.memory.memoryHeaps[heap].size / 0x1000000,
+ printf("%sHeap %u: %" PRIu64 " MiB (0x%" PRIx64 " B) %s\n",
+ Indent(indent + 1), heap,
+ info.memory.memoryHeaps[heap].size / 0x100000,
info.memory.memoryHeaps[heap].size, strbuf.str().c_str());
strbuf.str(std::string());
@@ -351,7 +363,8 @@
strbuf << " CACHED";
if ((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
strbuf << " LAZILY_ALLOCATED";
- printf(" Type %u:%s\n", type, strbuf.str().c_str());
+ printf("%sType %u:%s\n", Indent(indent + 2), type,
+ strbuf.str().c_str());
strbuf.str(std::string());
}
}
@@ -366,47 +379,120 @@
flags_str[3] = (flags & VK_QUEUE_SPARSE_BINDING_BIT) ? 'S' : '_';
flags_str[4] = '\0';
printf(
- " Queue Family %u: %ux %s\n"
- " timestampValidBits: %ub\n"
- " minImageTransferGranularity: (%u,%u,%u)\n",
- family, qprops.queueCount, flags_str, qprops.timestampValidBits,
+ "%sQueue Family %u: %ux %s\n"
+ "%stimestampValidBits: %ub\n"
+ "%sminImageTransferGranularity: (%u,%u,%u)\n",
+ Indent(indent + 1), family, qprops.queueCount, flags_str,
+ Indent(indent + 2), qprops.timestampValidBits, Indent(indent + 2),
qprops.minImageTransferGranularity.width,
qprops.minImageTransferGranularity.height,
qprops.minImageTransferGranularity.depth);
}
- if (!info.extensions.empty()) {
- printf(" Extensions [%zu]:\n", info.extensions.size());
- PrintExtensions(info.extensions, " ");
- }
- if (!info.layers.empty()) {
- printf(" Layers [%zu]:\n", info.layers.size());
- PrintLayers(info.layers, info.layer_extensions, " ");
- }
+ // clang-format off
+ printf("%sFeatures:\n", Indent(indent + 1));
+ printf("%srobustBufferAccess: %s\n", Indent(indent + 2), info.features.robustBufferAccess ? "YES" : "NO");
+ printf("%sfullDrawIndexUint32: %s\n", Indent(indent + 2), info.features.fullDrawIndexUint32 ? "YES" : "NO");
+ printf("%simageCubeArray: %s\n", Indent(indent + 2), info.features.imageCubeArray ? "YES" : "NO");
+ printf("%sindependentBlend: %s\n", Indent(indent + 2), info.features.independentBlend ? "YES" : "NO");
+ printf("%sgeometryShader: %s\n", Indent(indent + 2), info.features.geometryShader ? "YES" : "NO");
+ printf("%stessellationShader: %s\n", Indent(indent + 2), info.features.tessellationShader ? "YES" : "NO");
+ printf("%ssampleRateShading: %s\n", Indent(indent + 2), info.features.sampleRateShading ? "YES" : "NO");
+ printf("%sdualSrcBlend: %s\n", Indent(indent + 2), info.features.dualSrcBlend ? "YES" : "NO");
+ printf("%slogicOp: %s\n", Indent(indent + 2), info.features.logicOp ? "YES" : "NO");
+ printf("%smultiDrawIndirect: %s\n", Indent(indent + 2), info.features.multiDrawIndirect ? "YES" : "NO");
+ printf("%sdrawIndirectFirstInstance: %s\n", Indent(indent + 2), info.features.drawIndirectFirstInstance ? "YES" : "NO");
+ printf("%sdepthClamp: %s\n", Indent(indent + 2), info.features.depthClamp ? "YES" : "NO");
+ printf("%sdepthBiasClamp: %s\n", Indent(indent + 2), info.features.depthBiasClamp ? "YES" : "NO");
+ printf("%sfillModeNonSolid: %s\n", Indent(indent + 2), info.features.fillModeNonSolid ? "YES" : "NO");
+ printf("%sdepthBounds: %s\n", Indent(indent + 2), info.features.depthBounds ? "YES" : "NO");
+ printf("%swideLines: %s\n", Indent(indent + 2), info.features.wideLines ? "YES" : "NO");
+ printf("%slargePoints: %s\n", Indent(indent + 2), info.features.largePoints ? "YES" : "NO");
+ printf("%salphaToOne: %s\n", Indent(indent + 2), info.features.alphaToOne ? "YES" : "NO");
+ printf("%smultiViewport: %s\n", Indent(indent + 2), info.features.multiViewport ? "YES" : "NO");
+ printf("%ssamplerAnisotropy: %s\n", Indent(indent + 2), info.features.samplerAnisotropy ? "YES" : "NO");
+ printf("%stextureCompressionETC2: %s\n", Indent(indent + 2), info.features.textureCompressionETC2 ? "YES" : "NO");
+ printf("%stextureCompressionASTC_LDR: %s\n", Indent(indent + 2), info.features.textureCompressionASTC_LDR ? "YES" : "NO");
+ printf("%stextureCompressionBC: %s\n", Indent(indent + 2), info.features.textureCompressionBC ? "YES" : "NO");
+ printf("%socclusionQueryPrecise: %s\n", Indent(indent + 2), info.features.occlusionQueryPrecise ? "YES" : "NO");
+ printf("%spipelineStatisticsQuery: %s\n", Indent(indent + 2), info.features.pipelineStatisticsQuery ? "YES" : "NO");
+ printf("%svertexPipelineStoresAndAtomics: %s\n", Indent(indent + 2), info.features.vertexPipelineStoresAndAtomics ? "YES" : "NO");
+ printf("%sfragmentStoresAndAtomics: %s\n", Indent(indent + 2), info.features.fragmentStoresAndAtomics ? "YES" : "NO");
+ printf("%sshaderTessellationAndGeometryPointSize: %s\n", Indent(indent + 2), info.features.shaderTessellationAndGeometryPointSize ? "YES" : "NO");
+ printf("%sshaderImageGatherExtended: %s\n", Indent(indent + 2), info.features.shaderImageGatherExtended ? "YES" : "NO");
+ printf("%sshaderStorageImageExtendedFormats: %s\n", Indent(indent + 2), info.features.shaderStorageImageExtendedFormats ? "YES" : "NO");
+ printf("%sshaderStorageImageMultisample: %s\n", Indent(indent + 2), info.features.shaderStorageImageMultisample ? "YES" : "NO");
+ printf("%sshaderStorageImageReadWithoutFormat: %s\n", Indent(indent + 2), info.features.shaderStorageImageReadWithoutFormat ? "YES" : "NO");
+ printf("%sshaderStorageImageWriteWithoutFormat: %s\n", Indent(indent + 2), info.features.shaderStorageImageWriteWithoutFormat ? "YES" : "NO");
+ printf("%sshaderUniformBufferArrayDynamicIndexing: %s\n", Indent(indent + 2), info.features.shaderUniformBufferArrayDynamicIndexing ? "YES" : "NO");
+ printf("%sshaderSampledImageArrayDynamicIndexing: %s\n", Indent(indent + 2), info.features.shaderSampledImageArrayDynamicIndexing ? "YES" : "NO");
+ printf("%sshaderStorageBufferArrayDynamicIndexing: %s\n", Indent(indent + 2), info.features.shaderStorageBufferArrayDynamicIndexing ? "YES" : "NO");
+ printf("%sshaderStorageImageArrayDynamicIndexing: %s\n", Indent(indent + 2), info.features.shaderStorageImageArrayDynamicIndexing ? "YES" : "NO");
+ printf("%sshaderClipDistance: %s\n", Indent(indent + 2), info.features.shaderClipDistance ? "YES" : "NO");
+ printf("%sshaderCullDistance: %s\n", Indent(indent + 2), info.features.shaderCullDistance ? "YES" : "NO");
+ printf("%sshaderFloat64: %s\n", Indent(indent + 2), info.features.shaderFloat64 ? "YES" : "NO");
+ printf("%sshaderInt64: %s\n", Indent(indent + 2), info.features.shaderInt64 ? "YES" : "NO");
+ printf("%sshaderInt16: %s\n", Indent(indent + 2), info.features.shaderInt16 ? "YES" : "NO");
+ printf("%sshaderResourceResidency: %s\n", Indent(indent + 2), info.features.shaderResourceResidency ? "YES" : "NO");
+ printf("%sshaderResourceMinLod: %s\n", Indent(indent + 2), info.features.shaderResourceMinLod ? "YES" : "NO");
+ printf("%ssparseBinding: %s\n", Indent(indent + 2), info.features.sparseBinding ? "YES" : "NO");
+ printf("%ssparseResidencyBuffer: %s\n", Indent(indent + 2), info.features.sparseResidencyBuffer ? "YES" : "NO");
+ printf("%ssparseResidencyImage2D: %s\n", Indent(indent + 2), info.features.sparseResidencyImage2D ? "YES" : "NO");
+ printf("%ssparseResidencyImage3D: %s\n", Indent(indent + 2), info.features.sparseResidencyImage3D ? "YES" : "NO");
+ printf("%ssparseResidency2Samples: %s\n", Indent(indent + 2), info.features.sparseResidency2Samples ? "YES" : "NO");
+ printf("%ssparseResidency4Samples: %s\n", Indent(indent + 2), info.features.sparseResidency4Samples ? "YES" : "NO");
+ printf("%ssparseResidency8Samples: %s\n", Indent(indent + 2), info.features.sparseResidency8Samples ? "YES" : "NO");
+ printf("%ssparseResidency16Samples: %s\n", Indent(indent + 2), info.features.sparseResidency16Samples ? "YES" : "NO");
+ printf("%ssparseResidencyAliased: %s\n", Indent(indent + 2), info.features.sparseResidencyAliased ? "YES" : "NO");
+ printf("%svariableMultisampleRate: %s\n", Indent(indent + 2), info.features.variableMultisampleRate ? "YES" : "NO");
+ printf("%sinheritedQueries: %s\n", Indent(indent + 2), info.features.inheritedQueries ? "YES" : "NO");
+ // clang-format on
+
+ printf("%sExtensions [%zu]:\n", Indent(indent + 1), info.extensions.size());
+ if (!info.extensions.empty())
+ PrintExtensions(info.extensions, options, indent + 2);
+ printf("%sLayers [%zu]:\n", Indent(indent + 1), info.layers.size());
+ if (!info.layers.empty())
+ PrintLayers(info.layers, info.layer_extensions, options, indent + 2);
}
-void PrintInfo(const VulkanInfo& info) {
+void PrintInfo(const VulkanInfo& info, const Options& options) {
std::ostringstream strbuf;
+ size_t indent = 0;
- printf("Instance Extensions [%zu]:\n", info.extensions.size());
- PrintExtensions(info.extensions, " ");
- if (!info.layers.empty()) {
- printf("Instance Layers [%zu]:\n", info.layers.size());
- PrintLayers(info.layers, info.layer_extensions, " ");
- }
+ printf("%sInstance Extensions [%zu]:\n", Indent(indent),
+ info.extensions.size());
+ PrintExtensions(info.extensions, options, indent + 1);
+ printf("%sInstance Layers [%zu]:\n", Indent(indent), info.layers.size());
+ if (!info.layers.empty())
+ PrintLayers(info.layers, info.layer_extensions, options, indent + 1);
- printf("PhysicalDevices [%zu]:\n", info.gpus.size());
+ printf("%sPhysicalDevices [%zu]:\n", Indent(indent), info.gpus.size());
for (const auto& gpu : info.gpus)
- PrintGpuInfo(gpu);
+ PrintGpuInfo(gpu, options, indent + 1);
}
} // namespace
// ----------------------------------------------------------------------------
-int main(int /*argc*/, char const* /*argv*/ []) {
+int main(int argc, char const* argv[]) {
+ Options options = {
+ .layer_description = false, .layer_extensions = false,
+ };
+ for (int argi = 1; argi < argc; argi++) {
+ if (strcmp(argv[argi], "-v") == 0) {
+ options.layer_description = true;
+ options.layer_extensions = true;
+ } else if (strcmp(argv[argi], "-layer_description") == 0) {
+ options.layer_description = true;
+ } else if (strcmp(argv[argi], "-layer_extensions") == 0) {
+ options.layer_extensions = true;
+ }
+ }
+
VulkanInfo info;
GatherInfo(&info);
- PrintInfo(info);
+ PrintInfo(info, options);
return 0;
}