Merge "libvulkan: Support R5G6B5_UNORM_PACK16 as a swapchain format" 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 98617f4..6520e3b 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -144,7 +144,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)
@@ -613,6 +613,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");
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..6dfd7a8 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;
 }
 
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 8e2cf58..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?
@@ -345,8 +349,10 @@
              "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 --
 
@@ -416,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);
@@ -448,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.
 
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 462a8e5..9cbd234 100644
--- a/vulkan/tools/vkinfo.cpp
+++ b/vulkan/tools/vkinfo.cpp
@@ -342,7 +342,7 @@
             strbuf << "DEVICE_LOCAL";
         printf("%sHeap %u: %" PRIu64 " MiB (0x%" PRIx64 " B) %s\n",
                Indent(indent + 1), heap,
-               info.memory.memoryHeaps[heap].size / 0x1000000,
+               info.memory.memoryHeaps[heap].size / 0x100000,
                info.memory.memoryHeaps[heap].size, strbuf.str().c_str());
         strbuf.str(std::string());