swapchain.cpp revision 5ae3abb3ca6728de04935b0c81bcdbdfc37b0d47
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// #define LOG_NDEBUG 0
18
19#include <algorithm>
20#include <memory>
21
22#include <gui/BufferQueue.h>
23#include <log/log.h>
24#include <sync/sync.h>
25
26#include "loader.h"
27
28using namespace vulkan;
29
30// TODO(jessehall): Currently we don't have a good error code for when a native
31// window operation fails. Just returning INITIALIZATION_FAILED for now. Later
32// versions (post SDK 0.9) of the API/extension have a better error code.
33// When updating to that version, audit all error returns.
34
35namespace {
36
37// ----------------------------------------------------------------------------
38// These functions/classes form an adaptor that allows objects to be refcounted
39// by both android::sp<> and std::shared_ptr<> simultaneously, and delegates
40// allocation of the shared_ptr<> control structure to VkAllocCallbacks. The
41// platform holds a reference to the ANativeWindow using its embedded reference
42// count, and the ANativeWindow implementation holds references to the
43// ANativeWindowBuffers using their embedded reference counts, so the
44// shared_ptr *must* cooperate with these and hold at least one reference to
45// the object using the embedded reference count.
46
47template <typename T>
48struct NativeBaseDeleter {
49    void operator()(T* obj) { obj->common.decRef(&obj->common); }
50};
51
52template <typename T>
53class VulkanAllocator {
54   public:
55    typedef T value_type;
56
57    explicit VulkanAllocator(VkDevice device) : device_(device) {}
58
59    template <typename U>
60    explicit VulkanAllocator(const VulkanAllocator<U>& other)
61        : device_(other.device_) {}
62
63    T* allocate(size_t n) const {
64        return static_cast<T*>(AllocDeviceMem(
65            device_, n * sizeof(T), alignof(T), VK_SYSTEM_ALLOC_TYPE_INTERNAL));
66    }
67    void deallocate(T* p, size_t) const { return FreeDeviceMem(device_, p); }
68
69   private:
70    template <typename U>
71    friend class VulkanAllocator;
72    VkDevice device_;
73};
74
75template <typename T>
76std::shared_ptr<T> InitSharedPtr(VkDevice device, T* obj) {
77    obj->common.incRef(&obj->common);
78    return std::shared_ptr<T>(obj, NativeBaseDeleter<T>(),
79                              VulkanAllocator<T>(device));
80}
81
82// ----------------------------------------------------------------------------
83
84struct Swapchain {
85    Swapchain(std::shared_ptr<ANativeWindow> window_, uint32_t num_images_)
86        : window(window_), num_images(num_images_) {}
87
88    std::shared_ptr<ANativeWindow> window;
89    uint32_t num_images;
90
91    struct Image {
92        Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
93        VkImage image;
94        std::shared_ptr<ANativeWindowBuffer> buffer;
95        // The fence is only valid when the buffer is dequeued, and should be
96        // -1 any other time. When valid, we own the fd, and must ensure it is
97        // closed: either by closing it explicitly when queueing the buffer,
98        // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
99        int dequeue_fence;
100        bool dequeued;
101    } images[android::BufferQueue::NUM_BUFFER_SLOTS];
102};
103
104VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
105    return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
106}
107
108Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
109    return reinterpret_cast<Swapchain*>(handle.handle);
110}
111
112}  // anonymous namespace
113
114namespace vulkan {
115
116VkResult GetPhysicalDeviceSurfaceSupportKHR(
117    VkPhysicalDevice /*pdev*/,
118    uint32_t /*queue_family*/,
119    const VkSurfaceDescriptionKHR* surface_desc,
120    VkBool32* supported) {
121// TODO(jessehall): Fix the header, preferrably upstream, so values added to
122// existing enums don't trigger warnings like this.
123#pragma clang diagnostic push
124#pragma clang diagnostic ignored "-Wold-style-cast"
125#pragma clang diagnostic ignored "-Wsign-conversion"
126    ALOGE_IF(
127        surface_desc->sType != VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR,
128        "vkGetPhysicalDeviceSurfaceSupportKHR: pSurfaceDescription->sType=%#x "
129        "not supported",
130        surface_desc->sType);
131#pragma clang diagnostic pop
132
133    const VkSurfaceDescriptionWindowKHR* window_desc =
134        reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(surface_desc);
135
136    // TODO(jessehall): Also check whether the physical device exports the
137    // VK_EXT_ANDROID_native_buffer extension. For now, assume it does.
138    *supported = (window_desc->platform == VK_PLATFORM_ANDROID_KHR &&
139                  !window_desc->pPlatformHandle &&
140                  static_cast<ANativeWindow*>(window_desc->pPlatformWindow)
141                          ->common.magic == ANDROID_NATIVE_WINDOW_MAGIC);
142
143    return VK_SUCCESS;
144}
145
146VkResult GetSurfacePropertiesKHR(VkDevice /*device*/,
147                                 const VkSurfaceDescriptionKHR* surface_desc,
148                                 VkSurfacePropertiesKHR* properties) {
149    const VkSurfaceDescriptionWindowKHR* window_desc =
150        reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(surface_desc);
151    ANativeWindow* window =
152        static_cast<ANativeWindow*>(window_desc->pPlatformWindow);
153
154    int err;
155
156    // TODO(jessehall): Currently the window must be connected for several
157    // queries -- including default dimensions -- to work, since Surface caches
158    // the queried values at connect() and queueBuffer(), and query() returns
159    // those cached values.
160    //
161    // The proposed refactoring to create a VkSurface object (bug 14596) will
162    // give us a place to connect once per window. If that doesn't end up
163    // happening, we'll probably need to maintain an internal list of windows
164    // that have swapchains created for them, search that list here, and
165    // only temporarily connect if the window doesn't have a swapchain.
166
167    bool disconnect = true;
168    err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
169    if (err == -EINVAL) {
170        // This is returned if the window is already connected, among other
171        // things. We'll just assume we're already connected and charge ahead.
172        // See TODO above, this is not cool.
173        ALOGW(
174            "vkGetSurfacePropertiesKHR: native_window_api_connect returned "
175            "-EINVAL, assuming already connected");
176        err = 0;
177        disconnect = false;
178    } else if (err != 0) {
179        // TODO(jessehall): Improve error reporting. Can we enumerate possible
180        // errors and translate them to valid Vulkan result codes?
181        return VK_ERROR_INITIALIZATION_FAILED;
182    }
183
184    int width, height;
185    err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
186    if (err != 0) {
187        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
188              strerror(-err), err);
189        if (disconnect)
190            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
191        return VK_ERROR_INITIALIZATION_FAILED;
192    }
193    err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
194    if (err != 0) {
195        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
196              strerror(-err), err);
197        if (disconnect)
198            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
199        return VK_ERROR_INITIALIZATION_FAILED;
200    }
201
202    if (disconnect)
203        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
204
205    properties->currentExtent = VkExtent2D{width, height};
206
207    // TODO(jessehall): Figure out what the min/max values should be.
208    properties->minImageCount = 2;
209    properties->maxImageCount = 3;
210
211    // TODO(jessehall): Figure out what the max extent should be. Maximum
212    // texture dimension maybe?
213    properties->minImageExtent = VkExtent2D{1, 1};
214    properties->maxImageExtent = VkExtent2D{4096, 4096};
215
216    // TODO(jessehall): We can support all transforms, fix this once
217    // implemented.
218    properties->supportedTransforms = VK_SURFACE_TRANSFORM_NONE_BIT_KHR;
219
220    // TODO(jessehall): Implement based on NATIVE_WINDOW_TRANSFORM_HINT.
221    properties->currentTransform = VK_SURFACE_TRANSFORM_NONE_KHR;
222
223    properties->maxImageArraySize = 1;
224
225    // TODO(jessehall): I think these are right, but haven't thought hard about
226    // it. Do we need to query the driver for support of any of these?
227    // Currently not included:
228    // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
229    // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
230    // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
231    properties->supportedUsageFlags =
232        VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT |
233        VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
234        VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
235        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
236
237    return VK_SUCCESS;
238}
239
240VkResult GetSurfaceFormatsKHR(VkDevice /*device*/,
241                              const VkSurfaceDescriptionKHR* /*surface_desc*/,
242                              uint32_t* count,
243                              VkSurfaceFormatKHR* formats) {
244    // TODO(jessehall): Fill out the set of supported formats. Open question
245    // whether we should query the driver for support -- how does it know what
246    // the consumer can support? Should we support formats that don't
247    // correspond to gralloc formats?
248
249    const VkSurfaceFormatKHR kFormats[] = {
250        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
251        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
252    };
253    const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
254
255    VkResult result = VK_SUCCESS;
256    if (formats) {
257        if (*count < kNumFormats)
258            result = VK_INCOMPLETE;
259        std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
260    }
261    *count = kNumFormats;
262    return result;
263}
264
265VkResult GetSurfacePresentModesKHR(
266    VkDevice /*device*/,
267    const VkSurfaceDescriptionKHR* /*surface_desc*/,
268    uint32_t* count,
269    VkPresentModeKHR* modes) {
270    const VkPresentModeKHR kModes[] = {
271        VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
272    };
273    const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
274
275    VkResult result = VK_SUCCESS;
276    if (modes) {
277        if (*count < kNumModes)
278            result = VK_INCOMPLETE;
279        std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
280    }
281    *count = kNumModes;
282    return result;
283}
284
285VkResult CreateSwapchainKHR(VkDevice device,
286                            const VkSwapchainCreateInfoKHR* create_info,
287                            VkSwapchainKHR* swapchain_handle) {
288    int err;
289    VkResult result = VK_SUCCESS;
290
291    ALOGV_IF(create_info->imageArraySize != 1,
292             "Swapchain imageArraySize (%u) != 1 not supported",
293             create_info->imageArraySize);
294
295    ALOGE_IF(create_info->imageFormat != VK_FORMAT_R8G8B8A8_UNORM,
296             "swapchain formats other than R8G8B8A8_UNORM not yet implemented");
297    ALOGE_IF(create_info->imageColorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR,
298             "color spaces other than SRGB_NONLINEAR not yet implemented");
299    ALOGE_IF(create_info->oldSwapchain,
300             "swapchain re-creation not yet implemented");
301    ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_NONE_KHR,
302             "swapchain preTransform not yet implemented");
303    ALOGE_IF(create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR,
304             "present modes other than FIFO are not yet implemented");
305
306    // -- Configure the native window --
307    // Failure paths from here on need to disconnect the window.
308
309    std::shared_ptr<ANativeWindow> window = InitSharedPtr(
310        device, static_cast<ANativeWindow*>(
311                    reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(
312                        create_info->pSurfaceDescription)
313                        ->pPlatformWindow));
314
315    // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
316    err = native_window_api_connect(window.get(), NATIVE_WINDOW_API_EGL);
317    if (err != 0) {
318        // TODO(jessehall): Improve error reporting. Can we enumerate possible
319        // errors and translate them to valid Vulkan result codes?
320        ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
321              err);
322        return VK_ERROR_INITIALIZATION_FAILED;
323    }
324
325    err = native_window_set_buffers_dimensions(window.get(),
326                                               create_info->imageExtent.width,
327                                               create_info->imageExtent.height);
328    if (err != 0) {
329        // TODO(jessehall): Improve error reporting. Can we enumerate possible
330        // errors and translate them to valid Vulkan result codes?
331        ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
332              create_info->imageExtent.width, create_info->imageExtent.height,
333              strerror(-err), err);
334        native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
335        return VK_ERROR_INITIALIZATION_FAILED;
336    }
337
338    uint32_t min_undequeued_buffers;
339    err = window->query(window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
340                        reinterpret_cast<int*>(&min_undequeued_buffers));
341    if (err != 0) {
342        // TODO(jessehall): Improve error reporting. Can we enumerate possible
343        // errors and translate them to valid Vulkan result codes?
344        ALOGE("window->query failed: %s (%d)", strerror(-err), err);
345        native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
346        return VK_ERROR_INITIALIZATION_FAILED;
347    }
348    uint32_t num_images =
349        (create_info->minImageCount - 1) + min_undequeued_buffers;
350    err = native_window_set_buffer_count(window.get(), num_images);
351    if (err != 0) {
352        // TODO(jessehall): Improve error reporting. Can we enumerate possible
353        // errors and translate them to valid Vulkan result codes?
354        ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
355              err);
356        native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
357        return VK_ERROR_INITIALIZATION_FAILED;
358    }
359
360    // TODO(jessehall): Do we need to call modify native_window_set_usage()
361    // based on create_info->imageUsageFlags?
362
363    // -- Allocate our Swapchain object --
364    // After this point, we must deallocate the swapchain on error.
365
366    void* mem = AllocDeviceMem(device, sizeof(Swapchain), alignof(Swapchain),
367                               VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
368    if (!mem) {
369        native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
370        return VK_ERROR_OUT_OF_HOST_MEMORY;
371    }
372    Swapchain* swapchain = new (mem) Swapchain(window, num_images);
373
374    // -- Dequeue all buffers and create a VkImage for each --
375    // Any failures during or after this must cancel the dequeued buffers.
376
377    VkNativeBufferANDROID image_native_buffer = {
378// TODO(jessehall): Figure out how to make extension headers not horrible.
379#pragma clang diagnostic push
380#pragma clang diagnostic ignored "-Wold-style-cast"
381        .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
382#pragma clang diagnostic pop
383        .pNext = nullptr,
384    };
385    VkImageCreateInfo image_create = {
386        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
387        .pNext = &image_native_buffer,
388        .imageType = VK_IMAGE_TYPE_2D,
389        .format = VK_FORMAT_R8G8B8A8_UNORM,  // TODO(jessehall)
390        .extent = {0, 0, 1},
391        .mipLevels = 1,
392        .arraySize = 1,
393        .samples = 1,
394        .tiling = VK_IMAGE_TILING_OPTIMAL,
395        .usage = create_info->imageUsageFlags,
396        .flags = 0,
397        .sharingMode = create_info->sharingMode,
398        .queueFamilyCount = create_info->queueFamilyCount,
399        .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
400    };
401
402    const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
403    for (uint32_t i = 0; i < num_images; i++) {
404        Swapchain::Image& img = swapchain->images[i];
405
406        ANativeWindowBuffer* buffer;
407        err = window->dequeueBuffer(window.get(), &buffer, &img.dequeue_fence);
408        if (err != 0) {
409            // TODO(jessehall): Improve error reporting. Can we enumerate
410            // possible errors and translate them to valid Vulkan result codes?
411            ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
412            result = VK_ERROR_INITIALIZATION_FAILED;
413            break;
414        }
415        img.buffer = InitSharedPtr(device, buffer);
416        img.dequeued = true;
417
418        image_create.extent =
419            VkExtent3D{img.buffer->width, img.buffer->height, 1};
420        image_native_buffer.handle = img.buffer->handle;
421        image_native_buffer.stride = img.buffer->stride;
422        image_native_buffer.format = img.buffer->format;
423        image_native_buffer.usage = img.buffer->usage;
424
425        result = driver_vtbl.CreateImage(device, &image_create, &img.image);
426        if (result != VK_SUCCESS) {
427            ALOGD("vkCreateImage w/ native buffer failed: %u", result);
428            break;
429        }
430    }
431
432    // -- Cancel all buffers, returning them to the queue --
433    // If an error occurred before, also destroy the VkImage and release the
434    // buffer reference. Otherwise, we retain a strong reference to the buffer.
435    //
436    // TODO(jessehall): The error path here is the same as DestroySwapchain,
437    // but not the non-error path. Should refactor/unify.
438    for (uint32_t i = 0; i < num_images; i++) {
439        Swapchain::Image& img = swapchain->images[i];
440        if (img.dequeued) {
441            window->cancelBuffer(window.get(), img.buffer.get(),
442                                 img.dequeue_fence);
443            img.dequeue_fence = -1;
444            img.dequeued = false;
445        }
446        if (result != VK_SUCCESS) {
447            if (img.image)
448                driver_vtbl.DestroyImage(device, img.image);
449        }
450    }
451
452    if (result != VK_SUCCESS) {
453        native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
454        swapchain->~Swapchain();
455        FreeDeviceMem(device, swapchain);
456        return result;
457    }
458
459    *swapchain_handle = HandleFromSwapchain(swapchain);
460    return VK_SUCCESS;
461}
462
463VkResult DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle) {
464    const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
465    Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
466    const std::shared_ptr<ANativeWindow>& window = swapchain->window;
467
468    for (uint32_t i = 0; i < swapchain->num_images; i++) {
469        Swapchain::Image& img = swapchain->images[i];
470        if (img.dequeued) {
471            window->cancelBuffer(window.get(), img.buffer.get(),
472                                 img.dequeue_fence);
473            img.dequeue_fence = -1;
474            img.dequeued = false;
475        }
476        if (img.image) {
477            driver_vtbl.DestroyImage(device, img.image);
478        }
479    }
480
481    native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
482    swapchain->~Swapchain();
483    FreeDeviceMem(device, swapchain);
484
485    return VK_SUCCESS;
486}
487
488VkResult GetSwapchainImagesKHR(VkDevice,
489                               VkSwapchainKHR swapchain_handle,
490                               uint32_t* count,
491                               VkImage* images) {
492    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
493    VkResult result = VK_SUCCESS;
494    if (images) {
495        uint32_t n = swapchain.num_images;
496        if (*count < swapchain.num_images) {
497            n = *count;
498            result = VK_INCOMPLETE;
499        }
500        for (uint32_t i = 0; i < n; i++)
501            images[i] = swapchain.images[i].image;
502    }
503    *count = swapchain.num_images;
504    return result;
505}
506
507VkResult AcquireNextImageKHR(VkDevice device,
508                             VkSwapchainKHR swapchain_handle,
509                             uint64_t timeout,
510                             VkSemaphore semaphore,
511                             uint32_t* image_index) {
512    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
513    VkResult result;
514    int err;
515
516    ALOGW_IF(
517        timeout != UINT64_MAX,
518        "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
519
520    ANativeWindowBuffer* buffer;
521    int fence;
522    err = swapchain.window->dequeueBuffer(swapchain.window.get(), &buffer,
523                                          &fence);
524    if (err != 0) {
525        // TODO(jessehall): Improve error reporting. Can we enumerate possible
526        // errors and translate them to valid Vulkan result codes?
527        ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
528        return VK_ERROR_INITIALIZATION_FAILED;
529    }
530
531    uint32_t idx;
532    for (idx = 0; idx < swapchain.num_images; idx++) {
533        if (swapchain.images[idx].buffer.get() == buffer) {
534            swapchain.images[idx].dequeued = true;
535            swapchain.images[idx].dequeue_fence = fence;
536            break;
537        }
538    }
539    if (idx == swapchain.num_images) {
540        ALOGE("dequeueBuffer returned unrecognized buffer");
541        swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence);
542#pragma clang diagnostic push
543#pragma clang diagnostic ignored "-Wold-style-cast"
544        return VK_ERROR_OUT_OF_DATE_KHR;
545#pragma clang diagnostic pop
546    }
547
548    int fence_clone = -1;
549    if (fence != -1) {
550        fence_clone = dup(fence);
551        if (fence_clone == -1) {
552            ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
553                  strerror(errno), errno);
554            sync_wait(fence, -1 /* forever */);
555        }
556    }
557
558    const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
559    result =
560        driver_vtbl.ImportNativeFenceANDROID(device, semaphore, fence_clone);
561    if (result != VK_SUCCESS) {
562        // NOTE: we're relying on ImportNativeFenceANDROID to close
563        // fence_clone, even if the call fails. We could close it ourselves on
564        // failure, but that would create a race condition if the driver closes
565        // it on a failure path. We must assume one of: the driver *always*
566        // closes it even on failure, or *never* closes it on failure.
567        swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence);
568        swapchain.images[idx].dequeued = false;
569        swapchain.images[idx].dequeue_fence = -1;
570        return result;
571    }
572
573    *image_index = idx;
574    return VK_SUCCESS;
575}
576
577VkResult QueuePresentKHR(VkQueue queue, VkPresentInfoKHR* present_info) {
578#pragma clang diagnostic push
579#pragma clang diagnostic ignored "-Wold-style-cast"
580#pragma clang diagnostic ignored "-Wsign-conversion"
581    ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
582             "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
583             present_info->sType);
584#pragma clang diagnostic pop
585    ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
586
587    const DeviceVtbl& driver_vtbl = GetDriverVtbl(queue);
588    VkResult final_result = VK_SUCCESS;
589    for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
590        Swapchain& swapchain =
591            *SwapchainFromHandle(present_info->swapchains[sc]);
592        uint32_t image_idx = present_info->imageIndices[sc];
593        Swapchain::Image& img = swapchain.images[image_idx];
594        VkResult result;
595        int err;
596
597        int fence = -1;
598        result = driver_vtbl.QueueSignalNativeFenceANDROID(queue, &fence);
599        if (result != VK_SUCCESS) {
600            ALOGE("vkQueueSignalNativeFenceANDROID failed: %d", result);
601            if (final_result == VK_SUCCESS)
602                final_result = result;
603            // TODO(jessehall): What happens to the buffer here? Does the app
604            // still own it or not, i.e. should we cancel the buffer? Hard to
605            // do correctly without synchronizing, though I guess we could wait
606            // for the queue to idle.
607            continue;
608        }
609
610        err = swapchain.window->queueBuffer(swapchain.window.get(),
611                                            img.buffer.get(), fence);
612        if (err != 0) {
613            // TODO(jessehall): What now? We should probably cancel the buffer,
614            // I guess?
615            ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
616            if (final_result == VK_SUCCESS)
617                final_result = VK_ERROR_INITIALIZATION_FAILED;
618            continue;
619        }
620
621        if (img.dequeue_fence != -1) {
622            close(img.dequeue_fence);
623            img.dequeue_fence = -1;
624        }
625        img.dequeued = false;
626    }
627
628    return final_result;
629}
630
631}  // namespace vulkan
632