swapchain.cpp revision 55bc09788673f8f35bfb2450028827d5ea76c1d3
1eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams/*
2eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams * Copyright 2015 The Android Open Source Project
3eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams *
4eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams * Licensed under the Apache License, Version 2.0 (the "License");
5eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams * you may not use this file except in compliance with the License.
6eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams * You may obtain a copy of the License at
7eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams *
8eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams *      http://www.apache.org/licenses/LICENSE-2.0
9eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams *
10eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams * Unless required by applicable law or agreed to in writing, software
11eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams * distributed under the License is distributed on an "AS IS" BASIS,
12eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams * See the License for the specific language governing permissions and
14eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams * limitations under the License.
15eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams */
16eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
17eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams#include <algorithm>
18eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams#include <memory>
19eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
20eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams#include <gui/BufferQueue.h>
21eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams#include <log/log.h>
22807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams#include <sync/sync.h>
23eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
24709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#include "loader.h"
250b575de8ed0b628d84d256f5846500b0385979bdTim Murray
260b575de8ed0b628d84d256f5846500b0385979bdTim Murrayusing namespace vulkan;
27eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
28eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams// TODO(jessehall): Currently we don't have a good error code for when a native
290b575de8ed0b628d84d256f5846500b0385979bdTim Murray// window operation fails. Just returning INITIALIZATION_FAILED for now. Later
30eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams// versions (post SDK 0.9) of the API/extension have a better error code.
31b0934b67b95cc27e2358c2aa4db5f7c1067c8f9bStephen Hines// When updating to that version, audit all error returns.
32b0934b67b95cc27e2358c2aa4db5f7c1067c8f9bStephen Hines
33b0934b67b95cc27e2358c2aa4db5f7c1067c8f9bStephen Hinesnamespace {
34b0934b67b95cc27e2358c2aa4db5f7c1067c8f9bStephen Hines
35a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk// ----------------------------------------------------------------------------
363a25fdd3786c1a08b783d8a83ef94b756347ff5cTim Murray// These functions/classes form an adaptor that allows objects to be refcounted
377ac2a4dda4d20ca1f1b714e129a3a08f63178c18Jason Sams// by both android::sp<> and std::shared_ptr<> simultaneously, and delegates
382bd78f2d3e0a94a98dc03502decadfd2e17a70c8Miao Wang// allocation of the shared_ptr<> control structure to VkAllocationCallbacks.
39a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk// The
40eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams// platform holds a reference to the ANativeWindow using its embedded reference
41eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams// count, and the ANativeWindow implementation holds references to the
42eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams// ANativeWindowBuffers using their embedded reference counts, so the
43eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams// shared_ptr *must* cooperate with these and hold at least one reference to
44eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams// the object using the embedded reference count.
45eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
46eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Samstemplate <typename T>
47eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Samsstruct NativeBaseDeleter {
48eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    void operator()(T* obj) { obj->common.decRef(&obj->common); }
49eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams};
50eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
51eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Samstemplate <typename Host>
52eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Samsstruct AllocScope {};
5393eacc7ce0aad4314b4cb41a281f59ce54bb3286Jason Sams
54eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Samstemplate <>
55a614ae175bbf97201b5e18984d814a1d3e86faa8Jason Samsstruct AllocScope<VkInstance> {
56a614ae175bbf97201b5e18984d814a1d3e86faa8Jason Sams    static const VkSystemAllocationScope kScope =
573a25fdd3786c1a08b783d8a83ef94b756347ff5cTim Murray        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE;
582bd78f2d3e0a94a98dc03502decadfd2e17a70c8Miao Wang};
593a25fdd3786c1a08b783d8a83ef94b756347ff5cTim Murray
6093eacc7ce0aad4314b4cb41a281f59ce54bb3286Jason Samstemplate <>
6193eacc7ce0aad4314b4cb41a281f59ce54bb3286Jason Samsstruct AllocScope<VkDevice> {
6293eacc7ce0aad4314b4cb41a281f59ce54bb3286Jason Sams    static const VkSystemAllocationScope kScope =
6393eacc7ce0aad4314b4cb41a281f59ce54bb3286Jason Sams        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE;
642bd78f2d3e0a94a98dc03502decadfd2e17a70c8Miao Wang};
652bd78f2d3e0a94a98dc03502decadfd2e17a70c8Miao Wang
6693eacc7ce0aad4314b4cb41a281f59ce54bb3286Jason Samstemplate <typename T>
67a614ae175bbf97201b5e18984d814a1d3e86faa8Jason Samsclass VulkanAllocator {
68c2cfe6abfc74befbaa4d2ca09024a27fbfb1f515Tim Murray   public:
69eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    typedef T value_type;
70a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk
71a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    VulkanAllocator(const VkAllocationCallbacks& allocator,
72b322033c13487a174bb9c26466e9684d1ff4de8dJason Sams                    VkSystemAllocationScope scope)
732bd78f2d3e0a94a98dc03502decadfd2e17a70c8Miao Wang        : allocator_(allocator), scope_(scope) {}
74eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
75eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    template <typename U>
7693eacc7ce0aad4314b4cb41a281f59ce54bb3286Jason Sams    explicit VulkanAllocator(const VulkanAllocator<U>& other)
77a614ae175bbf97201b5e18984d814a1d3e86faa8Jason Sams        : allocator_(other.allocator_), scope_(other.scope_) {}
78a614ae175bbf97201b5e18984d814a1d3e86faa8Jason Sams
7993eacc7ce0aad4314b4cb41a281f59ce54bb3286Jason Sams    T* allocate(size_t n) const {
80a614ae175bbf97201b5e18984d814a1d3e86faa8Jason Sams        T* p = static_cast<T*>(allocator_.pfnAllocation(
81a614ae175bbf97201b5e18984d814a1d3e86faa8Jason Sams            allocator_.pUserData, n * sizeof(T), alignof(T), scope_));
82ddceab9a001f07a3395226c5e06e3b420720af0fJason Sams        if (!p)
83ddceab9a001f07a3395226c5e06e3b420720af0fJason Sams            throw std::bad_alloc();
84eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams        return p;
85eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    }
86eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    void deallocate(T* p, size_t) const noexcept {
8747a5881b8f85d65c74f2471fe6261d4cdb3dce5eMiao Wang        return allocator_.pfnFree(allocator_.pUserData, p);
8847a5881b8f85d65c74f2471fe6261d4cdb3dce5eMiao Wang    }
8947a5881b8f85d65c74f2471fe6261d4cdb3dce5eMiao Wang
9047a5881b8f85d65c74f2471fe6261d4cdb3dce5eMiao Wang   private:
9147a5881b8f85d65c74f2471fe6261d4cdb3dce5eMiao Wang    template <typename U>
92bc9dc27b84f4e5c72d4dbe8a8e01af87dd780f79Jason Sams    friend class VulkanAllocator;
93bc9dc27b84f4e5c72d4dbe8a8e01af87dd780f79Jason Sams    const VkAllocationCallbacks& allocator_;
94eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    const VkSystemAllocationScope scope_;
95eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams};
96eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
97eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Samstemplate <typename T, typename Host>
98eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Samsstd::shared_ptr<T> InitSharedPtr(Host host, T* obj) {
99eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    try {
100eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams        obj->common.incRef(&obj->common);
101eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams        return std::shared_ptr<T>(
102eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams            obj, NativeBaseDeleter<T>(),
103eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams            VulkanAllocator<T>(*GetAllocator(host), AllocScope<Host>::kScope));
104eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    } catch (std::bad_alloc&) {
105733396b67724162844ea2785c7495115dc5ee8d8Jason Sams        obj->common.decRef(&obj->common);
106733396b67724162844ea2785c7495115dc5ee8d8Jason Sams        return nullptr;
1077ac2a4dda4d20ca1f1b714e129a3a08f63178c18Jason Sams    }
1087ac2a4dda4d20ca1f1b714e129a3a08f63178c18Jason Sams}
1097ac2a4dda4d20ca1f1b714e129a3a08f63178c18Jason Sams
1107ac2a4dda4d20ca1f1b714e129a3a08f63178c18Jason Samsconst VkSurfaceTransformFlagsKHR kSupportedTransforms =
111eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR |
112eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
113eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR |
114099bc262f862cdeb547cf8a78fe9e0e92560f437Tim Murray    VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
115099bc262f862cdeb547cf8a78fe9e0e92560f437Tim Murray    // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
116eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR |
117eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
118eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR |
119eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR |
120099bc262f862cdeb547cf8a78fe9e0e92560f437Tim Murray    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
121eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
122eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason SamsVkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) {
1233bbc0fd40264ddae1592706d9023865b7b3e3195Jason Sams    // Native and Vulkan transforms are isomorphic, but are represented
1243bbc0fd40264ddae1592706d9023865b7b3e3195Jason Sams    // differently. Vulkan transforms are built up of an optional horizontal
1253bbc0fd40264ddae1592706d9023865b7b3e3195Jason Sams    // mirror, followed by a clockwise 0/90/180/270-degree rotation. Native
126eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    // transforms are built up from a horizontal flip, vertical flip, and
127807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams    // 90-degree rotation, all optional but always in that order.
128807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams
129099bc262f862cdeb547cf8a78fe9e0e92560f437Tim Murray    // TODO(jessehall): For now, only support pure rotations, not
130099bc262f862cdeb547cf8a78fe9e0e92560f437Tim Murray    // flip or flip-and-rotate, until I have more time to test them and build
131807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams    // sample code. As far as I know we never actually use anything besides
132807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams    // pure rotations anyway.
133807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams
134807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams    switch (native) {
135099bc262f862cdeb547cf8a78fe9e0e92560f437Tim Murray        case 0:  // 0x0
136807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams            return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
137807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams        // case NATIVE_WINDOW_TRANSFORM_FLIP_H:  // 0x1
1383bbc0fd40264ddae1592706d9023865b7b3e3195Jason Sams        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR;
1393bbc0fd40264ddae1592706d9023865b7b3e3195Jason Sams        // case NATIVE_WINDOW_TRANSFORM_FLIP_V:  // 0x2
1403bbc0fd40264ddae1592706d9023865b7b3e3195Jason Sams        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR;
141807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams        case NATIVE_WINDOW_TRANSFORM_ROT_180:  // FLIP_H | FLIP_V
142807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams            return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
143807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams        case NATIVE_WINDOW_TRANSFORM_ROT_90:  // 0x4
144807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams            return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
145807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams        // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90:
146807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR;
147807fdc4b6f3fb893015ee136565d6151bb2332d3Jason Sams        // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90:
14874a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
14974a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk        case NATIVE_WINDOW_TRANSFORM_ROT_270:  // FLIP_H | FLIP_V | ROT_90
150099bc262f862cdeb547cf8a78fe9e0e92560f437Tim Murray            return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
15174a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk        case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
15274a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk        default:
15374a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk            return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
15474a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk    }
15574a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk}
15674a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk
15774a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk// ----------------------------------------------------------------------------
15874a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk
15974a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchoukstruct Surface {
16074a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk    std::shared_ptr<ANativeWindow> window;
16174a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk};
16274a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk
1633bbc0fd40264ddae1592706d9023865b7b3e3195Jason SamsVkSurfaceKHR HandleFromSurface(Surface* surface) {
16474a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk    return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface));
16574a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk}
16674a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk
1673bbc0fd40264ddae1592706d9023865b7b3e3195Jason SamsSurface* SurfaceFromHandle(VkSurfaceKHR handle) {
16874a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk    return reinterpret_cast<Surface*>(handle);
169cc8cea7477352898921044483a6c803e25d02665Miao Wang}
170cc8cea7477352898921044483a6c803e25d02665Miao Wang
171cc8cea7477352898921044483a6c803e25d02665Miao Wangstruct Swapchain {
172cc8cea7477352898921044483a6c803e25d02665Miao Wang    Swapchain(Surface& surface_, uint32_t num_images_)
173cc8cea7477352898921044483a6c803e25d02665Miao Wang        : surface(surface_), num_images(num_images_) {}
174cc8cea7477352898921044483a6c803e25d02665Miao Wang
175cc8cea7477352898921044483a6c803e25d02665Miao Wang    Surface& surface;
176cc8cea7477352898921044483a6c803e25d02665Miao Wang    uint32_t num_images;
177cc8cea7477352898921044483a6c803e25d02665Miao Wang
178eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    struct Image {
179a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams        Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
180a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams        VkImage image;
181eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams        std::shared_ptr<ANativeWindowBuffer> buffer;
182a36c50a6ab87f4c9049318d4c6c8ec7b0a1e6e12Jason Sams        // The fence is only valid when the buffer is dequeued, and should be
183a36c50a6ab87f4c9049318d4c6c8ec7b0a1e6e12Jason Sams        // -1 any other time. When valid, we own the fd, and must ensure it is
184a36c50a6ab87f4c9049318d4c6c8ec7b0a1e6e12Jason Sams        // closed: either by closing it explicitly when queueing the buffer,
185eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams        // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
186bc9dc27b84f4e5c72d4dbe8a8e01af87dd780f79Jason Sams        int dequeue_fence;
187bc9dc27b84f4e5c72d4dbe8a8e01af87dd780f79Jason Sams        bool dequeued;
188bc9dc27b84f4e5c72d4dbe8a8e01af87dd780f79Jason Sams    } images[android::BufferQueue::NUM_BUFFER_SLOTS];
189eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams};
190eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
191VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
192    return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
193}
194
195Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
196    return reinterpret_cast<Swapchain*>(handle);
197}
198
199}  // anonymous namespace
200
201namespace vulkan {
202
203VKAPI_ATTR
204VkResult CreateAndroidSurfaceKHR_Bottom(
205    VkInstance instance,
206    const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
207    const VkAllocationCallbacks* allocator,
208    VkSurfaceKHR* out_surface) {
209    if (!allocator)
210        allocator = GetAllocator(instance);
211    void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
212                                         alignof(Surface),
213                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
214    if (!mem)
215        return VK_ERROR_OUT_OF_HOST_MEMORY;
216    Surface* surface = new (mem) Surface;
217
218    surface->window = InitSharedPtr(instance, pCreateInfo->window);
219    if (!surface->window) {
220        ALOGE("surface creation failed: out of memory");
221        surface->~Surface();
222        allocator->pfnFree(allocator->pUserData, surface);
223        return VK_ERROR_OUT_OF_HOST_MEMORY;
224    }
225
226    // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
227    int err =
228        native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
229    if (err != 0) {
230        // TODO(jessehall): Improve error reporting. Can we enumerate possible
231        // errors and translate them to valid Vulkan result codes?
232        ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
233              err);
234        surface->~Surface();
235        allocator->pfnFree(allocator->pUserData, surface);
236        return VK_ERROR_INITIALIZATION_FAILED;
237    }
238
239    *out_surface = HandleFromSurface(surface);
240    return VK_SUCCESS;
241}
242
243VKAPI_ATTR
244void DestroySurfaceKHR_Bottom(VkInstance instance,
245                              VkSurfaceKHR surface_handle,
246                              const VkAllocationCallbacks* allocator) {
247    Surface* surface = SurfaceFromHandle(surface_handle);
248    if (!surface)
249        return;
250    native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL);
251    surface->~Surface();
252    if (!allocator)
253        allocator = GetAllocator(instance);
254    allocator->pfnFree(allocator->pUserData, surface);
255}
256
257VKAPI_ATTR
258VkResult GetPhysicalDeviceSurfaceSupportKHR_Bottom(VkPhysicalDevice /*pdev*/,
259                                                   uint32_t /*queue_family*/,
260                                                   VkSurfaceKHR /*surface*/,
261                                                   VkBool32* supported) {
262    *supported = VK_TRUE;
263    return VK_SUCCESS;
264}
265
266VKAPI_ATTR
267VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Bottom(
268    VkPhysicalDevice /*pdev*/,
269    VkSurfaceKHR surface,
270    VkSurfaceCapabilitiesKHR* capabilities) {
271    int err;
272    ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
273
274    int width, height;
275    err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
276    if (err != 0) {
277        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
278              strerror(-err), err);
279        return VK_ERROR_INITIALIZATION_FAILED;
280    }
281    err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
282    if (err != 0) {
283        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
284              strerror(-err), err);
285        return VK_ERROR_INITIALIZATION_FAILED;
286    }
287
288    int transform_hint;
289    err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
290    if (err != 0) {
291        ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
292              strerror(-err), err);
293        return VK_ERROR_INITIALIZATION_FAILED;
294    }
295
296    // TODO(jessehall): Figure out what the min/max values should be.
297    capabilities->minImageCount = 2;
298    capabilities->maxImageCount = 3;
299
300    capabilities->currentExtent =
301        VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
302
303    // TODO(jessehall): Figure out what the max extent should be. Maximum
304    // texture dimension maybe?
305    capabilities->minImageExtent = VkExtent2D{1, 1};
306    capabilities->maxImageExtent = VkExtent2D{4096, 4096};
307
308    capabilities->maxImageArrayLayers = 1;
309
310    capabilities->supportedTransforms = kSupportedTransforms;
311    capabilities->currentTransform =
312        TranslateNativeToVulkanTransform(transform_hint);
313
314    // On Android, window composition is a WindowManager property, not something
315    // associated with the bufferqueue. It can't be changed from here.
316    capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
317
318    // TODO(jessehall): I think these are right, but haven't thought hard about
319    // it. Do we need to query the driver for support of any of these?
320    // Currently not included:
321    // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
322    // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
323    // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
324    capabilities->supportedUsageFlags =
325        VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
326        VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
327        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
328        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
329
330    return VK_SUCCESS;
331}
332
333VKAPI_ATTR
334VkResult GetPhysicalDeviceSurfaceFormatsKHR_Bottom(
335    VkPhysicalDevice /*pdev*/,
336    VkSurfaceKHR /*surface*/,
337    uint32_t* count,
338    VkSurfaceFormatKHR* formats) {
339    // TODO(jessehall): Fill out the set of supported formats. Longer term, add
340    // a new gralloc method to query whether a (format, usage) pair is
341    // supported, and check that for each gralloc format that corresponds to a
342    // Vulkan format. Shorter term, just add a few more formats to the ones
343    // hardcoded below.
344
345    const VkSurfaceFormatKHR kFormats[] = {
346        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
347        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
348        {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
349    };
350    const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
351
352    VkResult result = VK_SUCCESS;
353    if (formats) {
354        if (*count < kNumFormats)
355            result = VK_INCOMPLETE;
356        std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
357    }
358    *count = kNumFormats;
359    return result;
360}
361
362VKAPI_ATTR
363VkResult GetPhysicalDeviceSurfacePresentModesKHR_Bottom(
364    VkPhysicalDevice /*pdev*/,
365    VkSurfaceKHR /*surface*/,
366    uint32_t* count,
367    VkPresentModeKHR* modes) {
368    const VkPresentModeKHR kModes[] = {
369        VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
370    };
371    const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
372
373    VkResult result = VK_SUCCESS;
374    if (modes) {
375        if (*count < kNumModes)
376            result = VK_INCOMPLETE;
377        std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
378    }
379    *count = kNumModes;
380    return result;
381}
382
383VKAPI_ATTR
384VkResult CreateSwapchainKHR_Bottom(VkDevice device,
385                                   const VkSwapchainCreateInfoKHR* create_info,
386                                   const VkAllocationCallbacks* allocator,
387                                   VkSwapchainKHR* swapchain_handle) {
388    int err;
389    VkResult result = VK_SUCCESS;
390
391    if (!allocator)
392        allocator = GetAllocator(device);
393
394    ALOGV_IF(create_info->imageArrayLayers != 1,
395             "Swapchain imageArrayLayers (%u) != 1 not supported",
396             create_info->imageArrayLayers);
397
398    ALOGE_IF(create_info->imageColorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR,
399             "color spaces other than SRGB_NONLINEAR not yet implemented");
400    ALOGE_IF(create_info->oldSwapchain,
401             "swapchain re-creation not yet implemented");
402    ALOGE_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
403             "swapchain preTransform %d not supported",
404             create_info->preTransform);
405    ALOGW_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
406               create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
407             "swapchain present mode %d not supported",
408             create_info->presentMode);
409
410    // -- Configure the native window --
411
412    Surface& surface = *SurfaceFromHandle(create_info->surface);
413    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
414
415    int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
416    switch (create_info->imageFormat) {
417        case VK_FORMAT_R8G8B8A8_UNORM:
418        case VK_FORMAT_R8G8B8A8_SRGB:
419            native_format = HAL_PIXEL_FORMAT_RGBA_8888;
420            break;
421        case VK_FORMAT_R5G6B5_UNORM_PACK16:
422            native_format = HAL_PIXEL_FORMAT_RGB_565;
423            break;
424        default:
425            ALOGE("unsupported swapchain format %d", create_info->imageFormat);
426            break;
427    }
428    err = native_window_set_buffers_format(surface.window.get(), native_format);
429    if (err != 0) {
430        // TODO(jessehall): Improve error reporting. Can we enumerate possible
431        // errors and translate them to valid Vulkan result codes?
432        ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
433              native_format, strerror(-err), err);
434        return VK_ERROR_INITIALIZATION_FAILED;
435    }
436    err = native_window_set_buffers_data_space(surface.window.get(),
437                                               HAL_DATASPACE_SRGB_LINEAR);
438    if (err != 0) {
439        // TODO(jessehall): Improve error reporting. Can we enumerate possible
440        // errors and translate them to valid Vulkan result codes?
441        ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
442              HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err);
443        return VK_ERROR_INITIALIZATION_FAILED;
444    }
445
446    err = native_window_set_buffers_dimensions(
447        surface.window.get(), static_cast<int>(create_info->imageExtent.width),
448        static_cast<int>(create_info->imageExtent.height));
449    if (err != 0) {
450        // TODO(jessehall): Improve error reporting. Can we enumerate possible
451        // errors and translate them to valid Vulkan result codes?
452        ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
453              create_info->imageExtent.width, create_info->imageExtent.height,
454              strerror(-err), err);
455        return VK_ERROR_INITIALIZATION_FAILED;
456    }
457
458    err = native_window_set_scaling_mode(
459        surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
460    if (err != 0) {
461        // TODO(jessehall): Improve error reporting. Can we enumerate possible
462        // errors and translate them to valid Vulkan result codes?
463        ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
464              strerror(-err), err);
465        return VK_ERROR_INITIALIZATION_FAILED;
466    }
467
468    uint32_t min_undequeued_buffers;
469    err = surface.window->query(
470        surface.window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
471        reinterpret_cast<int*>(&min_undequeued_buffers));
472    if (err != 0) {
473        // TODO(jessehall): Improve error reporting. Can we enumerate possible
474        // errors and translate them to valid Vulkan result codes?
475        ALOGE("window->query failed: %s (%d)", strerror(-err), err);
476        return VK_ERROR_INITIALIZATION_FAILED;
477    }
478    // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
479    // async mode or not, and assumes not. But in async mode, the BufferQueue
480    // requires an extra undequeued buffer.
481    // See BufferQueueCore::getMinUndequeuedBufferCountLocked().
482    if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
483        min_undequeued_buffers += 1;
484
485    uint32_t num_images =
486        (create_info->minImageCount - 1) + min_undequeued_buffers;
487    err = native_window_set_buffer_count(surface.window.get(), num_images);
488    if (err != 0) {
489        // TODO(jessehall): Improve error reporting. Can we enumerate possible
490        // errors and translate them to valid Vulkan result codes?
491        ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
492              err);
493        return VK_ERROR_INITIALIZATION_FAILED;
494    }
495
496    int gralloc_usage = 0;
497    // TODO(jessehall): Remove conditional once all drivers have been updated
498    if (dispatch.GetSwapchainGrallocUsageANDROID) {
499        result = dispatch.GetSwapchainGrallocUsageANDROID(
500            device, create_info->imageFormat, create_info->imageUsage,
501            &gralloc_usage);
502        if (result != VK_SUCCESS) {
503            ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
504            return VK_ERROR_INITIALIZATION_FAILED;
505        }
506    } else {
507        gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
508    }
509    err = native_window_set_usage(surface.window.get(), gralloc_usage);
510    if (err != 0) {
511        // TODO(jessehall): Improve error reporting. Can we enumerate possible
512        // errors and translate them to valid Vulkan result codes?
513        ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
514        return VK_ERROR_INITIALIZATION_FAILED;
515    }
516
517    err = surface.window->setSwapInterval(
518        surface.window.get(),
519        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1);
520    if (err != 0) {
521        // TODO(jessehall): Improve error reporting. Can we enumerate possible
522        // errors and translate them to valid Vulkan result codes?
523        ALOGE("native_window->setSwapInterval failed: %s (%d)", strerror(-err),
524              err);
525        return VK_ERROR_INITIALIZATION_FAILED;
526    }
527
528    // -- Allocate our Swapchain object --
529    // After this point, we must deallocate the swapchain on error.
530
531    void* mem = allocator->pfnAllocation(allocator->pUserData,
532                                         sizeof(Swapchain), alignof(Swapchain),
533                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
534    if (!mem)
535        return VK_ERROR_OUT_OF_HOST_MEMORY;
536    Swapchain* swapchain = new (mem) Swapchain(surface, num_images);
537
538    // -- Dequeue all buffers and create a VkImage for each --
539    // Any failures during or after this must cancel the dequeued buffers.
540
541    VkNativeBufferANDROID image_native_buffer = {
542#pragma clang diagnostic push
543#pragma clang diagnostic ignored "-Wold-style-cast"
544        .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
545#pragma clang diagnostic pop
546        .pNext = nullptr,
547    };
548    VkImageCreateInfo image_create = {
549        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
550        .pNext = &image_native_buffer,
551        .imageType = VK_IMAGE_TYPE_2D,
552        .format = create_info->imageFormat,
553        .extent = {0, 0, 1},
554        .mipLevels = 1,
555        .arrayLayers = 1,
556        .samples = VK_SAMPLE_COUNT_1_BIT,
557        .tiling = VK_IMAGE_TILING_OPTIMAL,
558        .usage = create_info->imageUsage,
559        .flags = 0,
560        .sharingMode = create_info->imageSharingMode,
561        .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
562        .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
563    };
564
565    for (uint32_t i = 0; i < num_images; i++) {
566        Swapchain::Image& img = swapchain->images[i];
567
568        ANativeWindowBuffer* buffer;
569        err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
570                                            &img.dequeue_fence);
571        if (err != 0) {
572            // TODO(jessehall): Improve error reporting. Can we enumerate
573            // possible errors and translate them to valid Vulkan result codes?
574            ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
575            result = VK_ERROR_INITIALIZATION_FAILED;
576            break;
577        }
578        img.buffer = InitSharedPtr(device, buffer);
579        if (!img.buffer) {
580            ALOGE("swapchain creation failed: out of memory");
581            surface.window->cancelBuffer(surface.window.get(), buffer,
582                                         img.dequeue_fence);
583            result = VK_ERROR_OUT_OF_HOST_MEMORY;
584            break;
585        }
586        img.dequeued = true;
587
588        image_create.extent =
589            VkExtent3D{static_cast<uint32_t>(img.buffer->width),
590                       static_cast<uint32_t>(img.buffer->height),
591                       1};
592        image_native_buffer.handle = img.buffer->handle;
593        image_native_buffer.stride = img.buffer->stride;
594        image_native_buffer.format = img.buffer->format;
595        image_native_buffer.usage = img.buffer->usage;
596
597        result =
598            dispatch.CreateImage(device, &image_create, nullptr, &img.image);
599        if (result != VK_SUCCESS) {
600            ALOGD("vkCreateImage w/ native buffer failed: %u", result);
601            break;
602        }
603    }
604
605    // -- Cancel all buffers, returning them to the queue --
606    // If an error occurred before, also destroy the VkImage and release the
607    // buffer reference. Otherwise, we retain a strong reference to the buffer.
608    //
609    // TODO(jessehall): The error path here is the same as DestroySwapchain,
610    // but not the non-error path. Should refactor/unify.
611    for (uint32_t i = 0; i < num_images; i++) {
612        Swapchain::Image& img = swapchain->images[i];
613        if (img.dequeued) {
614            surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
615                                         img.dequeue_fence);
616            img.dequeue_fence = -1;
617            img.dequeued = false;
618        }
619        if (result != VK_SUCCESS) {
620            if (img.image)
621                dispatch.DestroyImage(device, img.image, nullptr);
622        }
623    }
624
625    if (result != VK_SUCCESS) {
626        swapchain->~Swapchain();
627        allocator->pfnFree(allocator->pUserData, swapchain);
628        return result;
629    }
630
631    *swapchain_handle = HandleFromSwapchain(swapchain);
632    return VK_SUCCESS;
633}
634
635VKAPI_ATTR
636void DestroySwapchainKHR_Bottom(VkDevice device,
637                                VkSwapchainKHR swapchain_handle,
638                                const VkAllocationCallbacks* allocator) {
639    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
640    Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
641    const std::shared_ptr<ANativeWindow>& window = swapchain->surface.window;
642
643    for (uint32_t i = 0; i < swapchain->num_images; i++) {
644        Swapchain::Image& img = swapchain->images[i];
645        if (img.dequeued) {
646            window->cancelBuffer(window.get(), img.buffer.get(),
647                                 img.dequeue_fence);
648            img.dequeue_fence = -1;
649            img.dequeued = false;
650        }
651        if (img.image) {
652            dispatch.DestroyImage(device, img.image, nullptr);
653        }
654    }
655
656    if (!allocator)
657        allocator = GetAllocator(device);
658    swapchain->~Swapchain();
659    allocator->pfnFree(allocator->pUserData, swapchain);
660}
661
662VKAPI_ATTR
663VkResult GetSwapchainImagesKHR_Bottom(VkDevice,
664                                      VkSwapchainKHR swapchain_handle,
665                                      uint32_t* count,
666                                      VkImage* images) {
667    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
668    VkResult result = VK_SUCCESS;
669    if (images) {
670        uint32_t n = swapchain.num_images;
671        if (*count < swapchain.num_images) {
672            n = *count;
673            result = VK_INCOMPLETE;
674        }
675        for (uint32_t i = 0; i < n; i++)
676            images[i] = swapchain.images[i].image;
677    }
678    *count = swapchain.num_images;
679    return result;
680}
681
682VKAPI_ATTR
683VkResult AcquireNextImageKHR_Bottom(VkDevice device,
684                                    VkSwapchainKHR swapchain_handle,
685                                    uint64_t timeout,
686                                    VkSemaphore semaphore,
687                                    VkFence vk_fence,
688                                    uint32_t* image_index) {
689    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
690    ANativeWindow* window = swapchain.surface.window.get();
691    VkResult result;
692    int err;
693
694    ALOGW_IF(
695        timeout != UINT64_MAX,
696        "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
697
698    ANativeWindowBuffer* buffer;
699    int fence_fd;
700    err = window->dequeueBuffer(window, &buffer, &fence_fd);
701    if (err != 0) {
702        // TODO(jessehall): Improve error reporting. Can we enumerate possible
703        // errors and translate them to valid Vulkan result codes?
704        ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
705        return VK_ERROR_INITIALIZATION_FAILED;
706    }
707
708    uint32_t idx;
709    for (idx = 0; idx < swapchain.num_images; idx++) {
710        if (swapchain.images[idx].buffer.get() == buffer) {
711            swapchain.images[idx].dequeued = true;
712            swapchain.images[idx].dequeue_fence = fence_fd;
713            break;
714        }
715    }
716    if (idx == swapchain.num_images) {
717        ALOGE("dequeueBuffer returned unrecognized buffer");
718        window->cancelBuffer(window, buffer, fence_fd);
719        return VK_ERROR_OUT_OF_DATE_KHR;
720    }
721
722    int fence_clone = -1;
723    if (fence_fd != -1) {
724        fence_clone = dup(fence_fd);
725        if (fence_clone == -1) {
726            ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
727                  strerror(errno), errno);
728            sync_wait(fence_fd, -1 /* forever */);
729        }
730    }
731
732    result = GetDriverDispatch(device).AcquireImageANDROID(
733        device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
734    if (result != VK_SUCCESS) {
735        // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
736        // even if the call fails. We could close it ourselves on failure, but
737        // that would create a race condition if the driver closes it on a
738        // failure path: some other thread might create an fd with the same
739        // number between the time the driver closes it and the time we close
740        // it. We must assume one of: the driver *always* closes it even on
741        // failure, or *never* closes it on failure.
742        window->cancelBuffer(window, buffer, fence_fd);
743        swapchain.images[idx].dequeued = false;
744        swapchain.images[idx].dequeue_fence = -1;
745        return result;
746    }
747
748    *image_index = idx;
749    return VK_SUCCESS;
750}
751
752VKAPI_ATTR
753VkResult QueuePresentKHR_Bottom(VkQueue queue,
754                                const VkPresentInfoKHR* present_info) {
755    ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
756             "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
757             present_info->sType);
758    ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
759
760    const DriverDispatchTable& dispatch = GetDriverDispatch(queue);
761    VkResult final_result = VK_SUCCESS;
762    for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
763        Swapchain& swapchain =
764            *SwapchainFromHandle(present_info->pSwapchains[sc]);
765        ANativeWindow* window = swapchain.surface.window.get();
766        uint32_t image_idx = present_info->pImageIndices[sc];
767        Swapchain::Image& img = swapchain.images[image_idx];
768        VkResult result;
769        int err;
770
771        int fence = -1;
772        result = dispatch.QueueSignalReleaseImageANDROID(
773            queue, present_info->waitSemaphoreCount,
774            present_info->pWaitSemaphores, img.image, &fence);
775        if (result != VK_SUCCESS) {
776            ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
777            if (present_info->pResults)
778                present_info->pResults[sc] = result;
779            if (final_result == VK_SUCCESS)
780                final_result = result;
781            // TODO(jessehall): What happens to the buffer here? Does the app
782            // still own it or not, i.e. should we cancel the buffer? Hard to
783            // do correctly without synchronizing, though I guess we could wait
784            // for the queue to idle.
785            continue;
786        }
787
788        err = window->queueBuffer(window, img.buffer.get(), fence);
789        if (err != 0) {
790            // TODO(jessehall): What now? We should probably cancel the buffer,
791            // I guess?
792            ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
793            if (present_info->pResults)
794                present_info->pResults[sc] = result;
795            if (final_result == VK_SUCCESS)
796                final_result = VK_ERROR_INITIALIZATION_FAILED;
797            continue;
798        }
799
800        if (img.dequeue_fence != -1) {
801            close(img.dequeue_fence);
802            img.dequeue_fence = -1;
803        }
804        img.dequeued = false;
805
806        if (present_info->pResults)
807            present_info->pResults[sc] = VK_SUCCESS;
808    }
809
810    return final_result;
811}
812
813}  // namespace vulkan
814