swapchain.cpp revision e8e689f1190a936ebd6bf6cbe28ab8625e94c6c7
1/*
2 * Copyright 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <algorithm>
18
19#include <gui/BufferQueue.h>
20#include <log/log.h>
21#include <sync/sync.h>
22#include <utils/StrongPointer.h>
23
24#include "driver.h"
25
26// TODO(jessehall): Currently we don't have a good error code for when a native
27// window operation fails. Just returning INITIALIZATION_FAILED for now. Later
28// versions (post SDK 0.9) of the API/extension have a better error code.
29// When updating to that version, audit all error returns.
30namespace vulkan {
31namespace driver {
32
33namespace {
34
35const VkSurfaceTransformFlagsKHR kSupportedTransforms =
36    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR |
37    VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
38    VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR |
39    VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
40    // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
41    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR |
42    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
43    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR |
44    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR |
45    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
46
47VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) {
48    // Native and Vulkan transforms are isomorphic, but are represented
49    // differently. Vulkan transforms are built up of an optional horizontal
50    // mirror, followed by a clockwise 0/90/180/270-degree rotation. Native
51    // transforms are built up from a horizontal flip, vertical flip, and
52    // 90-degree rotation, all optional but always in that order.
53
54    // TODO(jessehall): For now, only support pure rotations, not
55    // flip or flip-and-rotate, until I have more time to test them and build
56    // sample code. As far as I know we never actually use anything besides
57    // pure rotations anyway.
58
59    switch (native) {
60        case 0:  // 0x0
61            return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
62        // case NATIVE_WINDOW_TRANSFORM_FLIP_H:  // 0x1
63        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR;
64        // case NATIVE_WINDOW_TRANSFORM_FLIP_V:  // 0x2
65        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR;
66        case NATIVE_WINDOW_TRANSFORM_ROT_180:  // FLIP_H | FLIP_V
67            return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
68        case NATIVE_WINDOW_TRANSFORM_ROT_90:  // 0x4
69            return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
70        // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90:
71        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR;
72        // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90:
73        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
74        case NATIVE_WINDOW_TRANSFORM_ROT_270:  // FLIP_H | FLIP_V | ROT_90
75            return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
76        case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
77        default:
78            return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
79    }
80}
81
82int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) {
83    switch (transform) {
84        case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
85            return NATIVE_WINDOW_TRANSFORM_ROT_270;
86        case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
87            return NATIVE_WINDOW_TRANSFORM_ROT_180;
88        case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
89            return NATIVE_WINDOW_TRANSFORM_ROT_90;
90        // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
91        // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
92        //     return NATIVE_WINDOW_TRANSFORM_FLIP_H;
93        // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
94        //     return NATIVE_WINDOW_TRANSFORM_FLIP_H |
95        //            NATIVE_WINDOW_TRANSFORM_ROT_90;
96        // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
97        //     return NATIVE_WINDOW_TRANSFORM_FLIP_V;
98        // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
99        //     return NATIVE_WINDOW_TRANSFORM_FLIP_V |
100        //            NATIVE_WINDOW_TRANSFORM_ROT_90;
101        case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
102        case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
103        default:
104            return 0;
105    }
106}
107
108// ----------------------------------------------------------------------------
109
110struct Surface {
111    android::sp<ANativeWindow> window;
112};
113
114VkSurfaceKHR HandleFromSurface(Surface* surface) {
115    return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface));
116}
117
118Surface* SurfaceFromHandle(VkSurfaceKHR handle) {
119    return reinterpret_cast<Surface*>(handle);
120}
121
122struct Swapchain {
123    Swapchain(Surface& surface_, uint32_t num_images_)
124        : surface(surface_), num_images(num_images_) {}
125
126    Surface& surface;
127    uint32_t num_images;
128
129    struct Image {
130        Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
131        VkImage image;
132        android::sp<ANativeWindowBuffer> buffer;
133        // The fence is only valid when the buffer is dequeued, and should be
134        // -1 any other time. When valid, we own the fd, and must ensure it is
135        // closed: either by closing it explicitly when queueing the buffer,
136        // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
137        int dequeue_fence;
138        bool dequeued;
139    } images[android::BufferQueue::NUM_BUFFER_SLOTS];
140};
141
142VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
143    return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
144}
145
146Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
147    return reinterpret_cast<Swapchain*>(handle);
148}
149
150}  // anonymous namespace
151
152VKAPI_ATTR
153VkResult CreateAndroidSurfaceKHR(
154    VkInstance instance,
155    const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
156    const VkAllocationCallbacks* allocator,
157    VkSurfaceKHR* out_surface) {
158    if (!allocator)
159        allocator = &GetData(instance).allocator;
160    void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
161                                         alignof(Surface),
162                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
163    if (!mem)
164        return VK_ERROR_OUT_OF_HOST_MEMORY;
165    Surface* surface = new (mem) Surface;
166
167    surface->window = pCreateInfo->window;
168
169    // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
170    int err =
171        native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
172    if (err != 0) {
173        // TODO(jessehall): Improve error reporting. Can we enumerate possible
174        // errors and translate them to valid Vulkan result codes?
175        ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
176              err);
177        surface->~Surface();
178        allocator->pfnFree(allocator->pUserData, surface);
179        return VK_ERROR_INITIALIZATION_FAILED;
180    }
181
182    *out_surface = HandleFromSurface(surface);
183    return VK_SUCCESS;
184}
185
186VKAPI_ATTR
187void DestroySurfaceKHR(VkInstance instance,
188                       VkSurfaceKHR surface_handle,
189                       const VkAllocationCallbacks* allocator) {
190    Surface* surface = SurfaceFromHandle(surface_handle);
191    if (!surface)
192        return;
193    native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL);
194    surface->~Surface();
195    if (!allocator)
196        allocator = &GetData(instance).allocator;
197    allocator->pfnFree(allocator->pUserData, surface);
198}
199
200VKAPI_ATTR
201VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
202                                            uint32_t /*queue_family*/,
203                                            VkSurfaceKHR /*surface*/,
204                                            VkBool32* supported) {
205    *supported = VK_TRUE;
206    return VK_SUCCESS;
207}
208
209VKAPI_ATTR
210VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(
211    VkPhysicalDevice /*pdev*/,
212    VkSurfaceKHR surface,
213    VkSurfaceCapabilitiesKHR* capabilities) {
214    int err;
215    ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
216
217    int width, height;
218    err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
219    if (err != 0) {
220        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
221              strerror(-err), err);
222        return VK_ERROR_INITIALIZATION_FAILED;
223    }
224    err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
225    if (err != 0) {
226        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
227              strerror(-err), err);
228        return VK_ERROR_INITIALIZATION_FAILED;
229    }
230
231    int transform_hint;
232    err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
233    if (err != 0) {
234        ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
235              strerror(-err), err);
236        return VK_ERROR_INITIALIZATION_FAILED;
237    }
238
239    // TODO(jessehall): Figure out what the min/max values should be.
240    capabilities->minImageCount = 2;
241    capabilities->maxImageCount = 3;
242
243    capabilities->currentExtent =
244        VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
245
246    // TODO(jessehall): Figure out what the max extent should be. Maximum
247    // texture dimension maybe?
248    capabilities->minImageExtent = VkExtent2D{1, 1};
249    capabilities->maxImageExtent = VkExtent2D{4096, 4096};
250
251    capabilities->maxImageArrayLayers = 1;
252
253    capabilities->supportedTransforms = kSupportedTransforms;
254    capabilities->currentTransform =
255        TranslateNativeToVulkanTransform(transform_hint);
256
257    // On Android, window composition is a WindowManager property, not something
258    // associated with the bufferqueue. It can't be changed from here.
259    capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
260
261    // TODO(jessehall): I think these are right, but haven't thought hard about
262    // it. Do we need to query the driver for support of any of these?
263    // Currently not included:
264    // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
265    // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
266    // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
267    capabilities->supportedUsageFlags =
268        VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
269        VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
270        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
271        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
272
273    return VK_SUCCESS;
274}
275
276VKAPI_ATTR
277VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/,
278                                            VkSurfaceKHR /*surface*/,
279                                            uint32_t* count,
280                                            VkSurfaceFormatKHR* formats) {
281    // TODO(jessehall): Fill out the set of supported formats. Longer term, add
282    // a new gralloc method to query whether a (format, usage) pair is
283    // supported, and check that for each gralloc format that corresponds to a
284    // Vulkan format. Shorter term, just add a few more formats to the ones
285    // hardcoded below.
286
287    const VkSurfaceFormatKHR kFormats[] = {
288        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
289        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
290        {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
291    };
292    const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
293
294    VkResult result = VK_SUCCESS;
295    if (formats) {
296        if (*count < kNumFormats)
297            result = VK_INCOMPLETE;
298        std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
299    }
300    *count = kNumFormats;
301    return result;
302}
303
304VKAPI_ATTR
305VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/,
306                                                 VkSurfaceKHR /*surface*/,
307                                                 uint32_t* count,
308                                                 VkPresentModeKHR* modes) {
309    const VkPresentModeKHR kModes[] = {
310        VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
311    };
312    const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
313
314    VkResult result = VK_SUCCESS;
315    if (modes) {
316        if (*count < kNumModes)
317            result = VK_INCOMPLETE;
318        std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
319    }
320    *count = kNumModes;
321    return result;
322}
323
324VKAPI_ATTR
325VkResult CreateSwapchainKHR(VkDevice device,
326                            const VkSwapchainCreateInfoKHR* create_info,
327                            const VkAllocationCallbacks* allocator,
328                            VkSwapchainKHR* swapchain_handle) {
329    int err;
330    VkResult result = VK_SUCCESS;
331
332    if (!allocator)
333        allocator = &GetData(device).allocator;
334
335    ALOGV_IF(create_info->imageArrayLayers != 1,
336             "Swapchain imageArrayLayers (%u) != 1 not supported",
337             create_info->imageArrayLayers);
338
339    ALOGE_IF(create_info->imageColorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR,
340             "color spaces other than SRGB_NONLINEAR not yet implemented");
341    ALOGE_IF(create_info->oldSwapchain,
342             "swapchain re-creation not yet implemented");
343    ALOGE_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
344             "swapchain preTransform %d not supported",
345             create_info->preTransform);
346    ALOGW_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
347               create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
348             "swapchain present mode %d not supported",
349             create_info->presentMode);
350
351    // -- Configure the native window --
352
353    Surface& surface = *SurfaceFromHandle(create_info->surface);
354    const auto& dispatch = GetData(device).driver;
355
356    int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
357    switch (create_info->imageFormat) {
358        case VK_FORMAT_R8G8B8A8_UNORM:
359        case VK_FORMAT_R8G8B8A8_SRGB:
360            native_format = HAL_PIXEL_FORMAT_RGBA_8888;
361            break;
362        case VK_FORMAT_R5G6B5_UNORM_PACK16:
363            native_format = HAL_PIXEL_FORMAT_RGB_565;
364            break;
365        default:
366            ALOGE("unsupported swapchain format %d", create_info->imageFormat);
367            break;
368    }
369    err = native_window_set_buffers_format(surface.window.get(), native_format);
370    if (err != 0) {
371        // TODO(jessehall): Improve error reporting. Can we enumerate possible
372        // errors and translate them to valid Vulkan result codes?
373        ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
374              native_format, strerror(-err), err);
375        return VK_ERROR_INITIALIZATION_FAILED;
376    }
377    err = native_window_set_buffers_data_space(surface.window.get(),
378                                               HAL_DATASPACE_SRGB_LINEAR);
379    if (err != 0) {
380        // TODO(jessehall): Improve error reporting. Can we enumerate possible
381        // errors and translate them to valid Vulkan result codes?
382        ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
383              HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err);
384        return VK_ERROR_INITIALIZATION_FAILED;
385    }
386
387    err = native_window_set_buffers_dimensions(
388        surface.window.get(), static_cast<int>(create_info->imageExtent.width),
389        static_cast<int>(create_info->imageExtent.height));
390    if (err != 0) {
391        // TODO(jessehall): Improve error reporting. Can we enumerate possible
392        // errors and translate them to valid Vulkan result codes?
393        ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
394              create_info->imageExtent.width, create_info->imageExtent.height,
395              strerror(-err), err);
396        return VK_ERROR_INITIALIZATION_FAILED;
397    }
398
399    // VkSwapchainCreateInfo::preTransform indicates the transformation the app
400    // applied during rendering. native_window_set_transform() expects the
401    // inverse: the transform the app is requesting that the compositor perform
402    // during composition. With native windows, pre-transform works by rendering
403    // with the same transform the compositor is applying (as in Vulkan), but
404    // then requesting the inverse transform, so that when the compositor does
405    // it's job the two transforms cancel each other out and the compositor ends
406    // up applying an identity transform to the app's buffer.
407    err = native_window_set_buffers_transform(
408        surface.window.get(),
409        InvertTransformToNative(create_info->preTransform));
410    if (err != 0) {
411        // TODO(jessehall): Improve error reporting. Can we enumerate possible
412        // errors and translate them to valid Vulkan result codes?
413        ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
414              InvertTransformToNative(create_info->preTransform),
415              strerror(-err), err);
416        return VK_ERROR_INITIALIZATION_FAILED;
417    }
418
419    err = native_window_set_scaling_mode(
420        surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
421    if (err != 0) {
422        // TODO(jessehall): Improve error reporting. Can we enumerate possible
423        // errors and translate them to valid Vulkan result codes?
424        ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
425              strerror(-err), err);
426        return VK_ERROR_INITIALIZATION_FAILED;
427    }
428
429    int query_value;
430    err = surface.window->query(surface.window.get(),
431                                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
432                                &query_value);
433    if (err != 0 || query_value < 0) {
434        // TODO(jessehall): Improve error reporting. Can we enumerate possible
435        // errors and translate them to valid Vulkan result codes?
436        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
437              query_value);
438        return VK_ERROR_INITIALIZATION_FAILED;
439    }
440    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
441    // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
442    // async mode or not, and assumes not. But in async mode, the BufferQueue
443    // requires an extra undequeued buffer.
444    // See BufferQueueCore::getMinUndequeuedBufferCountLocked().
445    if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
446        min_undequeued_buffers += 1;
447
448    uint32_t num_images =
449        (create_info->minImageCount - 1) + min_undequeued_buffers;
450    err = native_window_set_buffer_count(surface.window.get(), num_images);
451    if (err != 0) {
452        // TODO(jessehall): Improve error reporting. Can we enumerate possible
453        // errors and translate them to valid Vulkan result codes?
454        ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
455              err);
456        return VK_ERROR_INITIALIZATION_FAILED;
457    }
458
459    int gralloc_usage = 0;
460    // TODO(jessehall): Remove conditional once all drivers have been updated
461    if (dispatch.GetSwapchainGrallocUsageANDROID) {
462        result = dispatch.GetSwapchainGrallocUsageANDROID(
463            device, create_info->imageFormat, create_info->imageUsage,
464            &gralloc_usage);
465        if (result != VK_SUCCESS) {
466            ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
467            return VK_ERROR_INITIALIZATION_FAILED;
468        }
469    } else {
470        gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
471    }
472    err = native_window_set_usage(surface.window.get(), gralloc_usage);
473    if (err != 0) {
474        // TODO(jessehall): Improve error reporting. Can we enumerate possible
475        // errors and translate them to valid Vulkan result codes?
476        ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
477        return VK_ERROR_INITIALIZATION_FAILED;
478    }
479
480    err = surface.window->setSwapInterval(
481        surface.window.get(),
482        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1);
483    if (err != 0) {
484        // TODO(jessehall): Improve error reporting. Can we enumerate possible
485        // errors and translate them to valid Vulkan result codes?
486        ALOGE("native_window->setSwapInterval failed: %s (%d)", strerror(-err),
487              err);
488        return VK_ERROR_INITIALIZATION_FAILED;
489    }
490
491    // -- Allocate our Swapchain object --
492    // After this point, we must deallocate the swapchain on error.
493
494    void* mem = allocator->pfnAllocation(allocator->pUserData,
495                                         sizeof(Swapchain), alignof(Swapchain),
496                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
497    if (!mem)
498        return VK_ERROR_OUT_OF_HOST_MEMORY;
499    Swapchain* swapchain = new (mem) Swapchain(surface, num_images);
500
501    // -- Dequeue all buffers and create a VkImage for each --
502    // Any failures during or after this must cancel the dequeued buffers.
503
504    VkNativeBufferANDROID image_native_buffer = {
505#pragma clang diagnostic push
506#pragma clang diagnostic ignored "-Wold-style-cast"
507        .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
508#pragma clang diagnostic pop
509        .pNext = nullptr,
510    };
511    VkImageCreateInfo image_create = {
512        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
513        .pNext = &image_native_buffer,
514        .imageType = VK_IMAGE_TYPE_2D,
515        .format = create_info->imageFormat,
516        .extent = {0, 0, 1},
517        .mipLevels = 1,
518        .arrayLayers = 1,
519        .samples = VK_SAMPLE_COUNT_1_BIT,
520        .tiling = VK_IMAGE_TILING_OPTIMAL,
521        .usage = create_info->imageUsage,
522        .flags = 0,
523        .sharingMode = create_info->imageSharingMode,
524        .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
525        .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
526    };
527
528    for (uint32_t i = 0; i < num_images; i++) {
529        Swapchain::Image& img = swapchain->images[i];
530
531        ANativeWindowBuffer* buffer;
532        err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
533                                            &img.dequeue_fence);
534        if (err != 0) {
535            // TODO(jessehall): Improve error reporting. Can we enumerate
536            // possible errors and translate them to valid Vulkan result codes?
537            ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
538            result = VK_ERROR_INITIALIZATION_FAILED;
539            break;
540        }
541        img.buffer = buffer;
542        img.dequeued = true;
543
544        image_create.extent =
545            VkExtent3D{static_cast<uint32_t>(img.buffer->width),
546                       static_cast<uint32_t>(img.buffer->height),
547                       1};
548        image_native_buffer.handle = img.buffer->handle;
549        image_native_buffer.stride = img.buffer->stride;
550        image_native_buffer.format = img.buffer->format;
551        image_native_buffer.usage = img.buffer->usage;
552
553        result =
554            dispatch.CreateImage(device, &image_create, nullptr, &img.image);
555        if (result != VK_SUCCESS) {
556            ALOGD("vkCreateImage w/ native buffer failed: %u", result);
557            break;
558        }
559    }
560
561    // -- Cancel all buffers, returning them to the queue --
562    // If an error occurred before, also destroy the VkImage and release the
563    // buffer reference. Otherwise, we retain a strong reference to the buffer.
564    //
565    // TODO(jessehall): The error path here is the same as DestroySwapchain,
566    // but not the non-error path. Should refactor/unify.
567    for (uint32_t i = 0; i < num_images; i++) {
568        Swapchain::Image& img = swapchain->images[i];
569        if (img.dequeued) {
570            surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
571                                         img.dequeue_fence);
572            img.dequeue_fence = -1;
573            img.dequeued = false;
574        }
575        if (result != VK_SUCCESS) {
576            if (img.image)
577                dispatch.DestroyImage(device, img.image, nullptr);
578        }
579    }
580
581    if (result != VK_SUCCESS) {
582        swapchain->~Swapchain();
583        allocator->pfnFree(allocator->pUserData, swapchain);
584        return result;
585    }
586
587    *swapchain_handle = HandleFromSwapchain(swapchain);
588    return VK_SUCCESS;
589}
590
591VKAPI_ATTR
592void DestroySwapchainKHR(VkDevice device,
593                         VkSwapchainKHR swapchain_handle,
594                         const VkAllocationCallbacks* allocator) {
595    const auto& dispatch = GetData(device).driver;
596    Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
597    const android::sp<ANativeWindow>& window = swapchain->surface.window;
598
599    for (uint32_t i = 0; i < swapchain->num_images; i++) {
600        Swapchain::Image& img = swapchain->images[i];
601        if (img.dequeued) {
602            window->cancelBuffer(window.get(), img.buffer.get(),
603                                 img.dequeue_fence);
604            img.dequeue_fence = -1;
605            img.dequeued = false;
606        }
607        if (img.image) {
608            dispatch.DestroyImage(device, img.image, nullptr);
609        }
610    }
611
612    if (!allocator)
613        allocator = &GetData(device).allocator;
614    swapchain->~Swapchain();
615    allocator->pfnFree(allocator->pUserData, swapchain);
616}
617
618VKAPI_ATTR
619VkResult GetSwapchainImagesKHR(VkDevice,
620                               VkSwapchainKHR swapchain_handle,
621                               uint32_t* count,
622                               VkImage* images) {
623    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
624    VkResult result = VK_SUCCESS;
625    if (images) {
626        uint32_t n = swapchain.num_images;
627        if (*count < swapchain.num_images) {
628            n = *count;
629            result = VK_INCOMPLETE;
630        }
631        for (uint32_t i = 0; i < n; i++)
632            images[i] = swapchain.images[i].image;
633    }
634    *count = swapchain.num_images;
635    return result;
636}
637
638VKAPI_ATTR
639VkResult AcquireNextImageKHR(VkDevice device,
640                             VkSwapchainKHR swapchain_handle,
641                             uint64_t timeout,
642                             VkSemaphore semaphore,
643                             VkFence vk_fence,
644                             uint32_t* image_index) {
645    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
646    ANativeWindow* window = swapchain.surface.window.get();
647    VkResult result;
648    int err;
649
650    ALOGW_IF(
651        timeout != UINT64_MAX,
652        "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
653
654    ANativeWindowBuffer* buffer;
655    int fence_fd;
656    err = window->dequeueBuffer(window, &buffer, &fence_fd);
657    if (err != 0) {
658        // TODO(jessehall): Improve error reporting. Can we enumerate possible
659        // errors and translate them to valid Vulkan result codes?
660        ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
661        return VK_ERROR_INITIALIZATION_FAILED;
662    }
663
664    uint32_t idx;
665    for (idx = 0; idx < swapchain.num_images; idx++) {
666        if (swapchain.images[idx].buffer.get() == buffer) {
667            swapchain.images[idx].dequeued = true;
668            swapchain.images[idx].dequeue_fence = fence_fd;
669            break;
670        }
671    }
672    if (idx == swapchain.num_images) {
673        ALOGE("dequeueBuffer returned unrecognized buffer");
674        window->cancelBuffer(window, buffer, fence_fd);
675        return VK_ERROR_OUT_OF_DATE_KHR;
676    }
677
678    int fence_clone = -1;
679    if (fence_fd != -1) {
680        fence_clone = dup(fence_fd);
681        if (fence_clone == -1) {
682            ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
683                  strerror(errno), errno);
684            sync_wait(fence_fd, -1 /* forever */);
685        }
686    }
687
688    result = GetData(device).driver.AcquireImageANDROID(
689        device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
690    if (result != VK_SUCCESS) {
691        // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
692        // even if the call fails. We could close it ourselves on failure, but
693        // that would create a race condition if the driver closes it on a
694        // failure path: some other thread might create an fd with the same
695        // number between the time the driver closes it and the time we close
696        // it. We must assume one of: the driver *always* closes it even on
697        // failure, or *never* closes it on failure.
698        window->cancelBuffer(window, buffer, fence_fd);
699        swapchain.images[idx].dequeued = false;
700        swapchain.images[idx].dequeue_fence = -1;
701        return result;
702    }
703
704    *image_index = idx;
705    return VK_SUCCESS;
706}
707
708VKAPI_ATTR
709VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
710    ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
711             "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
712             present_info->sType);
713    ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
714
715    const auto& dispatch = GetData(queue).driver;
716    VkResult final_result = VK_SUCCESS;
717    for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
718        Swapchain& swapchain =
719            *SwapchainFromHandle(present_info->pSwapchains[sc]);
720        ANativeWindow* window = swapchain.surface.window.get();
721        uint32_t image_idx = present_info->pImageIndices[sc];
722        Swapchain::Image& img = swapchain.images[image_idx];
723        VkResult result;
724        int err;
725
726        int fence = -1;
727        result = dispatch.QueueSignalReleaseImageANDROID(
728            queue, present_info->waitSemaphoreCount,
729            present_info->pWaitSemaphores, img.image, &fence);
730        if (result != VK_SUCCESS) {
731            ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
732            if (present_info->pResults)
733                present_info->pResults[sc] = result;
734            if (final_result == VK_SUCCESS)
735                final_result = result;
736            // TODO(jessehall): What happens to the buffer here? Does the app
737            // still own it or not, i.e. should we cancel the buffer? Hard to
738            // do correctly without synchronizing, though I guess we could wait
739            // for the queue to idle.
740            continue;
741        }
742
743        err = window->queueBuffer(window, img.buffer.get(), fence);
744        if (err != 0) {
745            // TODO(jessehall): What now? We should probably cancel the buffer,
746            // I guess?
747            ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
748            if (present_info->pResults)
749                present_info->pResults[sc] = result;
750            if (final_result == VK_SUCCESS)
751                final_result = VK_ERROR_INITIALIZATION_FAILED;
752            continue;
753        }
754
755        if (img.dequeue_fence != -1) {
756            close(img.dequeue_fence);
757            img.dequeue_fence = -1;
758        }
759        img.dequeued = false;
760
761        if (present_info->pResults)
762            present_info->pResults[sc] = VK_SUCCESS;
763    }
764
765    return final_result;
766}
767
768}  // namespace driver
769}  // namespace vulkan
770