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