swapchain.cpp revision f333922399393609f5bf022a3467b7541bd1ad0f
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#include <memory>
19
20#include <gui/BufferQueue.h>
21#include <log/log.h>
22#include <sync/sync.h>
23
24#include "loader.h"
25
26using namespace vulkan;
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.
32
33namespace {
34
35// ----------------------------------------------------------------------------
36// These functions/classes form an adaptor that allows objects to be refcounted
37// by both android::sp<> and std::shared_ptr<> simultaneously, and delegates
38// allocation of the shared_ptr<> control structure to VkAllocationCallbacks.
39// The
40// platform holds a reference to the ANativeWindow using its embedded reference
41// count, and the ANativeWindow implementation holds references to the
42// ANativeWindowBuffers using their embedded reference counts, so the
43// shared_ptr *must* cooperate with these and hold at least one reference to
44// the object using the embedded reference count.
45
46template <typename T>
47struct NativeBaseDeleter {
48    void operator()(T* obj) { obj->common.decRef(&obj->common); }
49};
50
51template <typename Host>
52struct AllocScope {};
53
54template <>
55struct AllocScope<VkInstance> {
56    static const VkSystemAllocationScope kScope =
57        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE;
58};
59
60template <>
61struct AllocScope<VkDevice> {
62    static const VkSystemAllocationScope kScope =
63        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE;
64};
65
66template <typename T>
67class VulkanAllocator {
68   public:
69    typedef T value_type;
70
71    VulkanAllocator(const VkAllocationCallbacks& allocator,
72                    VkSystemAllocationScope scope)
73        : allocator_(allocator), scope_(scope) {}
74
75    template <typename U>
76    explicit VulkanAllocator(const VulkanAllocator<U>& other)
77        : allocator_(other.allocator_), scope_(other.scope_) {}
78
79    T* allocate(size_t n) const {
80        return static_cast<T*>(allocator_.pfnAllocation(
81            allocator_.pUserData, n * sizeof(T), alignof(T), scope_));
82    }
83    void deallocate(T* p, size_t) const {
84        return allocator_.pfnFree(allocator_.pUserData, p);
85    }
86
87   private:
88    template <typename U>
89    friend class VulkanAllocator;
90    const VkAllocationCallbacks& allocator_;
91    const VkSystemAllocationScope scope_;
92};
93
94template <typename T, typename Host>
95std::shared_ptr<T> InitSharedPtr(Host host, T* obj) {
96    obj->common.incRef(&obj->common);
97    return std::shared_ptr<T>(
98        obj, NativeBaseDeleter<T>(),
99        VulkanAllocator<T>(*GetAllocator(host), AllocScope<Host>::kScope));
100}
101
102// ----------------------------------------------------------------------------
103
104struct Surface {
105    std::shared_ptr<ANativeWindow> window;
106};
107
108VkSurfaceKHR HandleFromSurface(Surface* surface) {
109    return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface));
110}
111
112Surface* SurfaceFromHandle(VkSurfaceKHR handle) {
113    return reinterpret_cast<Surface*>(handle);
114}
115
116struct Swapchain {
117    Swapchain(Surface& surface_, uint32_t num_images_)
118        : surface(surface_), num_images(num_images_) {}
119
120    Surface& surface;
121    uint32_t num_images;
122
123    struct Image {
124        Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
125        VkImage image;
126        std::shared_ptr<ANativeWindowBuffer> buffer;
127        // The fence is only valid when the buffer is dequeued, and should be
128        // -1 any other time. When valid, we own the fd, and must ensure it is
129        // closed: either by closing it explicitly when queueing the buffer,
130        // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
131        int dequeue_fence;
132        bool dequeued;
133    } images[android::BufferQueue::NUM_BUFFER_SLOTS];
134};
135
136VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
137    return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
138}
139
140Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
141    return reinterpret_cast<Swapchain*>(handle);
142}
143
144}  // anonymous namespace
145
146namespace vulkan {
147
148VKAPI_ATTR
149VkResult CreateAndroidSurfaceKHR_Bottom(
150    VkInstance instance,
151    const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
152    const VkAllocationCallbacks* allocator,
153    VkSurfaceKHR* out_surface) {
154    if (!allocator)
155        allocator = GetAllocator(instance);
156    void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
157                                         alignof(Surface),
158                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
159    if (!mem)
160        return VK_ERROR_OUT_OF_HOST_MEMORY;
161    Surface* surface = new (mem) Surface;
162
163    surface->window = InitSharedPtr(instance, pCreateInfo->window);
164
165    // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
166    int err =
167        native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
168    if (err != 0) {
169        // TODO(jessehall): Improve error reporting. Can we enumerate possible
170        // errors and translate them to valid Vulkan result codes?
171        ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
172              err);
173        surface->~Surface();
174        allocator->pfnFree(allocator->pUserData, surface);
175        return VK_ERROR_INITIALIZATION_FAILED;
176    }
177
178    *out_surface = HandleFromSurface(surface);
179    return VK_SUCCESS;
180}
181
182VKAPI_ATTR
183void DestroySurfaceKHR_Bottom(VkInstance instance,
184                              VkSurfaceKHR surface_handle,
185                              const VkAllocationCallbacks* allocator) {
186    Surface* surface = SurfaceFromHandle(surface_handle);
187    if (!surface)
188        return;
189    native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL);
190    surface->~Surface();
191    if (!allocator)
192        allocator = GetAllocator(instance);
193    allocator->pfnFree(allocator->pUserData, surface);
194}
195
196VKAPI_ATTR
197VkResult GetPhysicalDeviceSurfaceSupportKHR_Bottom(VkPhysicalDevice /*pdev*/,
198                                                   uint32_t /*queue_family*/,
199                                                   VkSurfaceKHR /*surface*/,
200                                                   VkBool32* supported) {
201    *supported = VK_TRUE;
202    return VK_SUCCESS;
203}
204
205VKAPI_ATTR
206VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Bottom(
207    VkPhysicalDevice /*pdev*/,
208    VkSurfaceKHR surface,
209    VkSurfaceCapabilitiesKHR* capabilities) {
210    int err;
211    ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
212
213    int width, height;
214    err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
215    if (err != 0) {
216        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
217              strerror(-err), err);
218        return VK_ERROR_INITIALIZATION_FAILED;
219    }
220    err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
221    if (err != 0) {
222        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
223              strerror(-err), err);
224        return VK_ERROR_INITIALIZATION_FAILED;
225    }
226
227    capabilities->currentExtent =
228        VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
229
230    // TODO(jessehall): Figure out what the min/max values should be.
231    capabilities->minImageCount = 2;
232    capabilities->maxImageCount = 3;
233
234    // TODO(jessehall): Figure out what the max extent should be. Maximum
235    // texture dimension maybe?
236    capabilities->minImageExtent = VkExtent2D{1, 1};
237    capabilities->maxImageExtent = VkExtent2D{4096, 4096};
238
239    // TODO(jessehall): We can support all transforms, fix this once
240    // implemented.
241    capabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
242
243    // TODO(jessehall): Implement based on NATIVE_WINDOW_TRANSFORM_HINT.
244    capabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
245
246    capabilities->maxImageArrayLayers = 1;
247
248    // TODO(jessehall): I think these are right, but haven't thought hard about
249    // it. Do we need to query the driver for support of any of these?
250    // Currently not included:
251    // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
252    // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
253    // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
254    capabilities->supportedUsageFlags =
255        VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
256        VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
257        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
258        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
259
260    return VK_SUCCESS;
261}
262
263VKAPI_ATTR
264VkResult GetPhysicalDeviceSurfaceFormatsKHR_Bottom(
265    VkPhysicalDevice /*pdev*/,
266    VkSurfaceKHR /*surface*/,
267    uint32_t* count,
268    VkSurfaceFormatKHR* formats) {
269    // TODO(jessehall): Fill out the set of supported formats. Longer term, add
270    // a new gralloc method to query whether a (format, usage) pair is
271    // supported, and check that for each gralloc format that corresponds to a
272    // Vulkan format. Shorter term, just add a few more formats to the ones
273    // hardcoded below.
274
275    const VkSurfaceFormatKHR kFormats[] = {
276        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
277        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
278    };
279    const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
280
281    VkResult result = VK_SUCCESS;
282    if (formats) {
283        if (*count < kNumFormats)
284            result = VK_INCOMPLETE;
285        std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
286    }
287    *count = kNumFormats;
288    return result;
289}
290
291VKAPI_ATTR
292VkResult GetPhysicalDeviceSurfacePresentModesKHR_Bottom(
293    VkPhysicalDevice /*pdev*/,
294    VkSurfaceKHR /*surface*/,
295    uint32_t* count,
296    VkPresentModeKHR* modes) {
297    const VkPresentModeKHR kModes[] = {
298        VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
299    };
300    const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
301
302    VkResult result = VK_SUCCESS;
303    if (modes) {
304        if (*count < kNumModes)
305            result = VK_INCOMPLETE;
306        std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
307    }
308    *count = kNumModes;
309    return result;
310}
311
312VKAPI_ATTR
313VkResult CreateSwapchainKHR_Bottom(VkDevice device,
314                                   const VkSwapchainCreateInfoKHR* create_info,
315                                   const VkAllocationCallbacks* allocator,
316                                   VkSwapchainKHR* swapchain_handle) {
317    int err;
318    VkResult result = VK_SUCCESS;
319
320    if (!allocator)
321        allocator = GetAllocator(device);
322
323    ALOGV_IF(create_info->imageArrayLayers != 1,
324             "Swapchain imageArrayLayers (%u) != 1 not supported",
325             create_info->imageArrayLayers);
326
327    ALOGE_IF(create_info->imageFormat != VK_FORMAT_R8G8B8A8_UNORM,
328             "swapchain formats other than R8G8B8A8_UNORM not yet implemented");
329    ALOGE_IF(create_info->imageColorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR,
330             "color spaces other than SRGB_NONLINEAR not yet implemented");
331    ALOGE_IF(create_info->oldSwapchain,
332             "swapchain re-creation not yet implemented");
333    ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
334             "swapchain preTransform not yet implemented");
335    ALOGW_IF((create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR ||
336              create_info->presentMode != VK_PRESENT_MODE_MAILBOX_KHR),
337             "swapchain present mode %d not supported",
338             create_info->presentMode);
339
340    // -- Configure the native window --
341
342    Surface& surface = *SurfaceFromHandle(create_info->surface);
343    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
344
345    err = native_window_set_buffers_dimensions(
346        surface.window.get(), static_cast<int>(create_info->imageExtent.width),
347        static_cast<int>(create_info->imageExtent.height));
348    if (err != 0) {
349        // TODO(jessehall): Improve error reporting. Can we enumerate possible
350        // errors and translate them to valid Vulkan result codes?
351        ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
352              create_info->imageExtent.width, create_info->imageExtent.height,
353              strerror(-err), err);
354        return VK_ERROR_INITIALIZATION_FAILED;
355    }
356
357    err = native_window_set_scaling_mode(
358        surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
359    if (err != 0) {
360        // TODO(jessehall): Improve error reporting. Can we enumerate possible
361        // errors and translate them to valid Vulkan result codes?
362        ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
363              strerror(-err), err);
364        return VK_ERROR_INITIALIZATION_FAILED;
365    }
366
367    uint32_t min_undequeued_buffers;
368    err = surface.window->query(
369        surface.window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
370        reinterpret_cast<int*>(&min_undequeued_buffers));
371    if (err != 0) {
372        // TODO(jessehall): Improve error reporting. Can we enumerate possible
373        // errors and translate them to valid Vulkan result codes?
374        ALOGE("window->query failed: %s (%d)", strerror(-err), err);
375        return VK_ERROR_INITIALIZATION_FAILED;
376    }
377    uint32_t num_images =
378        (create_info->minImageCount - 1) + min_undequeued_buffers;
379    err = native_window_set_buffer_count(surface.window.get(), num_images);
380    if (err != 0) {
381        // TODO(jessehall): Improve error reporting. Can we enumerate possible
382        // errors and translate them to valid Vulkan result codes?
383        ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
384              err);
385        return VK_ERROR_INITIALIZATION_FAILED;
386    }
387
388    int gralloc_usage = 0;
389    // TODO(jessehall): Remove conditional once all drivers have been updated
390    if (dispatch.GetSwapchainGrallocUsageANDROID) {
391        result = dispatch.GetSwapchainGrallocUsageANDROID(
392            device, create_info->imageFormat, create_info->imageUsage,
393            &gralloc_usage);
394        if (result != VK_SUCCESS) {
395            ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
396            return VK_ERROR_INITIALIZATION_FAILED;
397        }
398    } else {
399        gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
400    }
401    err = native_window_set_usage(surface.window.get(), gralloc_usage);
402    if (err != 0) {
403        // TODO(jessehall): Improve error reporting. Can we enumerate possible
404        // errors and translate them to valid Vulkan result codes?
405        ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
406        return VK_ERROR_INITIALIZATION_FAILED;
407    }
408
409    err = surface.window->setSwapInterval(
410        surface.window.get(),
411        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1);
412    if (err != 0) {
413        // TODO(jessehall): Improve error reporting. Can we enumerate possible
414        // errors and translate them to valid Vulkan result codes?
415        ALOGE("native_window->setSwapInterval failed: %s (%d)", strerror(-err),
416              err);
417        return VK_ERROR_INITIALIZATION_FAILED;
418    }
419
420    // -- Allocate our Swapchain object --
421    // After this point, we must deallocate the swapchain on error.
422
423    void* mem = allocator->pfnAllocation(allocator->pUserData,
424                                         sizeof(Swapchain), alignof(Swapchain),
425                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
426    if (!mem)
427        return VK_ERROR_OUT_OF_HOST_MEMORY;
428    Swapchain* swapchain = new (mem) Swapchain(surface, num_images);
429
430    // -- Dequeue all buffers and create a VkImage for each --
431    // Any failures during or after this must cancel the dequeued buffers.
432
433    VkNativeBufferANDROID image_native_buffer = {
434#pragma clang diagnostic push
435#pragma clang diagnostic ignored "-Wold-style-cast"
436        .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
437#pragma clang diagnostic pop
438        .pNext = nullptr,
439    };
440    VkImageCreateInfo image_create = {
441        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
442        .pNext = &image_native_buffer,
443        .imageType = VK_IMAGE_TYPE_2D,
444        .format = VK_FORMAT_R8G8B8A8_UNORM,  // TODO(jessehall)
445        .extent = {0, 0, 1},
446        .mipLevels = 1,
447        .arrayLayers = 1,
448        .samples = VK_SAMPLE_COUNT_1_BIT,
449        .tiling = VK_IMAGE_TILING_OPTIMAL,
450        .usage = create_info->imageUsage,
451        .flags = 0,
452        .sharingMode = create_info->imageSharingMode,
453        .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
454        .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
455    };
456
457    for (uint32_t i = 0; i < num_images; i++) {
458        Swapchain::Image& img = swapchain->images[i];
459
460        ANativeWindowBuffer* buffer;
461        err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
462                                            &img.dequeue_fence);
463        if (err != 0) {
464            // TODO(jessehall): Improve error reporting. Can we enumerate
465            // possible errors and translate them to valid Vulkan result codes?
466            ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
467            result = VK_ERROR_INITIALIZATION_FAILED;
468            break;
469        }
470        img.buffer = InitSharedPtr(device, buffer);
471        img.dequeued = true;
472
473        image_create.extent =
474            VkExtent3D{static_cast<uint32_t>(img.buffer->width),
475                       static_cast<uint32_t>(img.buffer->height),
476                       1};
477        image_native_buffer.handle = img.buffer->handle;
478        image_native_buffer.stride = img.buffer->stride;
479        image_native_buffer.format = img.buffer->format;
480        image_native_buffer.usage = img.buffer->usage;
481
482        result =
483            dispatch.CreateImage(device, &image_create, nullptr, &img.image);
484        if (result != VK_SUCCESS) {
485            ALOGD("vkCreateImage w/ native buffer failed: %u", result);
486            break;
487        }
488    }
489
490    // -- Cancel all buffers, returning them to the queue --
491    // If an error occurred before, also destroy the VkImage and release the
492    // buffer reference. Otherwise, we retain a strong reference to the buffer.
493    //
494    // TODO(jessehall): The error path here is the same as DestroySwapchain,
495    // but not the non-error path. Should refactor/unify.
496    for (uint32_t i = 0; i < num_images; i++) {
497        Swapchain::Image& img = swapchain->images[i];
498        if (img.dequeued) {
499            surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
500                                         img.dequeue_fence);
501            img.dequeue_fence = -1;
502            img.dequeued = false;
503        }
504        if (result != VK_SUCCESS) {
505            if (img.image)
506                dispatch.DestroyImage(device, img.image, nullptr);
507        }
508    }
509
510    if (result != VK_SUCCESS) {
511        swapchain->~Swapchain();
512        allocator->pfnFree(allocator->pUserData, swapchain);
513        return result;
514    }
515
516    *swapchain_handle = HandleFromSwapchain(swapchain);
517    return VK_SUCCESS;
518}
519
520VKAPI_ATTR
521void DestroySwapchainKHR_Bottom(VkDevice device,
522                                VkSwapchainKHR swapchain_handle,
523                                const VkAllocationCallbacks* allocator) {
524    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
525    Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
526    const std::shared_ptr<ANativeWindow>& window = swapchain->surface.window;
527
528    for (uint32_t i = 0; i < swapchain->num_images; i++) {
529        Swapchain::Image& img = swapchain->images[i];
530        if (img.dequeued) {
531            window->cancelBuffer(window.get(), img.buffer.get(),
532                                 img.dequeue_fence);
533            img.dequeue_fence = -1;
534            img.dequeued = false;
535        }
536        if (img.image) {
537            dispatch.DestroyImage(device, img.image, nullptr);
538        }
539    }
540
541    if (!allocator)
542        allocator = GetAllocator(device);
543    swapchain->~Swapchain();
544    allocator->pfnFree(allocator->pUserData, swapchain);
545}
546
547VKAPI_ATTR
548VkResult GetSwapchainImagesKHR_Bottom(VkDevice,
549                                      VkSwapchainKHR swapchain_handle,
550                                      uint32_t* count,
551                                      VkImage* images) {
552    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
553    VkResult result = VK_SUCCESS;
554    if (images) {
555        uint32_t n = swapchain.num_images;
556        if (*count < swapchain.num_images) {
557            n = *count;
558            result = VK_INCOMPLETE;
559        }
560        for (uint32_t i = 0; i < n; i++)
561            images[i] = swapchain.images[i].image;
562    }
563    *count = swapchain.num_images;
564    return result;
565}
566
567VKAPI_ATTR
568VkResult AcquireNextImageKHR_Bottom(VkDevice device,
569                                    VkSwapchainKHR swapchain_handle,
570                                    uint64_t timeout,
571                                    VkSemaphore semaphore,
572                                    VkFence vk_fence,
573                                    uint32_t* image_index) {
574    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
575    ANativeWindow* window = swapchain.surface.window.get();
576    VkResult result;
577    int err;
578
579    ALOGW_IF(
580        timeout != UINT64_MAX,
581        "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
582
583    ANativeWindowBuffer* buffer;
584    int fence_fd;
585    err = window->dequeueBuffer(window, &buffer, &fence_fd);
586    if (err != 0) {
587        // TODO(jessehall): Improve error reporting. Can we enumerate possible
588        // errors and translate them to valid Vulkan result codes?
589        ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
590        return VK_ERROR_INITIALIZATION_FAILED;
591    }
592
593    uint32_t idx;
594    for (idx = 0; idx < swapchain.num_images; idx++) {
595        if (swapchain.images[idx].buffer.get() == buffer) {
596            swapchain.images[idx].dequeued = true;
597            swapchain.images[idx].dequeue_fence = fence_fd;
598            break;
599        }
600    }
601    if (idx == swapchain.num_images) {
602        ALOGE("dequeueBuffer returned unrecognized buffer");
603        window->cancelBuffer(window, buffer, fence_fd);
604        return VK_ERROR_OUT_OF_DATE_KHR;
605    }
606
607    int fence_clone = -1;
608    if (fence_fd != -1) {
609        fence_clone = dup(fence_fd);
610        if (fence_clone == -1) {
611            ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
612                  strerror(errno), errno);
613            sync_wait(fence_fd, -1 /* forever */);
614        }
615    }
616
617    result = GetDriverDispatch(device).AcquireImageANDROID(
618        device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
619    if (result != VK_SUCCESS) {
620        // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
621        // even if the call fails. We could close it ourselves on failure, but
622        // that would create a race condition if the driver closes it on a
623        // failure path: some other thread might create an fd with the same
624        // number between the time the driver closes it and the time we close
625        // it. We must assume one of: the driver *always* closes it even on
626        // failure, or *never* closes it on failure.
627        window->cancelBuffer(window, buffer, fence_fd);
628        swapchain.images[idx].dequeued = false;
629        swapchain.images[idx].dequeue_fence = -1;
630        return result;
631    }
632
633    *image_index = idx;
634    return VK_SUCCESS;
635}
636
637VKAPI_ATTR
638VkResult QueuePresentKHR_Bottom(VkQueue queue,
639                                const VkPresentInfoKHR* present_info) {
640    ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
641             "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
642             present_info->sType);
643    ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
644
645    const DriverDispatchTable& dispatch = GetDriverDispatch(queue);
646    VkResult final_result = VK_SUCCESS;
647    for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
648        Swapchain& swapchain =
649            *SwapchainFromHandle(present_info->pSwapchains[sc]);
650        ANativeWindow* window = swapchain.surface.window.get();
651        uint32_t image_idx = present_info->pImageIndices[sc];
652        Swapchain::Image& img = swapchain.images[image_idx];
653        VkResult result;
654        int err;
655
656        int fence = -1;
657        result = dispatch.QueueSignalReleaseImageANDROID(
658            queue, present_info->waitSemaphoreCount,
659            present_info->pWaitSemaphores, img.image, &fence);
660        if (result != VK_SUCCESS) {
661            ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
662            if (present_info->pResults)
663                present_info->pResults[sc] = result;
664            if (final_result == VK_SUCCESS)
665                final_result = result;
666            // TODO(jessehall): What happens to the buffer here? Does the app
667            // still own it or not, i.e. should we cancel the buffer? Hard to
668            // do correctly without synchronizing, though I guess we could wait
669            // for the queue to idle.
670            continue;
671        }
672
673        err = window->queueBuffer(window, img.buffer.get(), fence);
674        if (err != 0) {
675            // TODO(jessehall): What now? We should probably cancel the buffer,
676            // I guess?
677            ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
678            if (present_info->pResults)
679                present_info->pResults[sc] = result;
680            if (final_result == VK_SUCCESS)
681                final_result = VK_ERROR_INITIALIZATION_FAILED;
682            continue;
683        }
684
685        if (img.dequeue_fence != -1) {
686            close(img.dequeue_fence);
687            img.dequeue_fence = -1;
688        }
689        img.dequeued = false;
690
691        if (present_info->pResults)
692            present_info->pResults[sc] = VK_SUCCESS;
693    }
694
695    return final_result;
696}
697
698}  // namespace vulkan
699