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 <grallocusage/GrallocUsageConversion.h>
     20 #include <log/log.h>
     21 #include <ui/BufferQueueDefs.h>
     22 #include <sync/sync.h>
     23 #include <utils/StrongPointer.h>
     24 #include <utils/Vector.h>
     25 #include <system/window.h>
     26 
     27 #include "driver.h"
     28 
     29 // TODO(jessehall): Currently we don't have a good error code for when a native
     30 // window operation fails. Just returning INITIALIZATION_FAILED for now. Later
     31 // versions (post SDK 0.9) of the API/extension have a better error code.
     32 // When updating to that version, audit all error returns.
     33 namespace vulkan {
     34 namespace driver {
     35 
     36 namespace {
     37 
     38 const VkSurfaceTransformFlagsKHR kSupportedTransforms =
     39     VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR |
     40     VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
     41     VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR |
     42     VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
     43     // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
     44     // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR |
     45     // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
     46     // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR |
     47     // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR |
     48     VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
     49 
     50 VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) {
     51     // Native and Vulkan transforms are isomorphic, but are represented
     52     // differently. Vulkan transforms are built up of an optional horizontal
     53     // mirror, followed by a clockwise 0/90/180/270-degree rotation. Native
     54     // transforms are built up from a horizontal flip, vertical flip, and
     55     // 90-degree rotation, all optional but always in that order.
     56 
     57     // TODO(jessehall): For now, only support pure rotations, not
     58     // flip or flip-and-rotate, until I have more time to test them and build
     59     // sample code. As far as I know we never actually use anything besides
     60     // pure rotations anyway.
     61 
     62     switch (native) {
     63         case 0:  // 0x0
     64             return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
     65         // case NATIVE_WINDOW_TRANSFORM_FLIP_H:  // 0x1
     66         //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR;
     67         // case NATIVE_WINDOW_TRANSFORM_FLIP_V:  // 0x2
     68         //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR;
     69         case NATIVE_WINDOW_TRANSFORM_ROT_180:  // FLIP_H | FLIP_V
     70             return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
     71         case NATIVE_WINDOW_TRANSFORM_ROT_90:  // 0x4
     72             return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
     73         // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90:
     74         //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR;
     75         // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90:
     76         //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
     77         case NATIVE_WINDOW_TRANSFORM_ROT_270:  // FLIP_H | FLIP_V | ROT_90
     78             return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
     79         case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
     80         default:
     81             return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
     82     }
     83 }
     84 
     85 int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) {
     86     switch (transform) {
     87         case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
     88             return NATIVE_WINDOW_TRANSFORM_ROT_270;
     89         case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
     90             return NATIVE_WINDOW_TRANSFORM_ROT_180;
     91         case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
     92             return NATIVE_WINDOW_TRANSFORM_ROT_90;
     93         // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
     94         // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
     95         //     return NATIVE_WINDOW_TRANSFORM_FLIP_H;
     96         // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
     97         //     return NATIVE_WINDOW_TRANSFORM_FLIP_H |
     98         //            NATIVE_WINDOW_TRANSFORM_ROT_90;
     99         // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
    100         //     return NATIVE_WINDOW_TRANSFORM_FLIP_V;
    101         // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
    102         //     return NATIVE_WINDOW_TRANSFORM_FLIP_V |
    103         //            NATIVE_WINDOW_TRANSFORM_ROT_90;
    104         case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
    105         case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
    106         default:
    107             return 0;
    108     }
    109 }
    110 
    111 class TimingInfo {
    112    public:
    113     TimingInfo() = default;
    114     TimingInfo(const VkPresentTimeGOOGLE* qp, uint64_t nativeFrameId)
    115         : vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0},
    116           native_frame_id_(nativeFrameId) {}
    117     bool ready() const {
    118         return (timestamp_desired_present_time_ !=
    119                         NATIVE_WINDOW_TIMESTAMP_PENDING &&
    120                 timestamp_actual_present_time_ !=
    121                         NATIVE_WINDOW_TIMESTAMP_PENDING &&
    122                 timestamp_render_complete_time_ !=
    123                         NATIVE_WINDOW_TIMESTAMP_PENDING &&
    124                 timestamp_composition_latch_time_ !=
    125                         NATIVE_WINDOW_TIMESTAMP_PENDING);
    126     }
    127     void calculate(int64_t rdur) {
    128         bool anyTimestampInvalid =
    129                 (timestamp_actual_present_time_ ==
    130                         NATIVE_WINDOW_TIMESTAMP_INVALID) ||
    131                 (timestamp_render_complete_time_ ==
    132                         NATIVE_WINDOW_TIMESTAMP_INVALID) ||
    133                 (timestamp_composition_latch_time_ ==
    134                         NATIVE_WINDOW_TIMESTAMP_INVALID);
    135         if (anyTimestampInvalid) {
    136             ALOGE("Unexpectedly received invalid timestamp.");
    137             vals_.actualPresentTime = 0;
    138             vals_.earliestPresentTime = 0;
    139             vals_.presentMargin = 0;
    140             return;
    141         }
    142 
    143         vals_.actualPresentTime =
    144                 static_cast<uint64_t>(timestamp_actual_present_time_);
    145         int64_t margin = (timestamp_composition_latch_time_ -
    146                            timestamp_render_complete_time_);
    147         // Calculate vals_.earliestPresentTime, and potentially adjust
    148         // vals_.presentMargin.  The initial value of vals_.earliestPresentTime
    149         // is vals_.actualPresentTime.  If we can subtract rdur (the duration
    150         // of a refresh cycle) from vals_.earliestPresentTime (and also from
    151         // vals_.presentMargin) and still leave a positive margin, then we can
    152         // report to the application that it could have presented earlier than
    153         // it did (per the extension specification).  If for some reason, we
    154         // can do this subtraction repeatedly, we do, since
    155         // vals_.earliestPresentTime really is supposed to be the "earliest".
    156         int64_t early_time = timestamp_actual_present_time_;
    157         while ((margin > rdur) &&
    158                ((early_time - rdur) > timestamp_composition_latch_time_)) {
    159             early_time -= rdur;
    160             margin -= rdur;
    161         }
    162         vals_.earliestPresentTime = static_cast<uint64_t>(early_time);
    163         vals_.presentMargin = static_cast<uint64_t>(margin);
    164     }
    165     void get_values(VkPastPresentationTimingGOOGLE* values) const {
    166         *values = vals_;
    167     }
    168 
    169    public:
    170     VkPastPresentationTimingGOOGLE vals_ { 0, 0, 0, 0, 0 };
    171 
    172     uint64_t native_frame_id_ { 0 };
    173     int64_t timestamp_desired_present_time_{ NATIVE_WINDOW_TIMESTAMP_PENDING };
    174     int64_t timestamp_actual_present_time_ { NATIVE_WINDOW_TIMESTAMP_PENDING };
    175     int64_t timestamp_render_complete_time_ { NATIVE_WINDOW_TIMESTAMP_PENDING };
    176     int64_t timestamp_composition_latch_time_
    177             { NATIVE_WINDOW_TIMESTAMP_PENDING };
    178 };
    179 
    180 // ----------------------------------------------------------------------------
    181 
    182 struct Surface {
    183     android::sp<ANativeWindow> window;
    184     VkSwapchainKHR swapchain_handle;
    185 };
    186 
    187 VkSurfaceKHR HandleFromSurface(Surface* surface) {
    188     return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface));
    189 }
    190 
    191 Surface* SurfaceFromHandle(VkSurfaceKHR handle) {
    192     return reinterpret_cast<Surface*>(handle);
    193 }
    194 
    195 // Maximum number of TimingInfo structs to keep per swapchain:
    196 enum { MAX_TIMING_INFOS = 10 };
    197 // Minimum number of frames to look for in the past (so we don't cause
    198 // syncronous requests to Surface Flinger):
    199 enum { MIN_NUM_FRAMES_AGO = 5 };
    200 
    201 struct Swapchain {
    202     Swapchain(Surface& surface_,
    203               uint32_t num_images_,
    204               VkPresentModeKHR present_mode)
    205         : surface(surface_),
    206           num_images(num_images_),
    207           mailbox_mode(present_mode == VK_PRESENT_MODE_MAILBOX_KHR),
    208           frame_timestamps_enabled(false),
    209           shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
    210                  present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
    211         ANativeWindow* window = surface.window.get();
    212         native_window_get_refresh_cycle_duration(
    213             window,
    214             &refresh_duration);
    215     }
    216 
    217     Surface& surface;
    218     uint32_t num_images;
    219     bool mailbox_mode;
    220     bool frame_timestamps_enabled;
    221     int64_t refresh_duration;
    222     bool shared;
    223 
    224     struct Image {
    225         Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
    226         VkImage image;
    227         android::sp<ANativeWindowBuffer> buffer;
    228         // The fence is only valid when the buffer is dequeued, and should be
    229         // -1 any other time. When valid, we own the fd, and must ensure it is
    230         // closed: either by closing it explicitly when queueing the buffer,
    231         // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
    232         int dequeue_fence;
    233         bool dequeued;
    234     } images[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
    235 
    236     android::Vector<TimingInfo> timing;
    237 };
    238 
    239 VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
    240     return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
    241 }
    242 
    243 Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
    244     return reinterpret_cast<Swapchain*>(handle);
    245 }
    246 
    247 void ReleaseSwapchainImage(VkDevice device,
    248                            ANativeWindow* window,
    249                            int release_fence,
    250                            Swapchain::Image& image) {
    251     ALOG_ASSERT(release_fence == -1 || image.dequeued,
    252                 "ReleaseSwapchainImage: can't provide a release fence for "
    253                 "non-dequeued images");
    254 
    255     if (image.dequeued) {
    256         if (release_fence >= 0) {
    257             // We get here from vkQueuePresentKHR. The application is
    258             // responsible for creating an execution dependency chain from
    259             // vkAcquireNextImage (dequeue_fence) to vkQueuePresentKHR
    260             // (release_fence), so we can drop the dequeue_fence here.
    261             if (image.dequeue_fence >= 0)
    262                 close(image.dequeue_fence);
    263         } else {
    264             // We get here during swapchain destruction, or various serious
    265             // error cases e.g. when we can't create the release_fence during
    266             // vkQueuePresentKHR. In non-error cases, the dequeue_fence should
    267             // have already signalled, since the swapchain images are supposed
    268             // to be idle before the swapchain is destroyed. In error cases,
    269             // there may be rendering in flight to the image, but since we
    270             // weren't able to create a release_fence, waiting for the
    271             // dequeue_fence is about the best we can do.
    272             release_fence = image.dequeue_fence;
    273         }
    274         image.dequeue_fence = -1;
    275 
    276         if (window) {
    277             window->cancelBuffer(window, image.buffer.get(), release_fence);
    278         } else {
    279             if (release_fence >= 0) {
    280                 sync_wait(release_fence, -1 /* forever */);
    281                 close(release_fence);
    282             }
    283         }
    284 
    285         image.dequeued = false;
    286     }
    287 
    288     if (image.image) {
    289         GetData(device).driver.DestroyImage(device, image.image, nullptr);
    290         image.image = VK_NULL_HANDLE;
    291     }
    292 
    293     image.buffer.clear();
    294 }
    295 
    296 void OrphanSwapchain(VkDevice device, Swapchain* swapchain) {
    297     if (swapchain->surface.swapchain_handle != HandleFromSwapchain(swapchain))
    298         return;
    299     for (uint32_t i = 0; i < swapchain->num_images; i++) {
    300         if (!swapchain->images[i].dequeued)
    301             ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]);
    302     }
    303     swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
    304     swapchain->timing.clear();
    305 }
    306 
    307 uint32_t get_num_ready_timings(Swapchain& swapchain) {
    308     if (swapchain.timing.size() < MIN_NUM_FRAMES_AGO) {
    309         return 0;
    310     }
    311 
    312     uint32_t num_ready = 0;
    313     const size_t num_timings = swapchain.timing.size() - MIN_NUM_FRAMES_AGO + 1;
    314     for (uint32_t i = 0; i < num_timings; i++) {
    315         TimingInfo& ti = swapchain.timing.editItemAt(i);
    316         if (ti.ready()) {
    317             // This TimingInfo is ready to be reported to the user.  Add it
    318             // to the num_ready.
    319             num_ready++;
    320             continue;
    321         }
    322         // This TimingInfo is not yet ready to be reported to the user,
    323         // and so we should look for any available timestamps that
    324         // might make it ready.
    325         int64_t desired_present_time = 0;
    326         int64_t render_complete_time = 0;
    327         int64_t composition_latch_time = 0;
    328         int64_t actual_present_time = 0;
    329         // Obtain timestamps:
    330         int ret = native_window_get_frame_timestamps(
    331             swapchain.surface.window.get(), ti.native_frame_id_,
    332             &desired_present_time, &render_complete_time,
    333             &composition_latch_time,
    334             NULL,  //&first_composition_start_time,
    335             NULL,  //&last_composition_start_time,
    336             NULL,  //&composition_finish_time,
    337             // TODO(ianelliott): Maybe ask if this one is
    338             // supported, at startup time (since it may not be
    339             // supported):
    340             &actual_present_time,
    341             NULL,  //&dequeue_ready_time,
    342             NULL /*&reads_done_time*/);
    343 
    344         if (ret != android::NO_ERROR) {
    345             continue;
    346         }
    347 
    348         // Record the timestamp(s) we received, and then see if this TimingInfo
    349         // is ready to be reported to the user:
    350         ti.timestamp_desired_present_time_ = desired_present_time;
    351         ti.timestamp_actual_present_time_ = actual_present_time;
    352         ti.timestamp_render_complete_time_ = render_complete_time;
    353         ti.timestamp_composition_latch_time_ = composition_latch_time;
    354 
    355         if (ti.ready()) {
    356             // The TimingInfo has received enough timestamps, and should now
    357             // use those timestamps to calculate the info that should be
    358             // reported to the user:
    359             ti.calculate(swapchain.refresh_duration);
    360             num_ready++;
    361         }
    362     }
    363     return num_ready;
    364 }
    365 
    366 // TODO(ianelliott): DEAL WITH RETURN VALUE (e.g. VK_INCOMPLETE)!!!
    367 void copy_ready_timings(Swapchain& swapchain,
    368                         uint32_t* count,
    369                         VkPastPresentationTimingGOOGLE* timings) {
    370     if (swapchain.timing.empty()) {
    371         *count = 0;
    372         return;
    373     }
    374 
    375     size_t last_ready = swapchain.timing.size() - 1;
    376     while (!swapchain.timing[last_ready].ready()) {
    377         if (last_ready == 0) {
    378             *count = 0;
    379             return;
    380         }
    381         last_ready--;
    382     }
    383 
    384     uint32_t num_copied = 0;
    385     size_t num_to_remove = 0;
    386     for (uint32_t i = 0; i <= last_ready && num_copied < *count; i++) {
    387         const TimingInfo& ti = swapchain.timing[i];
    388         if (ti.ready()) {
    389             ti.get_values(&timings[num_copied]);
    390             num_copied++;
    391         }
    392         num_to_remove++;
    393     }
    394 
    395     // Discard old frames that aren't ready if newer frames are ready.
    396     // We don't expect to get the timing info for those old frames.
    397     swapchain.timing.removeItemsAt(0, num_to_remove);
    398 
    399     *count = num_copied;
    400 }
    401 
    402 android_pixel_format GetNativePixelFormat(VkFormat format) {
    403     android_pixel_format native_format = HAL_PIXEL_FORMAT_RGBA_8888;
    404     switch (format) {
    405         case VK_FORMAT_R8G8B8A8_UNORM:
    406         case VK_FORMAT_R8G8B8A8_SRGB:
    407             native_format = HAL_PIXEL_FORMAT_RGBA_8888;
    408             break;
    409         case VK_FORMAT_R5G6B5_UNORM_PACK16:
    410             native_format = HAL_PIXEL_FORMAT_RGB_565;
    411             break;
    412         case VK_FORMAT_R16G16B16A16_SFLOAT:
    413             native_format = HAL_PIXEL_FORMAT_RGBA_FP16;
    414             break;
    415         case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
    416             native_format = HAL_PIXEL_FORMAT_RGBA_1010102;
    417             break;
    418         default:
    419             ALOGV("unsupported swapchain format %d", format);
    420             break;
    421     }
    422     return native_format;
    423 }
    424 
    425 android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) {
    426     switch (colorspace) {
    427         case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
    428             return HAL_DATASPACE_V0_SRGB;
    429         case VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT:
    430             return HAL_DATASPACE_DISPLAY_P3;
    431         case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
    432             return HAL_DATASPACE_V0_SCRGB_LINEAR;
    433         case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT:
    434             return HAL_DATASPACE_V0_SCRGB;
    435         case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
    436             return HAL_DATASPACE_DCI_P3_LINEAR;
    437         case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT:
    438             return HAL_DATASPACE_DCI_P3;
    439         case VK_COLOR_SPACE_BT709_LINEAR_EXT:
    440             return HAL_DATASPACE_V0_SRGB_LINEAR;
    441         case VK_COLOR_SPACE_BT709_NONLINEAR_EXT:
    442             return HAL_DATASPACE_V0_SRGB;
    443         case VK_COLOR_SPACE_BT2020_LINEAR_EXT:
    444             return HAL_DATASPACE_BT2020_LINEAR;
    445         case VK_COLOR_SPACE_HDR10_ST2084_EXT:
    446             return static_cast<android_dataspace>(
    447                 HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
    448                 HAL_DATASPACE_RANGE_FULL);
    449         case VK_COLOR_SPACE_DOLBYVISION_EXT:
    450             return static_cast<android_dataspace>(
    451                 HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
    452                 HAL_DATASPACE_RANGE_FULL);
    453         case VK_COLOR_SPACE_HDR10_HLG_EXT:
    454             return static_cast<android_dataspace>(
    455                 HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_HLG |
    456                 HAL_DATASPACE_RANGE_FULL);
    457         case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT:
    458             return static_cast<android_dataspace>(
    459                 HAL_DATASPACE_STANDARD_ADOBE_RGB |
    460                 HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL);
    461         case VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT:
    462             return HAL_DATASPACE_ADOBE_RGB;
    463 
    464         // Pass through is intended to allow app to provide data that is passed
    465         // to the display system without modification.
    466         case VK_COLOR_SPACE_PASS_THROUGH_EXT:
    467             return HAL_DATASPACE_ARBITRARY;
    468 
    469         default:
    470             // This indicates that we don't know about the
    471             // dataspace specified and we should indicate that
    472             // it's unsupported
    473             return HAL_DATASPACE_UNKNOWN;
    474     }
    475 }
    476 
    477 }  // anonymous namespace
    478 
    479 VKAPI_ATTR
    480 VkResult CreateAndroidSurfaceKHR(
    481     VkInstance instance,
    482     const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
    483     const VkAllocationCallbacks* allocator,
    484     VkSurfaceKHR* out_surface) {
    485     if (!allocator)
    486         allocator = &GetData(instance).allocator;
    487     void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
    488                                          alignof(Surface),
    489                                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    490     if (!mem)
    491         return VK_ERROR_OUT_OF_HOST_MEMORY;
    492     Surface* surface = new (mem) Surface;
    493 
    494     surface->window = pCreateInfo->window;
    495     surface->swapchain_handle = VK_NULL_HANDLE;
    496 
    497     // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
    498     int err =
    499         native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
    500     if (err != 0) {
    501         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    502         // errors and translate them to valid Vulkan result codes?
    503         ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
    504               err);
    505         surface->~Surface();
    506         allocator->pfnFree(allocator->pUserData, surface);
    507         return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
    508     }
    509 
    510     *out_surface = HandleFromSurface(surface);
    511     return VK_SUCCESS;
    512 }
    513 
    514 VKAPI_ATTR
    515 void DestroySurfaceKHR(VkInstance instance,
    516                        VkSurfaceKHR surface_handle,
    517                        const VkAllocationCallbacks* allocator) {
    518     Surface* surface = SurfaceFromHandle(surface_handle);
    519     if (!surface)
    520         return;
    521     native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL);
    522     ALOGV_IF(surface->swapchain_handle != VK_NULL_HANDLE,
    523              "destroyed VkSurfaceKHR 0x%" PRIx64
    524              " has active VkSwapchainKHR 0x%" PRIx64,
    525              reinterpret_cast<uint64_t>(surface_handle),
    526              reinterpret_cast<uint64_t>(surface->swapchain_handle));
    527     surface->~Surface();
    528     if (!allocator)
    529         allocator = &GetData(instance).allocator;
    530     allocator->pfnFree(allocator->pUserData, surface);
    531 }
    532 
    533 VKAPI_ATTR
    534 VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
    535                                             uint32_t /*queue_family*/,
    536                                             VkSurfaceKHR /*surface*/,
    537                                             VkBool32* supported) {
    538     *supported = VK_TRUE;
    539     return VK_SUCCESS;
    540 }
    541 
    542 VKAPI_ATTR
    543 VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(
    544     VkPhysicalDevice /*pdev*/,
    545     VkSurfaceKHR surface,
    546     VkSurfaceCapabilitiesKHR* capabilities) {
    547     int err;
    548     ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
    549 
    550     int width, height;
    551     err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
    552     if (err != 0) {
    553         ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
    554               strerror(-err), err);
    555         return VK_ERROR_SURFACE_LOST_KHR;
    556     }
    557     err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
    558     if (err != 0) {
    559         ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
    560               strerror(-err), err);
    561         return VK_ERROR_SURFACE_LOST_KHR;
    562     }
    563 
    564     int transform_hint;
    565     err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
    566     if (err != 0) {
    567         ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
    568               strerror(-err), err);
    569         return VK_ERROR_SURFACE_LOST_KHR;
    570     }
    571 
    572     // TODO(jessehall): Figure out what the min/max values should be.
    573     capabilities->minImageCount = 2;
    574     capabilities->maxImageCount = 3;
    575 
    576     capabilities->currentExtent =
    577         VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
    578 
    579     // TODO(jessehall): Figure out what the max extent should be. Maximum
    580     // texture dimension maybe?
    581     capabilities->minImageExtent = VkExtent2D{1, 1};
    582     capabilities->maxImageExtent = VkExtent2D{4096, 4096};
    583 
    584     capabilities->maxImageArrayLayers = 1;
    585 
    586     capabilities->supportedTransforms = kSupportedTransforms;
    587     capabilities->currentTransform =
    588         TranslateNativeToVulkanTransform(transform_hint);
    589 
    590     // On Android, window composition is a WindowManager property, not something
    591     // associated with the bufferqueue. It can't be changed from here.
    592     capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
    593 
    594     // TODO(jessehall): I think these are right, but haven't thought hard about
    595     // it. Do we need to query the driver for support of any of these?
    596     // Currently not included:
    597     // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
    598     // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
    599     capabilities->supportedUsageFlags =
    600         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
    601         VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
    602         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
    603         VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
    604 
    605     return VK_SUCCESS;
    606 }
    607 
    608 VKAPI_ATTR
    609 VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev,
    610                                             VkSurfaceKHR surface_handle,
    611                                             uint32_t* count,
    612                                             VkSurfaceFormatKHR* formats) {
    613     const InstanceData& instance_data = GetData(pdev);
    614 
    615     // TODO(jessehall): Fill out the set of supported formats. Longer term, add
    616     // a new gralloc method to query whether a (format, usage) pair is
    617     // supported, and check that for each gralloc format that corresponds to a
    618     // Vulkan format. Shorter term, just add a few more formats to the ones
    619     // hardcoded below.
    620 
    621     const VkSurfaceFormatKHR kFormats[] = {
    622         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
    623         {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
    624         {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
    625     };
    626     const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
    627     uint32_t total_num_formats = kNumFormats;
    628 
    629     bool wide_color_support = false;
    630     Surface& surface = *SurfaceFromHandle(surface_handle);
    631     int err = native_window_get_wide_color_support(surface.window.get(),
    632                                                    &wide_color_support);
    633     if (err) {
    634         // Not allowed to return a more sensible error code, so do this
    635         return VK_ERROR_OUT_OF_HOST_MEMORY;
    636     }
    637     ALOGV("wide_color_support is: %d", wide_color_support);
    638     wide_color_support =
    639         wide_color_support &&
    640         instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    641 
    642     const VkSurfaceFormatKHR kWideColorFormats[] = {
    643         {VK_FORMAT_R8G8B8A8_UNORM,
    644          VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
    645         {VK_FORMAT_R8G8B8A8_SRGB,
    646          VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
    647     };
    648     const uint32_t kNumWideColorFormats =
    649         sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]);
    650     if (wide_color_support) {
    651         total_num_formats += kNumWideColorFormats;
    652     }
    653 
    654     VkResult result = VK_SUCCESS;
    655     if (formats) {
    656         uint32_t out_count = 0;
    657         uint32_t transfer_count = 0;
    658         if (*count < total_num_formats)
    659             result = VK_INCOMPLETE;
    660         transfer_count = std::min(*count, kNumFormats);
    661         std::copy(kFormats, kFormats + transfer_count, formats);
    662         out_count += transfer_count;
    663         if (wide_color_support) {
    664             transfer_count = std::min(*count - out_count, kNumWideColorFormats);
    665             std::copy(kWideColorFormats, kWideColorFormats + transfer_count,
    666                       formats + out_count);
    667             out_count += transfer_count;
    668         }
    669         *count = out_count;
    670     } else {
    671         *count = total_num_formats;
    672     }
    673     return result;
    674 }
    675 
    676 VKAPI_ATTR
    677 VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(
    678     VkPhysicalDevice physicalDevice,
    679     const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
    680     VkSurfaceCapabilities2KHR* pSurfaceCapabilities) {
    681     VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR(
    682         physicalDevice, pSurfaceInfo->surface,
    683         &pSurfaceCapabilities->surfaceCapabilities);
    684 
    685     VkSurfaceCapabilities2KHR* caps = pSurfaceCapabilities;
    686     while (caps->pNext) {
    687         caps = reinterpret_cast<VkSurfaceCapabilities2KHR*>(caps->pNext);
    688 
    689         switch (caps->sType) {
    690             case VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR: {
    691                 VkSharedPresentSurfaceCapabilitiesKHR* shared_caps =
    692                     reinterpret_cast<VkSharedPresentSurfaceCapabilitiesKHR*>(
    693                         caps);
    694                 // Claim same set of usage flags are supported for
    695                 // shared present modes as for other modes.
    696                 shared_caps->sharedPresentSupportedUsageFlags =
    697                     pSurfaceCapabilities->surfaceCapabilities
    698                         .supportedUsageFlags;
    699             } break;
    700 
    701             default:
    702                 // Ignore all other extension structs
    703                 break;
    704         }
    705     }
    706 
    707     return result;
    708 }
    709 
    710 VKAPI_ATTR
    711 VkResult GetPhysicalDeviceSurfaceFormats2KHR(
    712     VkPhysicalDevice physicalDevice,
    713     const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
    714     uint32_t* pSurfaceFormatCount,
    715     VkSurfaceFormat2KHR* pSurfaceFormats) {
    716     if (!pSurfaceFormats) {
    717         return GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,
    718                                                   pSurfaceInfo->surface,
    719                                                   pSurfaceFormatCount, nullptr);
    720     } else {
    721         // temp vector for forwarding; we'll marshal it into the pSurfaceFormats
    722         // after the call.
    723         android::Vector<VkSurfaceFormatKHR> surface_formats;
    724         surface_formats.resize(*pSurfaceFormatCount);
    725         VkResult result = GetPhysicalDeviceSurfaceFormatsKHR(
    726             physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount,
    727             &surface_formats.editItemAt(0));
    728 
    729         if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
    730             // marshal results individually due to stride difference.
    731             // completely ignore any chained extension structs.
    732             uint32_t formats_to_marshal = *pSurfaceFormatCount;
    733             for (uint32_t i = 0u; i < formats_to_marshal; i++) {
    734                 pSurfaceFormats[i].surfaceFormat = surface_formats[i];
    735             }
    736         }
    737 
    738         return result;
    739     }
    740 }
    741 
    742 VKAPI_ATTR
    743 VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev,
    744                                                  VkSurfaceKHR /*surface*/,
    745                                                  uint32_t* count,
    746                                                  VkPresentModeKHR* modes) {
    747     android::Vector<VkPresentModeKHR> present_modes;
    748     present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
    749     present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
    750 
    751     VkPhysicalDevicePresentationPropertiesANDROID present_properties;
    752     if (QueryPresentationProperties(pdev, &present_properties)) {
    753         if (present_properties.sharedImage) {
    754             present_modes.push_back(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR);
    755             present_modes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR);
    756         }
    757     }
    758 
    759     uint32_t num_modes = uint32_t(present_modes.size());
    760 
    761     VkResult result = VK_SUCCESS;
    762     if (modes) {
    763         if (*count < num_modes)
    764             result = VK_INCOMPLETE;
    765         *count = std::min(*count, num_modes);
    766         std::copy(present_modes.begin(), present_modes.begin() + int(*count), modes);
    767     } else {
    768         *count = num_modes;
    769     }
    770     return result;
    771 }
    772 
    773 VKAPI_ATTR
    774 VkResult CreateSwapchainKHR(VkDevice device,
    775                             const VkSwapchainCreateInfoKHR* create_info,
    776                             const VkAllocationCallbacks* allocator,
    777                             VkSwapchainKHR* swapchain_handle) {
    778     int err;
    779     VkResult result = VK_SUCCESS;
    780 
    781     ALOGV("vkCreateSwapchainKHR: surface=0x%" PRIx64
    782           " minImageCount=%u imageFormat=%u imageColorSpace=%u"
    783           " imageExtent=%ux%u imageUsage=%#x preTransform=%u presentMode=%u"
    784           " oldSwapchain=0x%" PRIx64,
    785           reinterpret_cast<uint64_t>(create_info->surface),
    786           create_info->minImageCount, create_info->imageFormat,
    787           create_info->imageColorSpace, create_info->imageExtent.width,
    788           create_info->imageExtent.height, create_info->imageUsage,
    789           create_info->preTransform, create_info->presentMode,
    790           reinterpret_cast<uint64_t>(create_info->oldSwapchain));
    791 
    792     if (!allocator)
    793         allocator = &GetData(device).allocator;
    794 
    795     android_pixel_format native_pixel_format =
    796         GetNativePixelFormat(create_info->imageFormat);
    797     android_dataspace native_dataspace =
    798         GetNativeDataspace(create_info->imageColorSpace);
    799     if (native_dataspace == HAL_DATASPACE_UNKNOWN) {
    800         ALOGE(
    801             "CreateSwapchainKHR(VkSwapchainCreateInfoKHR.imageColorSpace = %d) "
    802             "failed: Unsupported color space",
    803             create_info->imageColorSpace);
    804         return VK_ERROR_INITIALIZATION_FAILED;
    805     }
    806 
    807     ALOGV_IF(create_info->imageArrayLayers != 1,
    808              "swapchain imageArrayLayers=%u not supported",
    809              create_info->imageArrayLayers);
    810     ALOGV_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
    811              "swapchain preTransform=%#x not supported",
    812              create_info->preTransform);
    813     ALOGV_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
    814                create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ||
    815                create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
    816                create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR),
    817              "swapchain presentMode=%u not supported",
    818              create_info->presentMode);
    819 
    820     Surface& surface = *SurfaceFromHandle(create_info->surface);
    821 
    822     if (surface.swapchain_handle != create_info->oldSwapchain) {
    823         ALOGV("Can't create a swapchain for VkSurfaceKHR 0x%" PRIx64
    824               " because it already has active swapchain 0x%" PRIx64
    825               " but VkSwapchainCreateInfo::oldSwapchain=0x%" PRIx64,
    826               reinterpret_cast<uint64_t>(create_info->surface),
    827               reinterpret_cast<uint64_t>(surface.swapchain_handle),
    828               reinterpret_cast<uint64_t>(create_info->oldSwapchain));
    829         return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
    830     }
    831     if (create_info->oldSwapchain != VK_NULL_HANDLE)
    832         OrphanSwapchain(device, SwapchainFromHandle(create_info->oldSwapchain));
    833 
    834     // -- Reset the native window --
    835     // The native window might have been used previously, and had its properties
    836     // changed from defaults. That will affect the answer we get for queries
    837     // like MIN_UNDEQUED_BUFFERS. Reset to a known/default state before we
    838     // attempt such queries.
    839 
    840     // The native window only allows dequeueing all buffers before any have
    841     // been queued, since after that point at least one is assumed to be in
    842     // non-FREE state at any given time. Disconnecting and re-connecting
    843     // orphans the previous buffers, getting us back to the state where we can
    844     // dequeue all buffers.
    845     err = native_window_api_disconnect(surface.window.get(),
    846                                        NATIVE_WINDOW_API_EGL);
    847     ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)",
    848              strerror(-err), err);
    849     err =
    850         native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL);
    851     ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)",
    852              strerror(-err), err);
    853 
    854     err = native_window_set_buffer_count(surface.window.get(), 0);
    855     if (err != 0) {
    856         ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
    857               strerror(-err), err);
    858         return VK_ERROR_SURFACE_LOST_KHR;
    859     }
    860 
    861     int swap_interval =
    862         create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
    863     err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
    864     if (err != 0) {
    865         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    866         // errors and translate them to valid Vulkan result codes?
    867         ALOGE("native_window->setSwapInterval(1) failed: %s (%d)",
    868               strerror(-err), err);
    869         return VK_ERROR_SURFACE_LOST_KHR;
    870     }
    871 
    872     err = native_window_set_shared_buffer_mode(surface.window.get(), false);
    873     if (err != 0) {
    874         ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)",
    875               strerror(-err), err);
    876         return VK_ERROR_SURFACE_LOST_KHR;
    877     }
    878 
    879     err = native_window_set_auto_refresh(surface.window.get(), false);
    880     if (err != 0) {
    881         ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)",
    882               strerror(-err), err);
    883         return VK_ERROR_SURFACE_LOST_KHR;
    884     }
    885 
    886     // -- Configure the native window --
    887 
    888     const auto& dispatch = GetData(device).driver;
    889 
    890     err = native_window_set_buffers_format(surface.window.get(),
    891                                            native_pixel_format);
    892     if (err != 0) {
    893         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    894         // errors and translate them to valid Vulkan result codes?
    895         ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
    896               native_pixel_format, strerror(-err), err);
    897         return VK_ERROR_SURFACE_LOST_KHR;
    898     }
    899     err = native_window_set_buffers_data_space(surface.window.get(),
    900                                                native_dataspace);
    901     if (err != 0) {
    902         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    903         // errors and translate them to valid Vulkan result codes?
    904         ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
    905               native_dataspace, strerror(-err), err);
    906         return VK_ERROR_SURFACE_LOST_KHR;
    907     }
    908 
    909     err = native_window_set_buffers_dimensions(
    910         surface.window.get(), static_cast<int>(create_info->imageExtent.width),
    911         static_cast<int>(create_info->imageExtent.height));
    912     if (err != 0) {
    913         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    914         // errors and translate them to valid Vulkan result codes?
    915         ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
    916               create_info->imageExtent.width, create_info->imageExtent.height,
    917               strerror(-err), err);
    918         return VK_ERROR_SURFACE_LOST_KHR;
    919     }
    920 
    921     // VkSwapchainCreateInfo::preTransform indicates the transformation the app
    922     // applied during rendering. native_window_set_transform() expects the
    923     // inverse: the transform the app is requesting that the compositor perform
    924     // during composition. With native windows, pre-transform works by rendering
    925     // with the same transform the compositor is applying (as in Vulkan), but
    926     // then requesting the inverse transform, so that when the compositor does
    927     // it's job the two transforms cancel each other out and the compositor ends
    928     // up applying an identity transform to the app's buffer.
    929     err = native_window_set_buffers_transform(
    930         surface.window.get(),
    931         InvertTransformToNative(create_info->preTransform));
    932     if (err != 0) {
    933         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    934         // errors and translate them to valid Vulkan result codes?
    935         ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
    936               InvertTransformToNative(create_info->preTransform),
    937               strerror(-err), err);
    938         return VK_ERROR_SURFACE_LOST_KHR;
    939     }
    940 
    941     err = native_window_set_scaling_mode(
    942         surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
    943     if (err != 0) {
    944         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    945         // errors and translate them to valid Vulkan result codes?
    946         ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
    947               strerror(-err), err);
    948         return VK_ERROR_SURFACE_LOST_KHR;
    949     }
    950 
    951     VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0;
    952     if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
    953         create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
    954         swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID;
    955         err = native_window_set_shared_buffer_mode(surface.window.get(), true);
    956         if (err != 0) {
    957             ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
    958             return VK_ERROR_SURFACE_LOST_KHR;
    959         }
    960     }
    961 
    962     if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
    963         err = native_window_set_auto_refresh(surface.window.get(), true);
    964         if (err != 0) {
    965             ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err);
    966             return VK_ERROR_SURFACE_LOST_KHR;
    967         }
    968     }
    969 
    970     int query_value;
    971     err = surface.window->query(surface.window.get(),
    972                                 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
    973                                 &query_value);
    974     if (err != 0 || query_value < 0) {
    975         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    976         // errors and translate them to valid Vulkan result codes?
    977         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
    978               query_value);
    979         return VK_ERROR_SURFACE_LOST_KHR;
    980     }
    981     uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
    982     uint32_t num_images =
    983         (create_info->minImageCount - 1) + min_undequeued_buffers;
    984 
    985     // Lower layer insists that we have at least two buffers. This is wasteful
    986     // and we'd like to relax it in the shared case, but not all the pieces are
    987     // in place for that to work yet. Note we only lie to the lower layer-- we
    988     // don't want to give the app back a swapchain with extra images (which they
    989     // can't actually use!).
    990     err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images));
    991     if (err != 0) {
    992         // TODO(jessehall): Improve error reporting. Can we enumerate possible
    993         // errors and translate them to valid Vulkan result codes?
    994         ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
    995               strerror(-err), err);
    996         return VK_ERROR_SURFACE_LOST_KHR;
    997     }
    998 
    999     int gralloc_usage = 0;
   1000     if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
   1001         uint64_t consumer_usage, producer_usage;
   1002         result = dispatch.GetSwapchainGrallocUsage2ANDROID(
   1003             device, create_info->imageFormat, create_info->imageUsage,
   1004             swapchain_image_usage, &consumer_usage, &producer_usage);
   1005         if (result != VK_SUCCESS) {
   1006             ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
   1007             return VK_ERROR_SURFACE_LOST_KHR;
   1008         }
   1009         gralloc_usage =
   1010             android_convertGralloc1To0Usage(producer_usage, consumer_usage);
   1011     } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
   1012         result = dispatch.GetSwapchainGrallocUsageANDROID(
   1013             device, create_info->imageFormat, create_info->imageUsage,
   1014             &gralloc_usage);
   1015         if (result != VK_SUCCESS) {
   1016             ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
   1017             return VK_ERROR_SURFACE_LOST_KHR;
   1018         }
   1019     }
   1020     err = native_window_set_usage(surface.window.get(), uint64_t(gralloc_usage));
   1021     if (err != 0) {
   1022         // TODO(jessehall): Improve error reporting. Can we enumerate possible
   1023         // errors and translate them to valid Vulkan result codes?
   1024         ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
   1025         return VK_ERROR_SURFACE_LOST_KHR;
   1026     }
   1027 
   1028     // -- Allocate our Swapchain object --
   1029     // After this point, we must deallocate the swapchain on error.
   1030 
   1031     void* mem = allocator->pfnAllocation(allocator->pUserData,
   1032                                          sizeof(Swapchain), alignof(Swapchain),
   1033                                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
   1034     if (!mem)
   1035         return VK_ERROR_OUT_OF_HOST_MEMORY;
   1036     Swapchain* swapchain =
   1037         new (mem) Swapchain(surface, num_images, create_info->presentMode);
   1038 
   1039     // -- Dequeue all buffers and create a VkImage for each --
   1040     // Any failures during or after this must cancel the dequeued buffers.
   1041 
   1042     VkSwapchainImageCreateInfoANDROID swapchain_image_create = {
   1043 #pragma clang diagnostic push
   1044 #pragma clang diagnostic ignored "-Wold-style-cast"
   1045         .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID,
   1046 #pragma clang diagnostic pop
   1047         .pNext = nullptr,
   1048         .usage = swapchain_image_usage,
   1049     };
   1050     VkNativeBufferANDROID image_native_buffer = {
   1051 #pragma clang diagnostic push
   1052 #pragma clang diagnostic ignored "-Wold-style-cast"
   1053         .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
   1054 #pragma clang diagnostic pop
   1055         .pNext = &swapchain_image_create,
   1056     };
   1057     VkImageCreateInfo image_create = {
   1058         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
   1059         .pNext = &image_native_buffer,
   1060         .imageType = VK_IMAGE_TYPE_2D,
   1061         .format = create_info->imageFormat,
   1062         .extent = {0, 0, 1},
   1063         .mipLevels = 1,
   1064         .arrayLayers = 1,
   1065         .samples = VK_SAMPLE_COUNT_1_BIT,
   1066         .tiling = VK_IMAGE_TILING_OPTIMAL,
   1067         .usage = create_info->imageUsage,
   1068         .flags = 0,
   1069         .sharingMode = create_info->imageSharingMode,
   1070         .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
   1071         .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
   1072     };
   1073 
   1074     for (uint32_t i = 0; i < num_images; i++) {
   1075         Swapchain::Image& img = swapchain->images[i];
   1076 
   1077         ANativeWindowBuffer* buffer;
   1078         err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
   1079                                             &img.dequeue_fence);
   1080         if (err != 0) {
   1081             // TODO(jessehall): Improve error reporting. Can we enumerate
   1082             // possible errors and translate them to valid Vulkan result codes?
   1083             ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
   1084             result = VK_ERROR_SURFACE_LOST_KHR;
   1085             break;
   1086         }
   1087         img.buffer = buffer;
   1088         img.dequeued = true;
   1089 
   1090         image_create.extent =
   1091             VkExtent3D{static_cast<uint32_t>(img.buffer->width),
   1092                        static_cast<uint32_t>(img.buffer->height),
   1093                        1};
   1094         image_native_buffer.handle = img.buffer->handle;
   1095         image_native_buffer.stride = img.buffer->stride;
   1096         image_native_buffer.format = img.buffer->format;
   1097         image_native_buffer.usage = int(img.buffer->usage);
   1098         android_convertGralloc0To1Usage(int(img.buffer->usage),
   1099             &image_native_buffer.usage2.producer,
   1100             &image_native_buffer.usage2.consumer);
   1101 
   1102         result =
   1103             dispatch.CreateImage(device, &image_create, nullptr, &img.image);
   1104         if (result != VK_SUCCESS) {
   1105             ALOGD("vkCreateImage w/ native buffer failed: %u", result);
   1106             break;
   1107         }
   1108     }
   1109 
   1110     // -- Cancel all buffers, returning them to the queue --
   1111     // If an error occurred before, also destroy the VkImage and release the
   1112     // buffer reference. Otherwise, we retain a strong reference to the buffer.
   1113     //
   1114     // TODO(jessehall): The error path here is the same as DestroySwapchain,
   1115     // but not the non-error path. Should refactor/unify.
   1116     if (!swapchain->shared) {
   1117         for (uint32_t i = 0; i < num_images; i++) {
   1118             Swapchain::Image& img = swapchain->images[i];
   1119             if (img.dequeued) {
   1120                 surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
   1121                                              img.dequeue_fence);
   1122                 img.dequeue_fence = -1;
   1123                 img.dequeued = false;
   1124             }
   1125             if (result != VK_SUCCESS) {
   1126                 if (img.image)
   1127                     dispatch.DestroyImage(device, img.image, nullptr);
   1128             }
   1129         }
   1130     }
   1131 
   1132     if (result != VK_SUCCESS) {
   1133         swapchain->~Swapchain();
   1134         allocator->pfnFree(allocator->pUserData, swapchain);
   1135         return result;
   1136     }
   1137 
   1138     surface.swapchain_handle = HandleFromSwapchain(swapchain);
   1139     *swapchain_handle = surface.swapchain_handle;
   1140     return VK_SUCCESS;
   1141 }
   1142 
   1143 VKAPI_ATTR
   1144 void DestroySwapchainKHR(VkDevice device,
   1145                          VkSwapchainKHR swapchain_handle,
   1146                          const VkAllocationCallbacks* allocator) {
   1147     const auto& dispatch = GetData(device).driver;
   1148     Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
   1149     if (!swapchain)
   1150         return;
   1151     bool active = swapchain->surface.swapchain_handle == swapchain_handle;
   1152     ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr;
   1153 
   1154     if (swapchain->frame_timestamps_enabled) {
   1155         native_window_enable_frame_timestamps(window, false);
   1156     }
   1157     for (uint32_t i = 0; i < swapchain->num_images; i++)
   1158         ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
   1159     if (active)
   1160         swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
   1161     if (!allocator)
   1162         allocator = &GetData(device).allocator;
   1163     swapchain->~Swapchain();
   1164     allocator->pfnFree(allocator->pUserData, swapchain);
   1165 }
   1166 
   1167 VKAPI_ATTR
   1168 VkResult GetSwapchainImagesKHR(VkDevice,
   1169                                VkSwapchainKHR swapchain_handle,
   1170                                uint32_t* count,
   1171                                VkImage* images) {
   1172     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
   1173     ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle,
   1174              "getting images for non-active swapchain 0x%" PRIx64
   1175              "; only dequeued image handles are valid",
   1176              reinterpret_cast<uint64_t>(swapchain_handle));
   1177     VkResult result = VK_SUCCESS;
   1178     if (images) {
   1179         uint32_t n = swapchain.num_images;
   1180         if (*count < swapchain.num_images) {
   1181             n = *count;
   1182             result = VK_INCOMPLETE;
   1183         }
   1184         for (uint32_t i = 0; i < n; i++)
   1185             images[i] = swapchain.images[i].image;
   1186         *count = n;
   1187     } else {
   1188         *count = swapchain.num_images;
   1189     }
   1190     return result;
   1191 }
   1192 
   1193 VKAPI_ATTR
   1194 VkResult AcquireNextImageKHR(VkDevice device,
   1195                              VkSwapchainKHR swapchain_handle,
   1196                              uint64_t timeout,
   1197                              VkSemaphore semaphore,
   1198                              VkFence vk_fence,
   1199                              uint32_t* image_index) {
   1200     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
   1201     ANativeWindow* window = swapchain.surface.window.get();
   1202     VkResult result;
   1203     int err;
   1204 
   1205     if (swapchain.surface.swapchain_handle != swapchain_handle)
   1206         return VK_ERROR_OUT_OF_DATE_KHR;
   1207 
   1208     ALOGW_IF(
   1209         timeout != UINT64_MAX,
   1210         "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
   1211 
   1212     if (swapchain.shared) {
   1213         // In shared mode, we keep the buffer dequeued all the time, so we don't
   1214         // want to dequeue a buffer here. Instead, just ask the driver to ensure
   1215         // the semaphore and fence passed to us will be signalled.
   1216         *image_index = 0;
   1217         result = GetData(device).driver.AcquireImageANDROID(
   1218                 device, swapchain.images[*image_index].image, -1, semaphore, vk_fence);
   1219         return result;
   1220     }
   1221 
   1222     ANativeWindowBuffer* buffer;
   1223     int fence_fd;
   1224     err = window->dequeueBuffer(window, &buffer, &fence_fd);
   1225     if (err != 0) {
   1226         // TODO(jessehall): Improve error reporting. Can we enumerate possible
   1227         // errors and translate them to valid Vulkan result codes?
   1228         ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
   1229         return VK_ERROR_SURFACE_LOST_KHR;
   1230     }
   1231 
   1232     uint32_t idx;
   1233     for (idx = 0; idx < swapchain.num_images; idx++) {
   1234         if (swapchain.images[idx].buffer.get() == buffer) {
   1235             swapchain.images[idx].dequeued = true;
   1236             swapchain.images[idx].dequeue_fence = fence_fd;
   1237             break;
   1238         }
   1239     }
   1240     if (idx == swapchain.num_images) {
   1241         ALOGE("dequeueBuffer returned unrecognized buffer");
   1242         window->cancelBuffer(window, buffer, fence_fd);
   1243         return VK_ERROR_OUT_OF_DATE_KHR;
   1244     }
   1245 
   1246     int fence_clone = -1;
   1247     if (fence_fd != -1) {
   1248         fence_clone = dup(fence_fd);
   1249         if (fence_clone == -1) {
   1250             ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
   1251                   strerror(errno), errno);
   1252             sync_wait(fence_fd, -1 /* forever */);
   1253         }
   1254     }
   1255 
   1256     result = GetData(device).driver.AcquireImageANDROID(
   1257         device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
   1258     if (result != VK_SUCCESS) {
   1259         // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
   1260         // even if the call fails. We could close it ourselves on failure, but
   1261         // that would create a race condition if the driver closes it on a
   1262         // failure path: some other thread might create an fd with the same
   1263         // number between the time the driver closes it and the time we close
   1264         // it. We must assume one of: the driver *always* closes it even on
   1265         // failure, or *never* closes it on failure.
   1266         window->cancelBuffer(window, buffer, fence_fd);
   1267         swapchain.images[idx].dequeued = false;
   1268         swapchain.images[idx].dequeue_fence = -1;
   1269         return result;
   1270     }
   1271 
   1272     *image_index = idx;
   1273     return VK_SUCCESS;
   1274 }
   1275 
   1276 static VkResult WorstPresentResult(VkResult a, VkResult b) {
   1277     // See the error ranking for vkQueuePresentKHR at the end of section 29.6
   1278     // (in spec version 1.0.14).
   1279     static const VkResult kWorstToBest[] = {
   1280         VK_ERROR_DEVICE_LOST,
   1281         VK_ERROR_SURFACE_LOST_KHR,
   1282         VK_ERROR_OUT_OF_DATE_KHR,
   1283         VK_ERROR_OUT_OF_DEVICE_MEMORY,
   1284         VK_ERROR_OUT_OF_HOST_MEMORY,
   1285         VK_SUBOPTIMAL_KHR,
   1286     };
   1287     for (auto result : kWorstToBest) {
   1288         if (a == result || b == result)
   1289             return result;
   1290     }
   1291     ALOG_ASSERT(a == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", a);
   1292     ALOG_ASSERT(b == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", b);
   1293     return a != VK_SUCCESS ? a : b;
   1294 }
   1295 
   1296 VKAPI_ATTR
   1297 VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
   1298     ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
   1299              "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
   1300              present_info->sType);
   1301 
   1302     VkDevice device = GetData(queue).driver_device;
   1303     const auto& dispatch = GetData(queue).driver;
   1304     VkResult final_result = VK_SUCCESS;
   1305 
   1306     // Look at the pNext chain for supported extension structs:
   1307     const VkPresentRegionsKHR* present_regions = nullptr;
   1308     const VkPresentTimesInfoGOOGLE* present_times = nullptr;
   1309     const VkPresentRegionsKHR* next =
   1310         reinterpret_cast<const VkPresentRegionsKHR*>(present_info->pNext);
   1311     while (next) {
   1312         switch (next->sType) {
   1313             case VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR:
   1314                 present_regions = next;
   1315                 break;
   1316             case VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE:
   1317                 present_times =
   1318                     reinterpret_cast<const VkPresentTimesInfoGOOGLE*>(next);
   1319                 break;
   1320             default:
   1321                 ALOGV("QueuePresentKHR ignoring unrecognized pNext->sType = %x",
   1322                       next->sType);
   1323                 break;
   1324         }
   1325         next = reinterpret_cast<const VkPresentRegionsKHR*>(next->pNext);
   1326     }
   1327     ALOGV_IF(
   1328         present_regions &&
   1329             present_regions->swapchainCount != present_info->swapchainCount,
   1330         "VkPresentRegions::swapchainCount != VkPresentInfo::swapchainCount");
   1331     ALOGV_IF(present_times &&
   1332                  present_times->swapchainCount != present_info->swapchainCount,
   1333              "VkPresentTimesInfoGOOGLE::swapchainCount != "
   1334              "VkPresentInfo::swapchainCount");
   1335     const VkPresentRegionKHR* regions =
   1336         (present_regions) ? present_regions->pRegions : nullptr;
   1337     const VkPresentTimeGOOGLE* times =
   1338         (present_times) ? present_times->pTimes : nullptr;
   1339     const VkAllocationCallbacks* allocator = &GetData(device).allocator;
   1340     android_native_rect_t* rects = nullptr;
   1341     uint32_t nrects = 0;
   1342 
   1343     for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
   1344         Swapchain& swapchain =
   1345             *SwapchainFromHandle(present_info->pSwapchains[sc]);
   1346         uint32_t image_idx = present_info->pImageIndices[sc];
   1347         Swapchain::Image& img = swapchain.images[image_idx];
   1348         const VkPresentRegionKHR* region =
   1349             (regions && !swapchain.mailbox_mode) ? &regions[sc] : nullptr;
   1350         const VkPresentTimeGOOGLE* time = (times) ? &times[sc] : nullptr;
   1351         VkResult swapchain_result = VK_SUCCESS;
   1352         VkResult result;
   1353         int err;
   1354 
   1355         int fence = -1;
   1356         result = dispatch.QueueSignalReleaseImageANDROID(
   1357             queue, present_info->waitSemaphoreCount,
   1358             present_info->pWaitSemaphores, img.image, &fence);
   1359         if (result != VK_SUCCESS) {
   1360             ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
   1361             swapchain_result = result;
   1362         }
   1363 
   1364         if (swapchain.surface.swapchain_handle ==
   1365             present_info->pSwapchains[sc]) {
   1366             ANativeWindow* window = swapchain.surface.window.get();
   1367             if (swapchain_result == VK_SUCCESS) {
   1368                 if (region) {
   1369                     // Process the incremental-present hint for this swapchain:
   1370                     uint32_t rcount = region->rectangleCount;
   1371                     if (rcount > nrects) {
   1372                         android_native_rect_t* new_rects =
   1373                             static_cast<android_native_rect_t*>(
   1374                                 allocator->pfnReallocation(
   1375                                     allocator->pUserData, rects,
   1376                                     sizeof(android_native_rect_t) * rcount,
   1377                                     alignof(android_native_rect_t),
   1378                                     VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
   1379                         if (new_rects) {
   1380                             rects = new_rects;
   1381                             nrects = rcount;
   1382                         } else {
   1383                             rcount = 0;  // Ignore the hint for this swapchain
   1384                         }
   1385                     }
   1386                     for (uint32_t r = 0; r < rcount; ++r) {
   1387                         if (region->pRectangles[r].layer > 0) {
   1388                             ALOGV(
   1389                                 "vkQueuePresentKHR ignoring invalid layer "
   1390                                 "(%u); using layer 0 instead",
   1391                                 region->pRectangles[r].layer);
   1392                         }
   1393                         int x = region->pRectangles[r].offset.x;
   1394                         int y = region->pRectangles[r].offset.y;
   1395                         int width = static_cast<int>(
   1396                             region->pRectangles[r].extent.width);
   1397                         int height = static_cast<int>(
   1398                             region->pRectangles[r].extent.height);
   1399                         android_native_rect_t* cur_rect = &rects[r];
   1400                         cur_rect->left = x;
   1401                         cur_rect->top = y + height;
   1402                         cur_rect->right = x + width;
   1403                         cur_rect->bottom = y;
   1404                     }
   1405                     native_window_set_surface_damage(window, rects, rcount);
   1406                 }
   1407                 if (time) {
   1408                     if (!swapchain.frame_timestamps_enabled) {
   1409                         ALOGV(
   1410                             "Calling "
   1411                             "native_window_enable_frame_timestamps(true)");
   1412                         native_window_enable_frame_timestamps(window, true);
   1413                         swapchain.frame_timestamps_enabled = true;
   1414                     }
   1415 
   1416                     // Record the nativeFrameId so it can be later correlated to
   1417                     // this present.
   1418                     uint64_t nativeFrameId = 0;
   1419                     err = native_window_get_next_frame_id(
   1420                             window, &nativeFrameId);
   1421                     if (err != android::NO_ERROR) {
   1422                         ALOGE("Failed to get next native frame ID.");
   1423                     }
   1424 
   1425                     // Add a new timing record with the user's presentID and
   1426                     // the nativeFrameId.
   1427                     swapchain.timing.push_back(TimingInfo(time, nativeFrameId));
   1428                     while (swapchain.timing.size() > MAX_TIMING_INFOS) {
   1429                         swapchain.timing.removeAt(0);
   1430                     }
   1431                     if (time->desiredPresentTime) {
   1432                         // Set the desiredPresentTime:
   1433                         ALOGV(
   1434                             "Calling "
   1435                             "native_window_set_buffers_timestamp(%" PRId64 ")",
   1436                             time->desiredPresentTime);
   1437                         native_window_set_buffers_timestamp(
   1438                             window,
   1439                             static_cast<int64_t>(time->desiredPresentTime));
   1440                     }
   1441                 }
   1442 
   1443                 err = window->queueBuffer(window, img.buffer.get(), fence);
   1444                 // queueBuffer always closes fence, even on error
   1445                 if (err != 0) {
   1446                     // TODO(jessehall): What now? We should probably cancel the
   1447                     // buffer, I guess?
   1448                     ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
   1449                     swapchain_result = WorstPresentResult(
   1450                         swapchain_result, VK_ERROR_OUT_OF_DATE_KHR);
   1451                 }
   1452                 if (img.dequeue_fence >= 0) {
   1453                     close(img.dequeue_fence);
   1454                     img.dequeue_fence = -1;
   1455                 }
   1456                 img.dequeued = false;
   1457 
   1458                 // If the swapchain is in shared mode, immediately dequeue the
   1459                 // buffer so it can be presented again without an intervening
   1460                 // call to AcquireNextImageKHR. We expect to get the same buffer
   1461                 // back from every call to dequeueBuffer in this mode.
   1462                 if (swapchain.shared && swapchain_result == VK_SUCCESS) {
   1463                     ANativeWindowBuffer* buffer;
   1464                     int fence_fd;
   1465                     err = window->dequeueBuffer(window, &buffer, &fence_fd);
   1466                     if (err != 0) {
   1467                         ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
   1468                         swapchain_result = WorstPresentResult(swapchain_result,
   1469                             VK_ERROR_SURFACE_LOST_KHR);
   1470                     }
   1471                     else if (img.buffer != buffer) {
   1472                         ALOGE("got wrong image back for shared swapchain");
   1473                         swapchain_result = WorstPresentResult(swapchain_result,
   1474                             VK_ERROR_SURFACE_LOST_KHR);
   1475                     }
   1476                     else {
   1477                         img.dequeue_fence = fence_fd;
   1478                         img.dequeued = true;
   1479                     }
   1480                 }
   1481             }
   1482             if (swapchain_result != VK_SUCCESS) {
   1483                 ReleaseSwapchainImage(device, window, fence, img);
   1484                 OrphanSwapchain(device, &swapchain);
   1485             }
   1486         } else {
   1487             ReleaseSwapchainImage(device, nullptr, fence, img);
   1488             swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
   1489         }
   1490 
   1491         if (present_info->pResults)
   1492             present_info->pResults[sc] = swapchain_result;
   1493 
   1494         if (swapchain_result != final_result)
   1495             final_result = WorstPresentResult(final_result, swapchain_result);
   1496     }
   1497     if (rects) {
   1498         allocator->pfnFree(allocator->pUserData, rects);
   1499     }
   1500 
   1501     return final_result;
   1502 }
   1503 
   1504 VKAPI_ATTR
   1505 VkResult GetRefreshCycleDurationGOOGLE(
   1506     VkDevice,
   1507     VkSwapchainKHR swapchain_handle,
   1508     VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
   1509     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
   1510     VkResult result = VK_SUCCESS;
   1511 
   1512     pDisplayTimingProperties->refreshDuration =
   1513             static_cast<uint64_t>(swapchain.refresh_duration);
   1514 
   1515     return result;
   1516 }
   1517 
   1518 VKAPI_ATTR
   1519 VkResult GetPastPresentationTimingGOOGLE(
   1520     VkDevice,
   1521     VkSwapchainKHR swapchain_handle,
   1522     uint32_t* count,
   1523     VkPastPresentationTimingGOOGLE* timings) {
   1524     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
   1525     ANativeWindow* window = swapchain.surface.window.get();
   1526     VkResult result = VK_SUCCESS;
   1527 
   1528     if (!swapchain.frame_timestamps_enabled) {
   1529         ALOGV("Calling native_window_enable_frame_timestamps(true)");
   1530         native_window_enable_frame_timestamps(window, true);
   1531         swapchain.frame_timestamps_enabled = true;
   1532     }
   1533 
   1534     if (timings) {
   1535         // TODO(ianelliott): plumb return value (e.g. VK_INCOMPLETE)
   1536         copy_ready_timings(swapchain, count, timings);
   1537     } else {
   1538         *count = get_num_ready_timings(swapchain);
   1539     }
   1540 
   1541     return result;
   1542 }
   1543 
   1544 VKAPI_ATTR
   1545 VkResult GetSwapchainStatusKHR(
   1546     VkDevice,
   1547     VkSwapchainKHR swapchain_handle) {
   1548     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
   1549     VkResult result = VK_SUCCESS;
   1550 
   1551     if (swapchain.surface.swapchain_handle != swapchain_handle) {
   1552         return VK_ERROR_OUT_OF_DATE_KHR;
   1553     }
   1554 
   1555     // TODO(chrisforbes): Implement this function properly
   1556 
   1557     return result;
   1558 }
   1559 
   1560 VKAPI_ATTR void SetHdrMetadataEXT(
   1561     VkDevice device,
   1562     uint32_t swapchainCount,
   1563     const VkSwapchainKHR* pSwapchains,
   1564     const VkHdrMetadataEXT* pHdrMetadataEXTs) {
   1565     // TODO: courtneygo: implement actual function
   1566     (void)device;
   1567     (void)swapchainCount;
   1568     (void)pSwapchains;
   1569     (void)pHdrMetadataEXTs;
   1570     return;
   1571 }
   1572 
   1573 }  // namespace driver
   1574 }  // namespace vulkan
   1575