swapchain.cpp revision 3d1c82a750046f055951242bf27909ad7d9cdf52
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    ALOGV("vkCreateSwapchainKHR: surface=0x%" PRIx64
333          " minImageCount=%u imageFormat=%u imageColorSpace=%u"
334          " imageExtent=%ux%u imageUsage=%#x preTransform=%u presentMode=%u"
335          " oldSwapchain=0x%" PRIx64,
336          reinterpret_cast<uint64_t>(create_info->surface),
337          create_info->minImageCount, create_info->imageFormat,
338          create_info->imageColorSpace, create_info->imageExtent.width,
339          create_info->imageExtent.height, create_info->imageUsage,
340          create_info->preTransform, create_info->presentMode,
341          reinterpret_cast<uint64_t>(create_info->oldSwapchain));
342
343    if (!allocator)
344        allocator = &GetData(device).allocator;
345
346    ALOGV_IF(create_info->imageArrayLayers != 1,
347             "Swapchain imageArrayLayers (%u) != 1 not supported",
348             create_info->imageArrayLayers);
349
350    ALOGE_IF(create_info->imageColorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR,
351             "color spaces other than SRGB_NONLINEAR not yet implemented");
352    ALOGE_IF(create_info->oldSwapchain,
353             "swapchain re-creation not yet implemented");
354    ALOGE_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
355             "swapchain preTransform %d not supported",
356             create_info->preTransform);
357    ALOGW_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
358               create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
359             "swapchain present mode %d not supported",
360             create_info->presentMode);
361
362    Surface& surface = *SurfaceFromHandle(create_info->surface);
363
364    // -- Reset the native window --
365    // The native window might have been used previously, and had its properties
366    // changed from defaults. That will affect the answer we get for queries
367    // like MIN_UNDEQUED_BUFFERS. Reset to a known/default state before we
368    // attempt such queries.
369
370    err = native_window_set_buffer_count(surface.window.get(), 0);
371    if (err != 0) {
372        ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
373              strerror(-err), err);
374        return VK_ERROR_INITIALIZATION_FAILED;
375    }
376
377    err = surface.window->setSwapInterval(surface.window.get(), 1);
378    if (err != 0) {
379        // TODO(jessehall): Improve error reporting. Can we enumerate possible
380        // errors and translate them to valid Vulkan result codes?
381        ALOGE("native_window->setSwapInterval(1) failed: %s (%d)",
382              strerror(-err), err);
383        return VK_ERROR_INITIALIZATION_FAILED;
384    }
385
386    // -- Configure the native window --
387
388    const auto& dispatch = GetData(device).driver;
389
390    int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
391    switch (create_info->imageFormat) {
392        case VK_FORMAT_R8G8B8A8_UNORM:
393        case VK_FORMAT_R8G8B8A8_SRGB:
394            native_format = HAL_PIXEL_FORMAT_RGBA_8888;
395            break;
396        case VK_FORMAT_R5G6B5_UNORM_PACK16:
397            native_format = HAL_PIXEL_FORMAT_RGB_565;
398            break;
399        default:
400            ALOGE("unsupported swapchain format %d", create_info->imageFormat);
401            break;
402    }
403    err = native_window_set_buffers_format(surface.window.get(), native_format);
404    if (err != 0) {
405        // TODO(jessehall): Improve error reporting. Can we enumerate possible
406        // errors and translate them to valid Vulkan result codes?
407        ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
408              native_format, strerror(-err), err);
409        return VK_ERROR_INITIALIZATION_FAILED;
410    }
411    err = native_window_set_buffers_data_space(surface.window.get(),
412                                               HAL_DATASPACE_SRGB_LINEAR);
413    if (err != 0) {
414        // TODO(jessehall): Improve error reporting. Can we enumerate possible
415        // errors and translate them to valid Vulkan result codes?
416        ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
417              HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err);
418        return VK_ERROR_INITIALIZATION_FAILED;
419    }
420
421    err = native_window_set_buffers_dimensions(
422        surface.window.get(), static_cast<int>(create_info->imageExtent.width),
423        static_cast<int>(create_info->imageExtent.height));
424    if (err != 0) {
425        // TODO(jessehall): Improve error reporting. Can we enumerate possible
426        // errors and translate them to valid Vulkan result codes?
427        ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
428              create_info->imageExtent.width, create_info->imageExtent.height,
429              strerror(-err), err);
430        return VK_ERROR_INITIALIZATION_FAILED;
431    }
432
433    // VkSwapchainCreateInfo::preTransform indicates the transformation the app
434    // applied during rendering. native_window_set_transform() expects the
435    // inverse: the transform the app is requesting that the compositor perform
436    // during composition. With native windows, pre-transform works by rendering
437    // with the same transform the compositor is applying (as in Vulkan), but
438    // then requesting the inverse transform, so that when the compositor does
439    // it's job the two transforms cancel each other out and the compositor ends
440    // up applying an identity transform to the app's buffer.
441    err = native_window_set_buffers_transform(
442        surface.window.get(),
443        InvertTransformToNative(create_info->preTransform));
444    if (err != 0) {
445        // TODO(jessehall): Improve error reporting. Can we enumerate possible
446        // errors and translate them to valid Vulkan result codes?
447        ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
448              InvertTransformToNative(create_info->preTransform),
449              strerror(-err), err);
450        return VK_ERROR_INITIALIZATION_FAILED;
451    }
452
453    err = native_window_set_scaling_mode(
454        surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
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_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
459              strerror(-err), err);
460        return VK_ERROR_INITIALIZATION_FAILED;
461    }
462
463    int query_value;
464    err = surface.window->query(surface.window.get(),
465                                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
466                                &query_value);
467    if (err != 0 || query_value < 0) {
468        // TODO(jessehall): Improve error reporting. Can we enumerate possible
469        // errors and translate them to valid Vulkan result codes?
470        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
471              query_value);
472        return VK_ERROR_INITIALIZATION_FAILED;
473    }
474    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
475    // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
476    // async mode or not, and assumes not. But in async mode, the BufferQueue
477    // requires an extra undequeued buffer.
478    // See BufferQueueCore::getMinUndequeuedBufferCountLocked().
479    if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
480        min_undequeued_buffers += 1;
481
482    uint32_t num_images =
483        (create_info->minImageCount - 1) + min_undequeued_buffers;
484    err = native_window_set_buffer_count(surface.window.get(), num_images);
485    if (err != 0) {
486        // TODO(jessehall): Improve error reporting. Can we enumerate possible
487        // errors and translate them to valid Vulkan result codes?
488        ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
489              strerror(-err), err);
490        return VK_ERROR_INITIALIZATION_FAILED;
491    }
492
493    int gralloc_usage = 0;
494    // TODO(jessehall): Remove conditional once all drivers have been updated
495    if (dispatch.GetSwapchainGrallocUsageANDROID) {
496        result = dispatch.GetSwapchainGrallocUsageANDROID(
497            device, create_info->imageFormat, create_info->imageUsage,
498            &gralloc_usage);
499        if (result != VK_SUCCESS) {
500            ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
501            return VK_ERROR_INITIALIZATION_FAILED;
502        }
503    } else {
504        gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
505    }
506    err = native_window_set_usage(surface.window.get(), gralloc_usage);
507    if (err != 0) {
508        // TODO(jessehall): Improve error reporting. Can we enumerate possible
509        // errors and translate them to valid Vulkan result codes?
510        ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
511        return VK_ERROR_INITIALIZATION_FAILED;
512    }
513
514    int swap_interval =
515        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
516    err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
517    if (err != 0) {
518        // TODO(jessehall): Improve error reporting. Can we enumerate possible
519        // errors and translate them to valid Vulkan result codes?
520        ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)",
521              swap_interval, strerror(-err), err);
522        return VK_ERROR_INITIALIZATION_FAILED;
523    }
524
525    // -- Allocate our Swapchain object --
526    // After this point, we must deallocate the swapchain on error.
527
528    void* mem = allocator->pfnAllocation(allocator->pUserData,
529                                         sizeof(Swapchain), alignof(Swapchain),
530                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
531    if (!mem)
532        return VK_ERROR_OUT_OF_HOST_MEMORY;
533    Swapchain* swapchain = new (mem) Swapchain(surface, num_images);
534
535    // -- Dequeue all buffers and create a VkImage for each --
536    // Any failures during or after this must cancel the dequeued buffers.
537
538    VkNativeBufferANDROID image_native_buffer = {
539#pragma clang diagnostic push
540#pragma clang diagnostic ignored "-Wold-style-cast"
541        .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
542#pragma clang diagnostic pop
543        .pNext = nullptr,
544    };
545    VkImageCreateInfo image_create = {
546        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
547        .pNext = &image_native_buffer,
548        .imageType = VK_IMAGE_TYPE_2D,
549        .format = create_info->imageFormat,
550        .extent = {0, 0, 1},
551        .mipLevels = 1,
552        .arrayLayers = 1,
553        .samples = VK_SAMPLE_COUNT_1_BIT,
554        .tiling = VK_IMAGE_TILING_OPTIMAL,
555        .usage = create_info->imageUsage,
556        .flags = 0,
557        .sharingMode = create_info->imageSharingMode,
558        .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
559        .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
560    };
561
562    for (uint32_t i = 0; i < num_images; i++) {
563        Swapchain::Image& img = swapchain->images[i];
564
565        ANativeWindowBuffer* buffer;
566        err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
567                                            &img.dequeue_fence);
568        if (err != 0) {
569            // TODO(jessehall): Improve error reporting. Can we enumerate
570            // possible errors and translate them to valid Vulkan result codes?
571            ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
572            result = VK_ERROR_INITIALIZATION_FAILED;
573            break;
574        }
575        img.buffer = buffer;
576        img.dequeued = true;
577
578        image_create.extent =
579            VkExtent3D{static_cast<uint32_t>(img.buffer->width),
580                       static_cast<uint32_t>(img.buffer->height),
581                       1};
582        image_native_buffer.handle = img.buffer->handle;
583        image_native_buffer.stride = img.buffer->stride;
584        image_native_buffer.format = img.buffer->format;
585        image_native_buffer.usage = img.buffer->usage;
586
587        result =
588            dispatch.CreateImage(device, &image_create, nullptr, &img.image);
589        if (result != VK_SUCCESS) {
590            ALOGD("vkCreateImage w/ native buffer failed: %u", result);
591            break;
592        }
593    }
594
595    // -- Cancel all buffers, returning them to the queue --
596    // If an error occurred before, also destroy the VkImage and release the
597    // buffer reference. Otherwise, we retain a strong reference to the buffer.
598    //
599    // TODO(jessehall): The error path here is the same as DestroySwapchain,
600    // but not the non-error path. Should refactor/unify.
601    for (uint32_t i = 0; i < num_images; i++) {
602        Swapchain::Image& img = swapchain->images[i];
603        if (img.dequeued) {
604            surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
605                                         img.dequeue_fence);
606            img.dequeue_fence = -1;
607            img.dequeued = false;
608        }
609        if (result != VK_SUCCESS) {
610            if (img.image)
611                dispatch.DestroyImage(device, img.image, nullptr);
612        }
613    }
614
615    if (result != VK_SUCCESS) {
616        swapchain->~Swapchain();
617        allocator->pfnFree(allocator->pUserData, swapchain);
618        return result;
619    }
620
621    *swapchain_handle = HandleFromSwapchain(swapchain);
622    return VK_SUCCESS;
623}
624
625VKAPI_ATTR
626void DestroySwapchainKHR(VkDevice device,
627                         VkSwapchainKHR swapchain_handle,
628                         const VkAllocationCallbacks* allocator) {
629    const auto& dispatch = GetData(device).driver;
630    Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
631    const android::sp<ANativeWindow>& window = swapchain->surface.window;
632
633    for (uint32_t i = 0; i < swapchain->num_images; i++) {
634        Swapchain::Image& img = swapchain->images[i];
635        if (img.dequeued) {
636            window->cancelBuffer(window.get(), img.buffer.get(),
637                                 img.dequeue_fence);
638            img.dequeue_fence = -1;
639            img.dequeued = false;
640        }
641        if (img.image) {
642            dispatch.DestroyImage(device, img.image, nullptr);
643        }
644    }
645
646    if (!allocator)
647        allocator = &GetData(device).allocator;
648    swapchain->~Swapchain();
649    allocator->pfnFree(allocator->pUserData, swapchain);
650}
651
652VKAPI_ATTR
653VkResult GetSwapchainImagesKHR(VkDevice,
654                               VkSwapchainKHR swapchain_handle,
655                               uint32_t* count,
656                               VkImage* images) {
657    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
658    VkResult result = VK_SUCCESS;
659    if (images) {
660        uint32_t n = swapchain.num_images;
661        if (*count < swapchain.num_images) {
662            n = *count;
663            result = VK_INCOMPLETE;
664        }
665        for (uint32_t i = 0; i < n; i++)
666            images[i] = swapchain.images[i].image;
667    }
668    *count = swapchain.num_images;
669    return result;
670}
671
672VKAPI_ATTR
673VkResult AcquireNextImageKHR(VkDevice device,
674                             VkSwapchainKHR swapchain_handle,
675                             uint64_t timeout,
676                             VkSemaphore semaphore,
677                             VkFence vk_fence,
678                             uint32_t* image_index) {
679    Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
680    ANativeWindow* window = swapchain.surface.window.get();
681    VkResult result;
682    int err;
683
684    ALOGW_IF(
685        timeout != UINT64_MAX,
686        "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
687
688    ANativeWindowBuffer* buffer;
689    int fence_fd;
690    err = window->dequeueBuffer(window, &buffer, &fence_fd);
691    if (err != 0) {
692        // TODO(jessehall): Improve error reporting. Can we enumerate possible
693        // errors and translate them to valid Vulkan result codes?
694        ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
695        return VK_ERROR_INITIALIZATION_FAILED;
696    }
697
698    uint32_t idx;
699    for (idx = 0; idx < swapchain.num_images; idx++) {
700        if (swapchain.images[idx].buffer.get() == buffer) {
701            swapchain.images[idx].dequeued = true;
702            swapchain.images[idx].dequeue_fence = fence_fd;
703            break;
704        }
705    }
706    if (idx == swapchain.num_images) {
707        ALOGE("dequeueBuffer returned unrecognized buffer");
708        window->cancelBuffer(window, buffer, fence_fd);
709        return VK_ERROR_OUT_OF_DATE_KHR;
710    }
711
712    int fence_clone = -1;
713    if (fence_fd != -1) {
714        fence_clone = dup(fence_fd);
715        if (fence_clone == -1) {
716            ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
717                  strerror(errno), errno);
718            sync_wait(fence_fd, -1 /* forever */);
719        }
720    }
721
722    result = GetData(device).driver.AcquireImageANDROID(
723        device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
724    if (result != VK_SUCCESS) {
725        // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
726        // even if the call fails. We could close it ourselves on failure, but
727        // that would create a race condition if the driver closes it on a
728        // failure path: some other thread might create an fd with the same
729        // number between the time the driver closes it and the time we close
730        // it. We must assume one of: the driver *always* closes it even on
731        // failure, or *never* closes it on failure.
732        window->cancelBuffer(window, buffer, fence_fd);
733        swapchain.images[idx].dequeued = false;
734        swapchain.images[idx].dequeue_fence = -1;
735        return result;
736    }
737
738    *image_index = idx;
739    return VK_SUCCESS;
740}
741
742VKAPI_ATTR
743VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
744    ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
745             "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
746             present_info->sType);
747    ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
748
749    const auto& dispatch = GetData(queue).driver;
750    VkResult final_result = VK_SUCCESS;
751    for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
752        Swapchain& swapchain =
753            *SwapchainFromHandle(present_info->pSwapchains[sc]);
754        ANativeWindow* window = swapchain.surface.window.get();
755        uint32_t image_idx = present_info->pImageIndices[sc];
756        Swapchain::Image& img = swapchain.images[image_idx];
757        VkResult result;
758        int err;
759
760        int fence = -1;
761        result = dispatch.QueueSignalReleaseImageANDROID(
762            queue, present_info->waitSemaphoreCount,
763            present_info->pWaitSemaphores, img.image, &fence);
764        if (result != VK_SUCCESS) {
765            ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
766            if (present_info->pResults)
767                present_info->pResults[sc] = result;
768            if (final_result == VK_SUCCESS)
769                final_result = result;
770            // TODO(jessehall): What happens to the buffer here? Does the app
771            // still own it or not, i.e. should we cancel the buffer? Hard to
772            // do correctly without synchronizing, though I guess we could wait
773            // for the queue to idle.
774            continue;
775        }
776
777        err = window->queueBuffer(window, img.buffer.get(), fence);
778        if (err != 0) {
779            // TODO(jessehall): What now? We should probably cancel the buffer,
780            // I guess?
781            ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
782            if (present_info->pResults)
783                present_info->pResults[sc] = result;
784            if (final_result == VK_SUCCESS)
785                final_result = VK_ERROR_INITIALIZATION_FAILED;
786            continue;
787        }
788
789        if (img.dequeue_fence != -1) {
790            close(img.dequeue_fence);
791            img.dequeue_fence = -1;
792        }
793        img.dequeued = false;
794
795        if (present_info->pResults)
796            present_info->pResults[sc] = VK_SUCCESS;
797    }
798
799    return final_result;
800}
801
802}  // namespace driver
803}  // namespace vulkan
804