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