swapchain.cpp revision dc22507e6fd6659c886aa1218f7681fd43b74598
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    VkSwapchainKHR swapchain_handle;
113};
114
115VkSurfaceKHR HandleFromSurface(Surface* surface) {
116    return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface));
117}
118
119Surface* SurfaceFromHandle(VkSurfaceKHR handle) {
120    return reinterpret_cast<Surface*>(handle);
121}
122
123struct Swapchain {
124    Swapchain(Surface& surface_, uint32_t num_images_)
125        : surface(surface_), num_images(num_images_) {}
126
127    Surface& surface;
128    uint32_t num_images;
129
130    struct Image {
131        Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
132        VkImage image;
133        android::sp<ANativeWindowBuffer> buffer;
134        // The fence is only valid when the buffer is dequeued, and should be
135        // -1 any other time. When valid, we own the fd, and must ensure it is
136        // closed: either by closing it explicitly when queueing the buffer,
137        // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
138        int dequeue_fence;
139        bool dequeued;
140    } images[android::BufferQueue::NUM_BUFFER_SLOTS];
141};
142
143VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
144    return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
145}
146
147Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
148    return reinterpret_cast<Swapchain*>(handle);
149}
150
151void ReleaseSwapchainImage(VkDevice device,
152                           ANativeWindow* window,
153                           int release_fence,
154                           Swapchain::Image& image) {
155    ALOG_ASSERT(release_fence == -1 || image.dequeued,
156                "ReleaseSwapchainImage: can't provide a release fence for "
157                "non-dequeued images");
158
159    if (image.dequeued) {
160        if (release_fence >= 0) {
161            // We get here from vkQueuePresentKHR. The application is
162            // responsible for creating an execution dependency chain from
163            // vkAcquireNextImage (dequeue_fence) to vkQueuePresentKHR
164            // (release_fence), so we can drop the dequeue_fence here.
165            if (image.dequeue_fence >= 0)
166                close(image.dequeue_fence);
167        } else {
168            // We get here during swapchain destruction, or various serious
169            // error cases e.g. when we can't create the release_fence during
170            // vkQueuePresentKHR. In non-error cases, the dequeue_fence should
171            // have already signalled, since the swapchain images are supposed
172            // to be idle before the swapchain is destroyed. In error cases,
173            // there may be rendering in flight to the image, but since we
174            // weren't able to create a release_fence, waiting for the
175            // dequeue_fence is about the best we can do.
176            release_fence = image.dequeue_fence;
177        }
178        image.dequeue_fence = -1;
179
180        if (window) {
181            window->cancelBuffer(window, image.buffer.get(), release_fence);
182        } else {
183            if (release_fence >= 0) {
184                sync_wait(release_fence, -1 /* forever */);
185                close(release_fence);
186            }
187        }
188
189        image.dequeued = false;
190    }
191
192    if (image.image) {
193        GetData(device).driver.DestroyImage(device, image.image, nullptr);
194        image.image = VK_NULL_HANDLE;
195    }
196
197    image.buffer.clear();
198}
199
200void OrphanSwapchain(VkDevice device, Swapchain* swapchain) {
201    if (swapchain->surface.swapchain_handle != HandleFromSwapchain(swapchain))
202        return;
203    const auto& dispatch = GetData(device).driver;
204    for (uint32_t i = 0; i < swapchain->num_images; i++) {
205        if (!swapchain->images[i].dequeued)
206            ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]);
207    }
208    swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
209}
210
211}  // anonymous namespace
212
213VKAPI_ATTR
214VkResult CreateAndroidSurfaceKHR(
215    VkInstance instance,
216    const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
217    const VkAllocationCallbacks* allocator,
218    VkSurfaceKHR* out_surface) {
219    if (!allocator)
220        allocator = &GetData(instance).allocator;
221    void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
222                                         alignof(Surface),
223                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
224    if (!mem)
225        return VK_ERROR_OUT_OF_HOST_MEMORY;
226    Surface* surface = new (mem) Surface;
227
228    surface->window = pCreateInfo->window;
229    surface->swapchain_handle = VK_NULL_HANDLE;
230
231    // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
232    int err =
233        native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
234    if (err != 0) {
235        // TODO(jessehall): Improve error reporting. Can we enumerate possible
236        // errors and translate them to valid Vulkan result codes?
237        ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
238              err);
239        surface->~Surface();
240        allocator->pfnFree(allocator->pUserData, surface);
241        return VK_ERROR_INITIALIZATION_FAILED;
242    }
243
244    *out_surface = HandleFromSurface(surface);
245    return VK_SUCCESS;
246}
247
248VKAPI_ATTR
249void DestroySurfaceKHR(VkInstance instance,
250                       VkSurfaceKHR surface_handle,
251                       const VkAllocationCallbacks* allocator) {
252    Surface* surface = SurfaceFromHandle(surface_handle);
253    if (!surface)
254        return;
255    native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL);
256    ALOGE_IF(surface->swapchain_handle != VK_NULL_HANDLE,
257             "destroyed VkSurfaceKHR 0x%" PRIx64
258             " has active VkSwapchainKHR 0x%" PRIx64,
259             reinterpret_cast<uint64_t>(surface_handle),
260             reinterpret_cast<uint64_t>(surface->swapchain_handle));
261    surface->~Surface();
262    if (!allocator)
263        allocator = &GetData(instance).allocator;
264    allocator->pfnFree(allocator->pUserData, surface);
265}
266
267VKAPI_ATTR
268VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
269                                            uint32_t /*queue_family*/,
270                                            VkSurfaceKHR /*surface*/,
271                                            VkBool32* supported) {
272    *supported = VK_TRUE;
273    return VK_SUCCESS;
274}
275
276VKAPI_ATTR
277VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(
278    VkPhysicalDevice /*pdev*/,
279    VkSurfaceKHR surface,
280    VkSurfaceCapabilitiesKHR* capabilities) {
281    int err;
282    ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
283
284    int width, height;
285    err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
286    if (err != 0) {
287        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
288              strerror(-err), err);
289        return VK_ERROR_INITIALIZATION_FAILED;
290    }
291    err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
292    if (err != 0) {
293        ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
294              strerror(-err), err);
295        return VK_ERROR_INITIALIZATION_FAILED;
296    }
297
298    int transform_hint;
299    err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
300    if (err != 0) {
301        ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
302              strerror(-err), err);
303        return VK_ERROR_INITIALIZATION_FAILED;
304    }
305
306    // TODO(jessehall): Figure out what the min/max values should be.
307    capabilities->minImageCount = 2;
308    capabilities->maxImageCount = 3;
309
310    capabilities->currentExtent =
311        VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
312
313    // TODO(jessehall): Figure out what the max extent should be. Maximum
314    // texture dimension maybe?
315    capabilities->minImageExtent = VkExtent2D{1, 1};
316    capabilities->maxImageExtent = VkExtent2D{4096, 4096};
317
318    capabilities->maxImageArrayLayers = 1;
319
320    capabilities->supportedTransforms = kSupportedTransforms;
321    capabilities->currentTransform =
322        TranslateNativeToVulkanTransform(transform_hint);
323
324    // On Android, window composition is a WindowManager property, not something
325    // associated with the bufferqueue. It can't be changed from here.
326    capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
327
328    // TODO(jessehall): I think these are right, but haven't thought hard about
329    // it. Do we need to query the driver for support of any of these?
330    // Currently not included:
331    // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
332    // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
333    // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
334    capabilities->supportedUsageFlags =
335        VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
336        VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
337        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
338        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
339
340    return VK_SUCCESS;
341}
342
343VKAPI_ATTR
344VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/,
345                                            VkSurfaceKHR /*surface*/,
346                                            uint32_t* count,
347                                            VkSurfaceFormatKHR* formats) {
348    // TODO(jessehall): Fill out the set of supported formats. Longer term, add
349    // a new gralloc method to query whether a (format, usage) pair is
350    // supported, and check that for each gralloc format that corresponds to a
351    // Vulkan format. Shorter term, just add a few more formats to the ones
352    // hardcoded below.
353
354    const VkSurfaceFormatKHR kFormats[] = {
355        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
356        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
357        {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
358    };
359    const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
360
361    VkResult result = VK_SUCCESS;
362    if (formats) {
363        if (*count < kNumFormats)
364            result = VK_INCOMPLETE;
365        std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
366    }
367    *count = kNumFormats;
368    return result;
369}
370
371VKAPI_ATTR
372VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/,
373                                                 VkSurfaceKHR /*surface*/,
374                                                 uint32_t* count,
375                                                 VkPresentModeKHR* modes) {
376    const VkPresentModeKHR kModes[] = {
377        VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
378    };
379    const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
380
381    VkResult result = VK_SUCCESS;
382    if (modes) {
383        if (*count < kNumModes)
384            result = VK_INCOMPLETE;
385        std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
386    }
387    *count = kNumModes;
388    return result;
389}
390
391VKAPI_ATTR
392VkResult CreateSwapchainKHR(VkDevice device,
393                            const VkSwapchainCreateInfoKHR* create_info,
394                            const VkAllocationCallbacks* allocator,
395                            VkSwapchainKHR* swapchain_handle) {
396    int err;
397    VkResult result = VK_SUCCESS;
398
399    ALOGV("vkCreateSwapchainKHR: surface=0x%" PRIx64
400          " minImageCount=%u imageFormat=%u imageColorSpace=%u"
401          " imageExtent=%ux%u imageUsage=%#x preTransform=%u presentMode=%u"
402          " oldSwapchain=0x%" PRIx64,
403          reinterpret_cast<uint64_t>(create_info->surface),
404          create_info->minImageCount, create_info->imageFormat,
405          create_info->imageColorSpace, create_info->imageExtent.width,
406          create_info->imageExtent.height, create_info->imageUsage,
407          create_info->preTransform, create_info->presentMode,
408          reinterpret_cast<uint64_t>(create_info->oldSwapchain));
409
410    if (!allocator)
411        allocator = &GetData(device).allocator;
412
413    ALOGE_IF(create_info->imageArrayLayers != 1,
414             "swapchain imageArrayLayers=%u not supported",
415             create_info->imageArrayLayers);
416    ALOGE_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
417             "swapchain imageColorSpace=%u not supported",
418             create_info->imageColorSpace);
419    ALOGE_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
420             "swapchain preTransform=%#x not supported",
421             create_info->preTransform);
422    ALOGE_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
423               create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
424             "swapchain presentMode=%u not supported",
425             create_info->presentMode);
426
427    Surface& surface = *SurfaceFromHandle(create_info->surface);
428
429    if (surface.swapchain_handle != create_info->oldSwapchain) {
430        ALOGE("Can't create a swapchain for VkSurfaceKHR 0x%" PRIx64
431              " because it already has active swapchain 0x%" PRIx64
432              " but VkSwapchainCreateInfo::oldSwapchain=0x%" PRIx64,
433              reinterpret_cast<uint64_t>(create_info->surface),
434              reinterpret_cast<uint64_t>(surface.swapchain_handle),
435              reinterpret_cast<uint64_t>(create_info->oldSwapchain));
436        return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
437    }
438    if (create_info->oldSwapchain != VK_NULL_HANDLE)
439        OrphanSwapchain(device, SwapchainFromHandle(create_info->oldSwapchain));
440
441    // -- Reset the native window --
442    // The native window might have been used previously, and had its properties
443    // changed from defaults. That will affect the answer we get for queries
444    // like MIN_UNDEQUED_BUFFERS. Reset to a known/default state before we
445    // attempt such queries.
446
447    // The native window only allows dequeueing all buffers before any have
448    // been queued, since after that point at least one is assumed to be in
449    // non-FREE state at any given time. Disconnecting and re-connecting
450    // orphans the previous buffers, getting us back to the state where we can
451    // dequeue all buffers.
452    err = native_window_api_disconnect(surface.window.get(),
453                                       NATIVE_WINDOW_API_EGL);
454    ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)",
455             strerror(-err), err);
456    err =
457        native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL);
458    ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)",
459             strerror(-err), err);
460
461    err = native_window_set_buffer_count(surface.window.get(), 0);
462    if (err != 0) {
463        ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
464              strerror(-err), err);
465        return VK_ERROR_INITIALIZATION_FAILED;
466    }
467
468    err = surface.window->setSwapInterval(surface.window.get(), 1);
469    if (err != 0) {
470        // TODO(jessehall): Improve error reporting. Can we enumerate possible
471        // errors and translate them to valid Vulkan result codes?
472        ALOGE("native_window->setSwapInterval(1) failed: %s (%d)",
473              strerror(-err), err);
474        return VK_ERROR_INITIALIZATION_FAILED;
475    }
476
477    // -- Configure the native window --
478
479    const auto& dispatch = GetData(device).driver;
480
481    int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
482    switch (create_info->imageFormat) {
483        case VK_FORMAT_R8G8B8A8_UNORM:
484        case VK_FORMAT_R8G8B8A8_SRGB:
485            native_format = HAL_PIXEL_FORMAT_RGBA_8888;
486            break;
487        case VK_FORMAT_R5G6B5_UNORM_PACK16:
488            native_format = HAL_PIXEL_FORMAT_RGB_565;
489            break;
490        default:
491            ALOGE("unsupported swapchain format %d", create_info->imageFormat);
492            break;
493    }
494    err = native_window_set_buffers_format(surface.window.get(), native_format);
495    if (err != 0) {
496        // TODO(jessehall): Improve error reporting. Can we enumerate possible
497        // errors and translate them to valid Vulkan result codes?
498        ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
499              native_format, strerror(-err), err);
500        return VK_ERROR_INITIALIZATION_FAILED;
501    }
502    err = native_window_set_buffers_data_space(surface.window.get(),
503                                               HAL_DATASPACE_SRGB_LINEAR);
504    if (err != 0) {
505        // TODO(jessehall): Improve error reporting. Can we enumerate possible
506        // errors and translate them to valid Vulkan result codes?
507        ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
508              HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err);
509        return VK_ERROR_INITIALIZATION_FAILED;
510    }
511
512    err = native_window_set_buffers_dimensions(
513        surface.window.get(), static_cast<int>(create_info->imageExtent.width),
514        static_cast<int>(create_info->imageExtent.height));
515    if (err != 0) {
516        // TODO(jessehall): Improve error reporting. Can we enumerate possible
517        // errors and translate them to valid Vulkan result codes?
518        ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
519              create_info->imageExtent.width, create_info->imageExtent.height,
520              strerror(-err), err);
521        return VK_ERROR_INITIALIZATION_FAILED;
522    }
523
524    // VkSwapchainCreateInfo::preTransform indicates the transformation the app
525    // applied during rendering. native_window_set_transform() expects the
526    // inverse: the transform the app is requesting that the compositor perform
527    // during composition. With native windows, pre-transform works by rendering
528    // with the same transform the compositor is applying (as in Vulkan), but
529    // then requesting the inverse transform, so that when the compositor does
530    // it's job the two transforms cancel each other out and the compositor ends
531    // up applying an identity transform to the app's buffer.
532    err = native_window_set_buffers_transform(
533        surface.window.get(),
534        InvertTransformToNative(create_info->preTransform));
535    if (err != 0) {
536        // TODO(jessehall): Improve error reporting. Can we enumerate possible
537        // errors and translate them to valid Vulkan result codes?
538        ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
539              InvertTransformToNative(create_info->preTransform),
540              strerror(-err), err);
541        return VK_ERROR_INITIALIZATION_FAILED;
542    }
543
544    err = native_window_set_scaling_mode(
545        surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
546    if (err != 0) {
547        // TODO(jessehall): Improve error reporting. Can we enumerate possible
548        // errors and translate them to valid Vulkan result codes?
549        ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
550              strerror(-err), err);
551        return VK_ERROR_INITIALIZATION_FAILED;
552    }
553
554    int query_value;
555    err = surface.window->query(surface.window.get(),
556                                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
557                                &query_value);
558    if (err != 0 || query_value < 0) {
559        // TODO(jessehall): Improve error reporting. Can we enumerate possible
560        // errors and translate them to valid Vulkan result codes?
561        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
562              query_value);
563        return VK_ERROR_INITIALIZATION_FAILED;
564    }
565    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
566    // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
567    // async mode or not, and assumes not. But in async mode, the BufferQueue
568    // requires an extra undequeued buffer.
569    // See BufferQueueCore::getMinUndequeuedBufferCountLocked().
570    if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
571        min_undequeued_buffers += 1;
572
573    uint32_t num_images =
574        (create_info->minImageCount - 1) + min_undequeued_buffers;
575    err = native_window_set_buffer_count(surface.window.get(), num_images);
576    if (err != 0) {
577        // TODO(jessehall): Improve error reporting. Can we enumerate possible
578        // errors and translate them to valid Vulkan result codes?
579        ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
580              strerror(-err), err);
581        return VK_ERROR_INITIALIZATION_FAILED;
582    }
583
584    int gralloc_usage = 0;
585    // TODO(jessehall): Remove conditional once all drivers have been updated
586    if (dispatch.GetSwapchainGrallocUsageANDROID) {
587        result = dispatch.GetSwapchainGrallocUsageANDROID(
588            device, create_info->imageFormat, create_info->imageUsage,
589            &gralloc_usage);
590        if (result != VK_SUCCESS) {
591            ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
592            return VK_ERROR_INITIALIZATION_FAILED;
593        }
594    } else {
595        gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
596    }
597    err = native_window_set_usage(surface.window.get(), gralloc_usage);
598    if (err != 0) {
599        // TODO(jessehall): Improve error reporting. Can we enumerate possible
600        // errors and translate them to valid Vulkan result codes?
601        ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
602        return VK_ERROR_INITIALIZATION_FAILED;
603    }
604
605    int swap_interval =
606        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
607    err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
608    if (err != 0) {
609        // TODO(jessehall): Improve error reporting. Can we enumerate possible
610        // errors and translate them to valid Vulkan result codes?
611        ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)",
612              swap_interval, strerror(-err), err);
613        return VK_ERROR_INITIALIZATION_FAILED;
614    }
615
616    // -- Allocate our Swapchain object --
617    // After this point, we must deallocate the swapchain on error.
618
619    void* mem = allocator->pfnAllocation(allocator->pUserData,
620                                         sizeof(Swapchain), alignof(Swapchain),
621                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
622    if (!mem)
623        return VK_ERROR_OUT_OF_HOST_MEMORY;
624    Swapchain* swapchain = new (mem) Swapchain(surface, num_images);
625
626    // -- Dequeue all buffers and create a VkImage for each --
627    // Any failures during or after this must cancel the dequeued buffers.
628
629    VkNativeBufferANDROID image_native_buffer = {
630#pragma clang diagnostic push
631#pragma clang diagnostic ignored "-Wold-style-cast"
632        .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
633#pragma clang diagnostic pop
634        .pNext = nullptr,
635    };
636    VkImageCreateInfo image_create = {
637        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
638        .pNext = &image_native_buffer,
639        .imageType = VK_IMAGE_TYPE_2D,
640        .format = create_info->imageFormat,
641        .extent = {0, 0, 1},
642        .mipLevels = 1,
643        .arrayLayers = 1,
644        .samples = VK_SAMPLE_COUNT_1_BIT,
645        .tiling = VK_IMAGE_TILING_OPTIMAL,
646        .usage = create_info->imageUsage,
647        .flags = 0,
648        .sharingMode = create_info->imageSharingMode,
649        .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
650        .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
651    };
652
653    for (uint32_t i = 0; i < num_images; i++) {
654        Swapchain::Image& img = swapchain->images[i];
655
656        ANativeWindowBuffer* buffer;
657        err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
658                                            &img.dequeue_fence);
659        if (err != 0) {
660            // TODO(jessehall): Improve error reporting. Can we enumerate
661            // possible errors and translate them to valid Vulkan result codes?
662            ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
663            result = VK_ERROR_INITIALIZATION_FAILED;
664            break;
665        }
666        img.buffer = buffer;
667        img.dequeued = true;
668
669        image_create.extent =
670            VkExtent3D{static_cast<uint32_t>(img.buffer->width),
671                       static_cast<uint32_t>(img.buffer->height),
672                       1};
673        image_native_buffer.handle = img.buffer->handle;
674        image_native_buffer.stride = img.buffer->stride;
675        image_native_buffer.format = img.buffer->format;
676        image_native_buffer.usage = img.buffer->usage;
677
678        result =
679            dispatch.CreateImage(device, &image_create, nullptr, &img.image);
680        if (result != VK_SUCCESS) {
681            ALOGD("vkCreateImage w/ native buffer failed: %u", result);
682            break;
683        }
684    }
685
686    // -- Cancel all buffers, returning them to the queue --
687    // If an error occurred before, also destroy the VkImage and release the
688    // buffer reference. Otherwise, we retain a strong reference to the buffer.
689    //
690    // TODO(jessehall): The error path here is the same as DestroySwapchain,
691    // but not the non-error path. Should refactor/unify.
692    for (uint32_t i = 0; i < num_images; i++) {
693        Swapchain::Image& img = swapchain->images[i];
694        if (img.dequeued) {
695            surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
696                                         img.dequeue_fence);
697            img.dequeue_fence = -1;
698            img.dequeued = false;
699        }
700        if (result != VK_SUCCESS) {
701            if (img.image)
702                dispatch.DestroyImage(device, img.image, nullptr);
703        }
704    }
705
706    if (result != VK_SUCCESS) {
707        swapchain->~Swapchain();
708        allocator->pfnFree(allocator->pUserData, swapchain);
709        return result;
710    }
711
712    surface.swapchain_handle = HandleFromSwapchain(swapchain);
713    *swapchain_handle = surface.swapchain_handle;
714    return VK_SUCCESS;
715}
716
717VKAPI_ATTR
718void DestroySwapchainKHR(VkDevice device,
719                         VkSwapchainKHR swapchain_handle,
720                         const VkAllocationCallbacks* allocator) {
721    const auto& dispatch = GetData(device).driver;
722    Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
723    ANativeWindow* window =
724        (swapchain->surface.swapchain_handle == swapchain_handle)
725            ? swapchain->surface.window.get()
726            : nullptr;
727
728    for (uint32_t i = 0; i < swapchain->num_images; i++)
729        ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
730    if (swapchain->surface.swapchain_handle == swapchain_handle)
731        swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
732    if (!allocator)
733        allocator = &GetData(device).allocator;
734    swapchain->~Swapchain();
735    allocator->pfnFree(allocator->pUserData, swapchain);
736}
737
738VKAPI_ATTR
739VkResult GetSwapchainImagesKHR(VkDevice,
740                               VkSwapchainKHR swapchain_handle,
741                               uint32_t* count,
742                               VkImage* images) {
743    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
744    ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle,
745             "getting images for non-active swapchain 0x%" PRIx64
746             "; only dequeued image handles are valid",
747             reinterpret_cast<uint64_t>(swapchain_handle));
748    VkResult result = VK_SUCCESS;
749    if (images) {
750        uint32_t n = swapchain.num_images;
751        if (*count < swapchain.num_images) {
752            n = *count;
753            result = VK_INCOMPLETE;
754        }
755        for (uint32_t i = 0; i < n; i++)
756            images[i] = swapchain.images[i].image;
757    }
758    *count = swapchain.num_images;
759    return result;
760}
761
762VKAPI_ATTR
763VkResult AcquireNextImageKHR(VkDevice device,
764                             VkSwapchainKHR swapchain_handle,
765                             uint64_t timeout,
766                             VkSemaphore semaphore,
767                             VkFence vk_fence,
768                             uint32_t* image_index) {
769    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
770    ANativeWindow* window = swapchain.surface.window.get();
771    VkResult result;
772    int err;
773
774    if (swapchain.surface.swapchain_handle != swapchain_handle)
775        return VK_ERROR_OUT_OF_DATE_KHR;
776
777    ALOGW_IF(
778        timeout != UINT64_MAX,
779        "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
780
781    ANativeWindowBuffer* buffer;
782    int fence_fd;
783    err = window->dequeueBuffer(window, &buffer, &fence_fd);
784    if (err != 0) {
785        // TODO(jessehall): Improve error reporting. Can we enumerate possible
786        // errors and translate them to valid Vulkan result codes?
787        ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
788        return VK_ERROR_INITIALIZATION_FAILED;
789    }
790
791    uint32_t idx;
792    for (idx = 0; idx < swapchain.num_images; idx++) {
793        if (swapchain.images[idx].buffer.get() == buffer) {
794            swapchain.images[idx].dequeued = true;
795            swapchain.images[idx].dequeue_fence = fence_fd;
796            break;
797        }
798    }
799    if (idx == swapchain.num_images) {
800        ALOGE("dequeueBuffer returned unrecognized buffer");
801        window->cancelBuffer(window, buffer, fence_fd);
802        return VK_ERROR_OUT_OF_DATE_KHR;
803    }
804
805    int fence_clone = -1;
806    if (fence_fd != -1) {
807        fence_clone = dup(fence_fd);
808        if (fence_clone == -1) {
809            ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
810                  strerror(errno), errno);
811            sync_wait(fence_fd, -1 /* forever */);
812        }
813    }
814
815    result = GetData(device).driver.AcquireImageANDROID(
816        device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
817    if (result != VK_SUCCESS) {
818        // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
819        // even if the call fails. We could close it ourselves on failure, but
820        // that would create a race condition if the driver closes it on a
821        // failure path: some other thread might create an fd with the same
822        // number between the time the driver closes it and the time we close
823        // it. We must assume one of: the driver *always* closes it even on
824        // failure, or *never* closes it on failure.
825        window->cancelBuffer(window, buffer, fence_fd);
826        swapchain.images[idx].dequeued = false;
827        swapchain.images[idx].dequeue_fence = -1;
828        return result;
829    }
830
831    *image_index = idx;
832    return VK_SUCCESS;
833}
834
835static VkResult WorstPresentResult(VkResult a, VkResult b) {
836    // See the error ranking for vkQueuePresentKHR at the end of section 29.6
837    // (in spec version 1.0.14).
838    static const VkResult kWorstToBest[] = {
839        VK_ERROR_DEVICE_LOST,
840        VK_ERROR_SURFACE_LOST_KHR,
841        VK_ERROR_OUT_OF_DATE_KHR,
842        VK_ERROR_OUT_OF_DEVICE_MEMORY,
843        VK_ERROR_OUT_OF_HOST_MEMORY,
844        VK_SUBOPTIMAL_KHR,
845    };
846    for (auto result : kWorstToBest) {
847        if (a == result || b == result)
848            return result;
849    }
850    ALOG_ASSERT(a == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", a);
851    ALOG_ASSERT(b == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", b);
852    return a != VK_SUCCESS ? a : b;
853}
854
855VKAPI_ATTR
856VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
857    ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
858             "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
859             present_info->sType);
860    ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
861
862    VkDevice device = GetData(queue).driver_device;
863    const auto& dispatch = GetData(queue).driver;
864    VkResult final_result = VK_SUCCESS;
865
866    for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
867        Swapchain& swapchain =
868            *SwapchainFromHandle(present_info->pSwapchains[sc]);
869        uint32_t image_idx = present_info->pImageIndices[sc];
870        Swapchain::Image& img = swapchain.images[image_idx];
871        VkResult swapchain_result = VK_SUCCESS;
872        VkResult result;
873        int err;
874
875        int fence = -1;
876        result = dispatch.QueueSignalReleaseImageANDROID(
877            queue, present_info->waitSemaphoreCount,
878            present_info->pWaitSemaphores, img.image, &fence);
879        if (result != VK_SUCCESS) {
880            ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
881            swapchain_result = result;
882        }
883
884        if (swapchain.surface.swapchain_handle ==
885            present_info->pSwapchains[sc]) {
886            ANativeWindow* window = swapchain.surface.window.get();
887            if (swapchain_result == VK_SUCCESS) {
888                err = window->queueBuffer(window, img.buffer.get(), fence);
889                // queueBuffer always closes fence, even on error
890                if (err != 0) {
891                    // TODO(jessehall): What now? We should probably cancel the
892                    // buffer, I guess?
893                    ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
894                    swapchain_result = WorstPresentResult(
895                        swapchain_result, VK_ERROR_OUT_OF_DATE_KHR);
896                }
897                if (img.dequeue_fence >= 0) {
898                    close(img.dequeue_fence);
899                    img.dequeue_fence = -1;
900                }
901                img.dequeued = false;
902            }
903            if (swapchain_result != VK_SUCCESS) {
904                ReleaseSwapchainImage(device, window, fence, img);
905                OrphanSwapchain(device, &swapchain);
906            }
907        } else {
908            ReleaseSwapchainImage(device, nullptr, fence, img);
909            swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
910        }
911
912        if (present_info->pResults)
913            present_info->pResults[sc] = swapchain_result;
914
915        if (swapchain_result != final_result)
916            final_result = WorstPresentResult(final_result, swapchain_result);
917    }
918
919    return final_result;
920}
921
922}  // namespace driver
923}  // namespace vulkan
924