[go: nahoru, domu]

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