GpuService: Add 'help' and 'vkjson' commands
Bug: 26620936 and 27352427
Change-Id: Id0ad5b7184ddc624eddfb292a0d86546c26fb9ea
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 1595bdf..fb6307e 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -38,6 +38,9 @@
RenderEngine/GLES11RenderEngine.cpp \
RenderEngine/GLES20RenderEngine.cpp
+LOCAL_C_INCLUDES := \
+ frameworks/native/vulkan/include \
+ external/vulkan-validation-layers/libs/vkjson
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
@@ -107,6 +110,7 @@
LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
LOCAL_CFLAGS += -std=c++14
+LOCAL_STATIC_LIBRARIES := libvkjson
LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
@@ -119,7 +123,8 @@
libbinder \
libui \
libgui \
- libpowermanager
+ libpowermanager \
+ libvulkan
LOCAL_MODULE := libsurfaceflinger
diff --git a/services/surfaceflinger/GpuService.cpp b/services/surfaceflinger/GpuService.cpp
index b20fc33..0c29971 100644
--- a/services/surfaceflinger/GpuService.cpp
+++ b/services/surfaceflinger/GpuService.cpp
@@ -17,6 +17,8 @@
#include "GpuService.h"
#include <binder/Parcel.h>
+#include <utils/String8.h>
+#include <vkjson.h>
namespace android {
@@ -53,15 +55,121 @@
// ----------------------------------------------------------------------------
+namespace {
+ status_t cmd_help(int out);
+ status_t cmd_vkjson(int out, int err);
+}
+
const char* const GpuService::SERVICE_NAME = "gpu";
GpuService::GpuService() {}
-status_t GpuService::shellCommand(int /*in*/, int /*out*/, int /*err*/,
- Vector<String16>& /*args*/)
+status_t GpuService::shellCommand(int /*in*/, int out, int err,
+ Vector<String16>& args)
{
- ALOGD("GpuService::shellCommand");
+ ALOGV("GpuService::shellCommand");
+ for (size_t i = 0, n = args.size(); i < n; i++)
+ ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).string());
+
+ if (args[0] == String16("vkjson"))
+ return cmd_vkjson(out, err);
+ else if (args[0] == String16("help"))
+ return cmd_help(out);
+
return NO_ERROR;
}
+// ----------------------------------------------------------------------------
+
+namespace {
+
+status_t cmd_help(int out) {
+ FILE* outs = fdopen(out, "w");
+ if (!outs) {
+ ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno),
+ errno);
+ return BAD_VALUE;
+ }
+ fprintf(outs,
+ "GPU Service commands:\n"
+ " vkjson dump Vulkan device capabilities as JSON\n");
+ fclose(outs);
+ return NO_ERROR;
+}
+
+VkResult vkjsonPrint(FILE* out, FILE* err) {
+ VkResult result;
+
+ const VkApplicationInfo app_info = {
+ VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr,
+ "vkjson", 1, /* app name, version */
+ "", 0, /* engine name, version */
+ VK_API_VERSION
+ };
+ const VkInstanceCreateInfo instance_info = {
+ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, nullptr,
+ 0, /* flags */
+ &app_info,
+ 0, nullptr, /* layers */
+ 0, nullptr, /* extensions */
+ };
+ VkInstance instance;
+ result = vkCreateInstance(&instance_info, nullptr, &instance);
+ if (result != VK_SUCCESS) {
+ fprintf(err, "vkCreateInstance failed: %d\n", result);
+ return result;
+ }
+
+ uint32_t ngpu = 0;
+ result = vkEnumeratePhysicalDevices(instance, &ngpu, nullptr);
+ if (result != VK_SUCCESS) {
+ fprintf(err, "vkEnumeratePhysicalDevices failed: %d\n", result);
+ return result;
+ }
+ std::vector<VkPhysicalDevice> gpus(ngpu, VK_NULL_HANDLE);
+ result = vkEnumeratePhysicalDevices(instance, &ngpu, gpus.data());
+ if (result != VK_SUCCESS) {
+ fprintf(err, "vkEnumeratePhysicalDevices failed: %d\n", result);
+ return result;
+ }
+
+ for (size_t i = 0, n = gpus.size(); i < n; i++) {
+ auto props = VkJsonGetAllProperties(gpus[i]);
+ std::string json = VkJsonAllPropertiesToJson(props);
+ fwrite(json.data(), 1, json.size(), out);
+ if (i < n - 1)
+ fputc(',', out);
+ fputc('\n', out);
+ }
+
+ vkDestroyInstance(instance, nullptr);
+
+ return VK_SUCCESS;
+}
+
+status_t cmd_vkjson(int out, int err) {
+ int errnum;
+ FILE* outs = fdopen(out, "w");
+ if (!outs) {
+ errnum = errno;
+ ALOGE("vkjson: failed to create output stream: %s", strerror(errnum));
+ return -errnum;
+ }
+ FILE* errs = fdopen(err, "w");
+ if (!errs) {
+ errnum = errno;
+ ALOGE("vkjson: failed to create error stream: %s", strerror(errnum));
+ fclose(outs);
+ return -errnum;
+ }
+ fprintf(outs, "[\n");
+ VkResult result = vkjsonPrint(outs, errs);
+ fprintf(outs, "]\n");
+ fclose(errs);
+ fclose(outs);
+ return result >= 0 ? NO_ERROR : UNKNOWN_ERROR;
+}
+
+} // anonymous namespace
+
} // namespace android