Home | History | Annotate | Download | only in libvulkan
      1 /*
      2  * Copyright 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <algorithm>
     18 
     19 #include <gui/BufferQueue.h>
     20 #include <log/log.h>
     21 #include <sync/sync.h>
     22 #include <utils/StrongPointer.h>
     23 
     24 #include "driver.h"
     25 
     26 // TODO(jessehall): Currently we don't have a good error code for when a native
     27 // window operation fails. Just returning INITIALIZATION_FAILED for now. Later
     28 // versions (post SDK 0.9) of the API/extension have a better error code.
     29 // When updating to that version, audit all error returns.
     30 namespace vulkan {
     31 namespace driver {
     32 
     33 namespace {
     34 
     35 const VkSurfaceTransformFlagsKHR kSupportedTransforms =
     36     VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR |
     37     VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
     38     VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR |
     39     VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
     40     // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
     41     // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR |
     42     // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
     43     // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR |
     44     // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR |
     45     VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
     46 
     47 VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) {
     48     // Native and Vulkan transforms are isomorphic, but are represented
     49     // differently. Vulkan transforms are built up of an optional horizontal
     50     // mirror, followed by a clockwise 0/90/180/270-degree rotation. Native
     51     // transforms are built up from a horizontal flip, vertical flip, and
     52     // 90-degree rotation, all optional but always in that order.
     53 
     54     // TODO(jessehall): For now, only support pure rotations, not
     55     // flip or flip-and-rotate, until I have more time to test them and build
     56     // sample code. As far as I know we never actually use anything besides
     57     // pure rotations anyway.
     58 
     59     switch (native) {
     60         case 0:  // 0x0
     61             return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
     62         // case NATIVE_WINDOW_TRANSFORM_FLIP_H:  // 0x1
     63         //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR;
     64         // case NATIVE_WINDOW_TRANSFORM_FLIP_V:  // 0x2
     65         //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR;
     66         case NATIVE_WINDOW_TRANSFORM_ROT_180:  // FLIP_H | FLIP_V
     67             return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
     68         case NATIVE_WINDOW_TRANSFORM_ROT_90:  // 0x4
     69             return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
     70         // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90:
     71         //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR;
     72         // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90:
     73         //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
     74         case NATIVE_WINDOW_TRANSFORM_ROT_270:  // FLIP_H | FLIP_V | ROT_90
     75             return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
     76         case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
     77         default:
     78             return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
     79     }
     80 }
     81 
     82 int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) {
     83     switch (transform) {
     84         case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
     85             return NATIVE_WINDOW_TRANSFORM_ROT_270;
     86         case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
     87             return NATIVE_WINDOW_TRANSFORM_ROT_180;
     88         case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
     89             return NATIVE_WINDOW_TRANSFORM_ROT_90;
     90         // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
     91         // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
     92         //     return NATIVE_WINDOW_TRANSFORM_FLIP_H;
     93         // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
     94         //     return NATIVE_WINDOW_TRANSFORM_FLIP_H |
     95         //            NATIVE_WINDOW_TRANSFORM_ROT_90;
     96         // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
     97         //     return NATIVE_WINDOW_TRANSFORM_FLIP_V;
     98         // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
     99         //     return NATIVE_WINDOW_TRANSFORM_FLIP_V |
    100         //            NATIVE_WINDOW_TRANSFORM_ROT_90;
    101         case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
    102         case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
    103         default:
    104             return 0;
    105     }
    106 }
    107 
    108 // ----------------------------------------------------------------------------
    109 
    110 struct Surface {
    111     android::sp<ANativeWindow> window;
    112     VkSwapchainKHR swapchain_handle;
    113 };
    114 
    115 VkSurfaceKHR HandleFromSurface(Surface* surface) {
    116     return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface));
    117 }
    118 
    119 Surface* SurfaceFromHandle(VkSurfaceKHR handle) {
    120     return reinterpret_cast<Surface*>(handle);
    121 }
    122 
    123 struct Swapchain {
    124     Swapchain(Surface& surface_, uint32_t num_images_)
    125         : surface(surface_), num_images(num_images_) {}
    126 
    127     Surface& surface;
    128     uint32_t num_images;
    129 
    130     struct Image {
    131         Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
    132         VkImage image;
    133         android::sp<ANativeWindowBuffer> buffer;
    134         // The fence is only valid when the buffer is dequeued, and should be
    135         // -1 any other time. When valid, we own the fd, and must ensure it is
    136         // closed: either by closing it explicitly when queueing the buffer,
    137         // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
    138         int dequeue_fence;
    139         bool dequeued;
    140     } images[android::BufferQueue::NUM_BUFFER_SLOTS];
    141 };
    142 
    143 VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
    144     return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
    145 }
    146 
    147 Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
    148     return reinterpret_cast<Swapchain*>(handle);
    149 }
    150 
    151 void ReleaseSwapchainImage(VkDevice device,
    152                            ANativeWindow* window,
    153                            int release_fence,
    154                            Swapchain::Image& image) {
    155     ALOG_ASSERT(release_fence == -1 || image.dequeued,
    156                 "ReleaseSwapchainImage: can't provide a release fence for "
    157                 "non-dequeued images");
    158 
    159     if (image.dequeued) {
    160         if (release_fence >= 0) {
    161             // We get here from vkQueuePresentKHR. The application is
    162             // responsible for creating an execution dependency chain from
    163             // vkAcquireNextImage (dequeue_fence) to vkQueuePresentKHR
    164             // (release_fence), so we can drop the dequeue_fence here.
    165             if (image.dequeue_fence >= 0)
    166                 close(image.dequeue_fence);
    167         } else {
    168             // We get here during swapchain destruction, or various serious
    169             // error cases e.g. when we can't create the release_fence during
    170             // vkQueuePresentKHR. In non-error cases, the dequeue_fence should
    171             // have already signalled, since the swapchain images are supposed
    172             // to be idle before the swapchain is destroyed. In error cases,
    173             // there may be rendering in flight to the image, but since we
    174             // weren't able to create a release_fence, waiting for the
    175             // dequeue_fence is about the best we can do.
    176             release_fence = image.dequeue_fence;
    177         }
    178         image.dequeue_fence = -1;
    179 
    180         if (window) {
    181             window->cancelBuffer(window, image.buffer.get(), release_fence);
    182         } else {
    183             if (release_fence >= 0) {
    184                 sync_wait(release_fence, -1 /* forever */);
    185                 close(release_fence);
    186             }
    187         }
    188 
    189         image.dequeued = false;
    190     }
    191 
    192     if (image.image) {
    193         GetData(device).driver.DestroyImage(device, image.image, nullptr);
    194         image.image = VK_NULL_HANDLE;
    195     }
    196 
    197     image.buffer.clear();
    198 }
    199 
    200 void OrphanSwapchain(VkDevice device, Swapchain* swapchain) {
    201     if (swapchain->surface.swapchain_handle != HandleFromSwapchain(swapchain))
    202         return;
    203     for (uint32_t i = 0; i < swapchain->num_images; i++) {
    204         if (!swapchain->images[i].dequeued)
    205             ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]);
    206     }
    207     swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
    208 }
    209 
    210 }  // anonymous namespace
    211 
    212 VKAPI_ATTR
    213 VkResult CreateAndroidSurfaceKHR(
    214     VkInstance instance,
    215     const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
    216     const VkAllocationCallbacks* allocator,
    217     VkSurfaceKHR* out_surface) {
    218     if (!allocator)
    219         allocator = &GetData(instance).allocator;
    220     void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
    221                                          alignof(Surface),
    222                                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    223     if (!mem)
    224         return VK_ERROR_OUT_OF_HOST_MEMORY;
    225     Surface* surface = new (mem) Surface;
    226 
    227     surface->window = pCreateInfo->window;
    228     surface->swapchain_handle = VK_NULL_HANDLE;
    229 
    230     // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
    231     int err =
    232         native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
    233     if (err != 0) {
    234         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    235         // errors and translate them to valid Vulkan result codes?
    236         ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
    237               err);
    238         surface->~Surface();
    239         allocator->pfnFree(allocator->pUserData, surface);
    240         return VK_ERROR_INITIALIZATION_FAILED;
    241     }
    242 
    243     *out_surface = HandleFromSurface(surface);
    244     return VK_SUCCESS;
    245 }
    246 
    247 VKAPI_ATTR
    248 void DestroySurfaceKHR(VkInstance instance,
    249                        VkSurfaceKHR surface_handle,
    250                        const VkAllocationCallbacks* allocator) {
    251     Surface* surface = SurfaceFromHandle(surface_handle);
    252     if (!surface)
    253         return;
    254     native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL);
    255     ALOGV_IF(surface->swapchain_handle != VK_NULL_HANDLE,
    256              "destroyed VkSurfaceKHR 0x%" PRIx64
    257              " has active VkSwapchainKHR 0x%" PRIx64,
    258              reinterpret_cast<uint64_t>(surface_handle),
    259              reinterpret_cast<uint64_t>(surface->swapchain_handle));
    260     surface->~Surface();
    261     if (!allocator)
    262         allocator = &GetData(instance).allocator;
    263     allocator->pfnFree(allocator->pUserData, surface);
    264 }
    265 
    266 VKAPI_ATTR
    267 VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
    268                                             uint32_t /*queue_family*/,
    269                                             VkSurfaceKHR /*surface*/,
    270                                             VkBool32* supported) {
    271     *supported = VK_TRUE;
    272     return VK_SUCCESS;
    273 }
    274 
    275 VKAPI_ATTR
    276 VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(
    277     VkPhysicalDevice /*pdev*/,
    278     VkSurfaceKHR surface,
    279     VkSurfaceCapabilitiesKHR* capabilities) {
    280     int err;
    281     ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
    282 
    283     int width, height;
    284     err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
    285     if (err != 0) {
    286         ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
    287               strerror(-err), err);
    288         return VK_ERROR_INITIALIZATION_FAILED;
    289     }
    290     err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
    291     if (err != 0) {
    292         ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
    293               strerror(-err), err);
    294         return VK_ERROR_INITIALIZATION_FAILED;
    295     }
    296 
    297     int transform_hint;
    298     err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
    299     if (err != 0) {
    300         ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
    301               strerror(-err), err);
    302         return VK_ERROR_INITIALIZATION_FAILED;
    303     }
    304 
    305     // TODO(jessehall): Figure out what the min/max values should be.
    306     capabilities->minImageCount = 2;
    307     capabilities->maxImageCount = 3;
    308 
    309     capabilities->currentExtent =
    310         VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
    311 
    312     // TODO(jessehall): Figure out what the max extent should be. Maximum
    313     // texture dimension maybe?
    314     capabilities->minImageExtent = VkExtent2D{1, 1};
    315     capabilities->maxImageExtent = VkExtent2D{4096, 4096};
    316 
    317     capabilities->maxImageArrayLayers = 1;
    318 
    319     capabilities->supportedTransforms = kSupportedTransforms;
    320     capabilities->currentTransform =
    321         TranslateNativeToVulkanTransform(transform_hint);
    322 
    323     // On Android, window composition is a WindowManager property, not something
    324     // associated with the bufferqueue. It can't be changed from here.
    325     capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
    326 
    327     // TODO(jessehall): I think these are right, but haven't thought hard about
    328     // it. Do we need to query the driver for support of any of these?
    329     // Currently not included:
    330     // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
    331     // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
    332     // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
    333     capabilities->supportedUsageFlags =
    334         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
    335         VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
    336         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
    337         VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
    338 
    339     return VK_SUCCESS;
    340 }
    341 
    342 VKAPI_ATTR
    343 VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/,
    344                                             VkSurfaceKHR /*surface*/,
    345                                             uint32_t* count,
    346                                             VkSurfaceFormatKHR* formats) {
    347     // TODO(jessehall): Fill out the set of supported formats. Longer term, add
    348     // a new gralloc method to query whether a (format, usage) pair is
    349     // supported, and check that for each gralloc format that corresponds to a
    350     // Vulkan format. Shorter term, just add a few more formats to the ones
    351     // hardcoded below.
    352 
    353     const VkSurfaceFormatKHR kFormats[] = {
    354         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
    355         {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
    356         {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
    357     };
    358     const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
    359 
    360     VkResult result = VK_SUCCESS;
    361     if (formats) {
    362         if (*count < kNumFormats)
    363             result = VK_INCOMPLETE;
    364         std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
    365     }
    366     *count = kNumFormats;
    367     return result;
    368 }
    369 
    370 VKAPI_ATTR
    371 VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/,
    372                                                  VkSurfaceKHR /*surface*/,
    373                                                  uint32_t* count,
    374                                                  VkPresentModeKHR* modes) {
    375     const VkPresentModeKHR kModes[] = {
    376         VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
    377     };
    378     const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
    379 
    380     VkResult result = VK_SUCCESS;
    381     if (modes) {
    382         if (*count < kNumModes)
    383             result = VK_INCOMPLETE;
    384         std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
    385     }
    386     *count = kNumModes;
    387     return result;
    388 }
    389 
    390 VKAPI_ATTR
    391 VkResult CreateSwapchainKHR(VkDevice device,
    392                             const VkSwapchainCreateInfoKHR* create_info,
    393                             const VkAllocationCallbacks* allocator,
    394                             VkSwapchainKHR* swapchain_handle) {
    395     int err;
    396     VkResult result = VK_SUCCESS;
    397 
    398     ALOGV("vkCreateSwapchainKHR: surface=0x%" PRIx64
    399           " minImageCount=%u imageFormat=%u imageColorSpace=%u"
    400           " imageExtent=%ux%u imageUsage=%#x preTransform=%u presentMode=%u"
    401           " oldSwapchain=0x%" PRIx64,
    402           reinterpret_cast<uint64_t>(create_info->surface),
    403           create_info->minImageCount, create_info->imageFormat,
    404           create_info->imageColorSpace, create_info->imageExtent.width,
    405           create_info->imageExtent.height, create_info->imageUsage,
    406           create_info->preTransform, create_info->presentMode,
    407           reinterpret_cast<uint64_t>(create_info->oldSwapchain));
    408 
    409     if (!allocator)
    410         allocator = &GetData(device).allocator;
    411 
    412     ALOGV_IF(create_info->imageArrayLayers != 1,
    413              "swapchain imageArrayLayers=%u not supported",
    414              create_info->imageArrayLayers);
    415     ALOGV_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
    416              "swapchain imageColorSpace=%u not supported",
    417              create_info->imageColorSpace);
    418     ALOGV_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
    419              "swapchain preTransform=%#x not supported",
    420              create_info->preTransform);
    421     ALOGV_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
    422                create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
    423              "swapchain presentMode=%u not supported",
    424              create_info->presentMode);
    425 
    426     Surface& surface = *SurfaceFromHandle(create_info->surface);
    427 
    428     if (surface.swapchain_handle != create_info->oldSwapchain) {
    429         ALOGV("Can't create a swapchain for VkSurfaceKHR 0x%" PRIx64
    430               " because it already has active swapchain 0x%" PRIx64
    431               " but VkSwapchainCreateInfo::oldSwapchain=0x%" PRIx64,
    432               reinterpret_cast<uint64_t>(create_info->surface),
    433               reinterpret_cast<uint64_t>(surface.swapchain_handle),
    434               reinterpret_cast<uint64_t>(create_info->oldSwapchain));
    435         return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
    436     }
    437     if (create_info->oldSwapchain != VK_NULL_HANDLE)
    438         OrphanSwapchain(device, SwapchainFromHandle(create_info->oldSwapchain));
    439 
    440     // -- Reset the native window --
    441     // The native window might have been used previously, and had its properties
    442     // changed from defaults. That will affect the answer we get for queries
    443     // like MIN_UNDEQUED_BUFFERS. Reset to a known/default state before we
    444     // attempt such queries.
    445 
    446     // The native window only allows dequeueing all buffers before any have
    447     // been queued, since after that point at least one is assumed to be in
    448     // non-FREE state at any given time. Disconnecting and re-connecting
    449     // orphans the previous buffers, getting us back to the state where we can
    450     // dequeue all buffers.
    451     err = native_window_api_disconnect(surface.window.get(),
    452                                        NATIVE_WINDOW_API_EGL);
    453     ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)",
    454              strerror(-err), err);
    455     err =
    456         native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL);
    457     ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)",
    458              strerror(-err), err);
    459 
    460     err = native_window_set_buffer_count(surface.window.get(), 0);
    461     if (err != 0) {
    462         ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
    463               strerror(-err), err);
    464         return VK_ERROR_INITIALIZATION_FAILED;
    465     }
    466 
    467     err = surface.window->setSwapInterval(surface.window.get(), 1);
    468     if (err != 0) {
    469         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    470         // errors and translate them to valid Vulkan result codes?
    471         ALOGE("native_window->setSwapInterval(1) failed: %s (%d)",
    472               strerror(-err), err);
    473         return VK_ERROR_INITIALIZATION_FAILED;
    474     }
    475 
    476     // -- Configure the native window --
    477 
    478     const auto& dispatch = GetData(device).driver;
    479 
    480     int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
    481     switch (create_info->imageFormat) {
    482         case VK_FORMAT_R8G8B8A8_UNORM:
    483         case VK_FORMAT_R8G8B8A8_SRGB:
    484             native_format = HAL_PIXEL_FORMAT_RGBA_8888;
    485             break;
    486         case VK_FORMAT_R5G6B5_UNORM_PACK16:
    487             native_format = HAL_PIXEL_FORMAT_RGB_565;
    488             break;
    489         default:
    490             ALOGV("unsupported swapchain format %d", create_info->imageFormat);
    491             break;
    492     }
    493     err = native_window_set_buffers_format(surface.window.get(), native_format);
    494     if (err != 0) {
    495         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    496         // errors and translate them to valid Vulkan result codes?
    497         ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
    498               native_format, strerror(-err), err);
    499         return VK_ERROR_INITIALIZATION_FAILED;
    500     }
    501     err = native_window_set_buffers_data_space(surface.window.get(),
    502                                                HAL_DATASPACE_SRGB_LINEAR);
    503     if (err != 0) {
    504         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    505         // errors and translate them to valid Vulkan result codes?
    506         ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
    507               HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err);
    508         return VK_ERROR_INITIALIZATION_FAILED;
    509     }
    510 
    511     err = native_window_set_buffers_dimensions(
    512         surface.window.get(), static_cast<int>(create_info->imageExtent.width),
    513         static_cast<int>(create_info->imageExtent.height));
    514     if (err != 0) {
    515         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    516         // errors and translate them to valid Vulkan result codes?
    517         ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
    518               create_info->imageExtent.width, create_info->imageExtent.height,
    519               strerror(-err), err);
    520         return VK_ERROR_INITIALIZATION_FAILED;
    521     }
    522 
    523     // VkSwapchainCreateInfo::preTransform indicates the transformation the app
    524     // applied during rendering. native_window_set_transform() expects the
    525     // inverse: the transform the app is requesting that the compositor perform
    526     // during composition. With native windows, pre-transform works by rendering
    527     // with the same transform the compositor is applying (as in Vulkan), but
    528     // then requesting the inverse transform, so that when the compositor does
    529     // it's job the two transforms cancel each other out and the compositor ends
    530     // up applying an identity transform to the app's buffer.
    531     err = native_window_set_buffers_transform(
    532         surface.window.get(),
    533         InvertTransformToNative(create_info->preTransform));
    534     if (err != 0) {
    535         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    536         // errors and translate them to valid Vulkan result codes?
    537         ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
    538               InvertTransformToNative(create_info->preTransform),
    539               strerror(-err), err);
    540         return VK_ERROR_INITIALIZATION_FAILED;
    541     }
    542 
    543     err = native_window_set_scaling_mode(
    544         surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
    545     if (err != 0) {
    546         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    547         // errors and translate them to valid Vulkan result codes?
    548         ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
    549               strerror(-err), err);
    550         return VK_ERROR_INITIALIZATION_FAILED;
    551     }
    552 
    553     int query_value;
    554     err = surface.window->query(surface.window.get(),
    555                                 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
    556                                 &query_value);
    557     if (err != 0 || query_value < 0) {
    558         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    559         // errors and translate them to valid Vulkan result codes?
    560         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
    561               query_value);
    562         return VK_ERROR_INITIALIZATION_FAILED;
    563     }
    564     uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
    565     // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
    566     // async mode or not, and assumes not. But in async mode, the BufferQueue
    567     // requires an extra undequeued buffer.
    568     // See BufferQueueCore::getMinUndequeuedBufferCountLocked().
    569     if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
    570         min_undequeued_buffers += 1;
    571 
    572     uint32_t num_images =
    573         (create_info->minImageCount - 1) + min_undequeued_buffers;
    574     err = native_window_set_buffer_count(surface.window.get(), num_images);
    575     if (err != 0) {
    576         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    577         // errors and translate them to valid Vulkan result codes?
    578         ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
    579               strerror(-err), err);
    580         return VK_ERROR_INITIALIZATION_FAILED;
    581     }
    582 
    583     int gralloc_usage = 0;
    584     // TODO(jessehall): Remove conditional once all drivers have been updated
    585     if (dispatch.GetSwapchainGrallocUsageANDROID) {
    586         result = dispatch.GetSwapchainGrallocUsageANDROID(
    587             device, create_info->imageFormat, create_info->imageUsage,
    588             &gralloc_usage);
    589         if (result != VK_SUCCESS) {
    590             ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
    591             return VK_ERROR_INITIALIZATION_FAILED;
    592         }
    593     } else {
    594         gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
    595     }
    596     err = native_window_set_usage(surface.window.get(), gralloc_usage);
    597     if (err != 0) {
    598         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    599         // errors and translate them to valid Vulkan result codes?
    600         ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
    601         return VK_ERROR_INITIALIZATION_FAILED;
    602     }
    603 
    604     int swap_interval =
    605         create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
    606     err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
    607     if (err != 0) {
    608         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    609         // errors and translate them to valid Vulkan result codes?
    610         ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)",
    611               swap_interval, strerror(-err), err);
    612         return VK_ERROR_INITIALIZATION_FAILED;
    613     }
    614 
    615     // -- Allocate our Swapchain object --
    616     // After this point, we must deallocate the swapchain on error.
    617 
    618     void* mem = allocator->pfnAllocation(allocator->pUserData,
    619                                          sizeof(Swapchain), alignof(Swapchain),
    620                                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    621     if (!mem)
    622         return VK_ERROR_OUT_OF_HOST_MEMORY;
    623     Swapchain* swapchain = new (mem) Swapchain(surface, num_images);
    624 
    625     // -- Dequeue all buffers and create a VkImage for each --
    626     // Any failures during or after this must cancel the dequeued buffers.
    627 
    628     VkNativeBufferANDROID image_native_buffer = {
    629 #pragma clang diagnostic push
    630 #pragma clang diagnostic ignored "-Wold-style-cast"
    631         .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
    632 #pragma clang diagnostic pop
    633         .pNext = nullptr,
    634     };
    635     VkImageCreateInfo image_create = {
    636         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
    637         .pNext = &image_native_buffer,
    638         .imageType = VK_IMAGE_TYPE_2D,
    639         .format = create_info->imageFormat,
    640         .extent = {0, 0, 1},
    641         .mipLevels = 1,
    642         .arrayLayers = 1,
    643         .samples = VK_SAMPLE_COUNT_1_BIT,
    644         .tiling = VK_IMAGE_TILING_OPTIMAL,
    645         .usage = create_info->imageUsage,
    646         .flags = 0,
    647         .sharingMode = create_info->imageSharingMode,
    648         .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
    649         .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
    650     };
    651 
    652     for (uint32_t i = 0; i < num_images; i++) {
    653         Swapchain::Image& img = swapchain->images[i];
    654 
    655         ANativeWindowBuffer* buffer;
    656         err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
    657                                             &img.dequeue_fence);
    658         if (err != 0) {
    659             // TODO(jessehall): Improve error reporting. Can we enumerate
    660             // possible errors and translate them to valid Vulkan result codes?
    661             ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
    662             result = VK_ERROR_INITIALIZATION_FAILED;
    663             break;
    664         }
    665         img.buffer = buffer;
    666         img.dequeued = true;
    667 
    668         image_create.extent =
    669             VkExtent3D{static_cast<uint32_t>(img.buffer->width),
    670                        static_cast<uint32_t>(img.buffer->height),
    671                        1};
    672         image_native_buffer.handle = img.buffer->handle;
    673         image_native_buffer.stride = img.buffer->stride;
    674         image_native_buffer.format = img.buffer->format;
    675         image_native_buffer.usage = img.buffer->usage;
    676 
    677         result =
    678             dispatch.CreateImage(device, &image_create, nullptr, &img.image);
    679         if (result != VK_SUCCESS) {
    680             ALOGD("vkCreateImage w/ native buffer failed: %u", result);
    681             break;
    682         }
    683     }
    684 
    685     // -- Cancel all buffers, returning them to the queue --
    686     // If an error occurred before, also destroy the VkImage and release the
    687     // buffer reference. Otherwise, we retain a strong reference to the buffer.
    688     //
    689     // TODO(jessehall): The error path here is the same as DestroySwapchain,
    690     // but not the non-error path. Should refactor/unify.
    691     for (uint32_t i = 0; i < num_images; i++) {
    692         Swapchain::Image& img = swapchain->images[i];
    693         if (img.dequeued) {
    694             surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
    695                                          img.dequeue_fence);
    696             img.dequeue_fence = -1;
    697             img.dequeued = false;
    698         }
    699         if (result != VK_SUCCESS) {
    700             if (img.image)
    701                 dispatch.DestroyImage(device, img.image, nullptr);
    702         }
    703     }
    704 
    705     if (result != VK_SUCCESS) {
    706         swapchain->~Swapchain();
    707         allocator->pfnFree(allocator->pUserData, swapchain);
    708         return result;
    709     }
    710 
    711     surface.swapchain_handle = HandleFromSwapchain(swapchain);
    712     *swapchain_handle = surface.swapchain_handle;
    713     return VK_SUCCESS;
    714 }
    715 
    716 VKAPI_ATTR
    717 void DestroySwapchainKHR(VkDevice device,
    718                          VkSwapchainKHR swapchain_handle,
    719                          const VkAllocationCallbacks* allocator) {
    720     const auto& dispatch = GetData(device).driver;
    721     Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
    722     bool active = swapchain->surface.swapchain_handle == swapchain_handle;
    723     ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr;
    724 
    725     for (uint32_t i = 0; i < swapchain->num_images; i++)
    726         ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
    727     if (active)
    728         swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
    729     if (!allocator)
    730         allocator = &GetData(device).allocator;
    731     swapchain->~Swapchain();
    732     allocator->pfnFree(allocator->pUserData, swapchain);
    733 }
    734 
    735 VKAPI_ATTR
    736 VkResult GetSwapchainImagesKHR(VkDevice,
    737                                VkSwapchainKHR swapchain_handle,
    738                                uint32_t* count,
    739                                VkImage* images) {
    740     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
    741     ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle,
    742              "getting images for non-active swapchain 0x%" PRIx64
    743              "; only dequeued image handles are valid",
    744              reinterpret_cast<uint64_t>(swapchain_handle));
    745     VkResult result = VK_SUCCESS;
    746     if (images) {
    747         uint32_t n = swapchain.num_images;
    748         if (*count < swapchain.num_images) {
    749             n = *count;
    750             result = VK_INCOMPLETE;
    751         }
    752         for (uint32_t i = 0; i < n; i++)
    753             images[i] = swapchain.images[i].image;
    754     }
    755     *count = swapchain.num_images;
    756     return result;
    757 }
    758 
    759 VKAPI_ATTR
    760 VkResult AcquireNextImageKHR(VkDevice device,
    761                              VkSwapchainKHR swapchain_handle,
    762                              uint64_t timeout,
    763                              VkSemaphore semaphore,
    764                              VkFence vk_fence,
    765                              uint32_t* image_index) {
    766     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
    767     ANativeWindow* window = swapchain.surface.window.get();
    768     VkResult result;
    769     int err;
    770 
    771     if (swapchain.surface.swapchain_handle != swapchain_handle)
    772         return VK_ERROR_OUT_OF_DATE_KHR;
    773 
    774     ALOGW_IF(
    775         timeout != UINT64_MAX,
    776         "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
    777 
    778     ANativeWindowBuffer* buffer;
    779     int fence_fd;
    780     err = window->dequeueBuffer(window, &buffer, &fence_fd);
    781     if (err != 0) {
    782         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    783         // errors and translate them to valid Vulkan result codes?
    784         ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
    785         return VK_ERROR_INITIALIZATION_FAILED;
    786     }
    787 
    788     uint32_t idx;
    789     for (idx = 0; idx < swapchain.num_images; idx++) {
    790         if (swapchain.images[idx].buffer.get() == buffer) {
    791             swapchain.images[idx].dequeued = true;
    792             swapchain.images[idx].dequeue_fence = fence_fd;
    793             break;
    794         }
    795     }
    796     if (idx == swapchain.num_images) {
    797         ALOGE("dequeueBuffer returned unrecognized buffer");
    798         window->cancelBuffer(window, buffer, fence_fd);
    799         return VK_ERROR_OUT_OF_DATE_KHR;
    800     }
    801 
    802     int fence_clone = -1;
    803     if (fence_fd != -1) {
    804         fence_clone = dup(fence_fd);
    805         if (fence_clone == -1) {
    806             ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
    807                   strerror(errno), errno);
    808             sync_wait(fence_fd, -1 /* forever */);
    809         }
    810     }
    811 
    812     result = GetData(device).driver.AcquireImageANDROID(
    813         device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
    814     if (result != VK_SUCCESS) {
    815         // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
    816         // even if the call fails. We could close it ourselves on failure, but
    817         // that would create a race condition if the driver closes it on a
    818         // failure path: some other thread might create an fd with the same
    819         // number between the time the driver closes it and the time we close
    820         // it. We must assume one of: the driver *always* closes it even on
    821         // failure, or *never* closes it on failure.
    822         window->cancelBuffer(window, buffer, fence_fd);
    823         swapchain.images[idx].dequeued = false;
    824         swapchain.images[idx].dequeue_fence = -1;
    825         return result;
    826     }
    827 
    828     *image_index = idx;
    829     return VK_SUCCESS;
    830 }
    831 
    832 static VkResult WorstPresentResult(VkResult a, VkResult b) {
    833     // See the error ranking for vkQueuePresentKHR at the end of section 29.6
    834     // (in spec version 1.0.14).
    835     static const VkResult kWorstToBest[] = {
    836         VK_ERROR_DEVICE_LOST,
    837         VK_ERROR_SURFACE_LOST_KHR,
    838         VK_ERROR_OUT_OF_DATE_KHR,
    839         VK_ERROR_OUT_OF_DEVICE_MEMORY,
    840         VK_ERROR_OUT_OF_HOST_MEMORY,
    841         VK_SUBOPTIMAL_KHR,
    842     };
    843     for (auto result : kWorstToBest) {
    844         if (a == result || b == result)
    845             return result;
    846     }
    847     ALOG_ASSERT(a == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", a);
    848     ALOG_ASSERT(b == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", b);
    849     return a != VK_SUCCESS ? a : b;
    850 }
    851 
    852 VKAPI_ATTR
    853 VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
    854     ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
    855              "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
    856              present_info->sType);
    857     ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
    858 
    859     VkDevice device = GetData(queue).driver_device;
    860     const auto& dispatch = GetData(queue).driver;
    861     VkResult final_result = VK_SUCCESS;
    862 
    863     for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
    864         Swapchain& swapchain =
    865             *SwapchainFromHandle(present_info->pSwapchains[sc]);
    866         uint32_t image_idx = present_info->pImageIndices[sc];
    867         Swapchain::Image& img = swapchain.images[image_idx];
    868         VkResult swapchain_result = VK_SUCCESS;
    869         VkResult result;
    870         int err;
    871 
    872         int fence = -1;
    873         result = dispatch.QueueSignalReleaseImageANDROID(
    874             queue, present_info->waitSemaphoreCount,
    875             present_info->pWaitSemaphores, img.image, &fence);
    876         if (result != VK_SUCCESS) {
    877             ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
    878             swapchain_result = result;
    879         }
    880 
    881         if (swapchain.surface.swapchain_handle ==
    882             present_info->pSwapchains[sc]) {
    883             ANativeWindow* window = swapchain.surface.window.get();
    884             if (swapchain_result == VK_SUCCESS) {
    885                 err = window->queueBuffer(window, img.buffer.get(), fence);
    886                 // queueBuffer always closes fence, even on error
    887                 if (err != 0) {
    888                     // TODO(jessehall): What now? We should probably cancel the
    889                     // buffer, I guess?
    890                     ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
    891                     swapchain_result = WorstPresentResult(
    892                         swapchain_result, VK_ERROR_OUT_OF_DATE_KHR);
    893                 }
    894                 if (img.dequeue_fence >= 0) {
    895                     close(img.dequeue_fence);
    896                     img.dequeue_fence = -1;
    897                 }
    898                 img.dequeued = false;
    899             }
    900             if (swapchain_result != VK_SUCCESS) {
    901                 ReleaseSwapchainImage(device, window, fence, img);
    902                 OrphanSwapchain(device, &swapchain);
    903             }
    904         } else {
    905             ReleaseSwapchainImage(device, nullptr, fence, img);
    906             swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
    907         }
    908 
    909         if (present_info->pResults)
    910             present_info->pResults[sc] = swapchain_result;
    911 
    912         if (swapchain_result != final_result)
    913             final_result = WorstPresentResult(final_result, swapchain_result);
    914     }
    915 
    916     return final_result;
    917 }
    918 
    919 }  // namespace driver
    920 }  // namespace vulkan
    921