libvulkan: Un-revert and fix VK_PRESENT_MODE_MAILBOX_KHR

This reverts commit 9ec497c, which was a revert of f333922, and fixes
the problem that caused the initial revert.

MODE_MAILBOX corresponds to BufferQueue "async" mode; in that mode we
need one extra un-dequeued buffer at all times. We weren't accounting
for that, and weren't allocating enough bufers.

Bug: 26918467
Change-Id: Ice67e6d16828e50413ae453ecf3c67b8fb288f1a
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index bab5a59..e1b2afa 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -346,8 +346,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 --
 
@@ -386,6 +388,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 +427,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.