OSDN Git Service

Merge "ui: Fix bad size check in Fence::unflatten" into klp-dev am: 25556811f0 am...
[android-x86/frameworks-native.git] / vulkan / libvulkan / swapchain.cpp
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.
30 namespace vulkan {
31 namespace driver {
32
33 namespace {
34
35 const 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
47 VkSurfaceTransformFlagBitsKHR 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
82 int 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
110 struct Surface {
111     android::sp<ANativeWindow> window;
112     VkSwapchainKHR swapchain_handle;
113 };
114
115 VkSurfaceKHR HandleFromSurface(Surface* surface) {
116     return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface));
117 }
118
119 Surface* SurfaceFromHandle(VkSurfaceKHR handle) {
120     return reinterpret_cast<Surface*>(handle);
121 }
122
123 struct 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
143 VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
144     return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
145 }
146
147 Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
148     return reinterpret_cast<Swapchain*>(handle);
149 }
150
151 void 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
200 void 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
212 VKAPI_ATTR
213 VkResult 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
247 VKAPI_ATTR
248 void 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
266 VKAPI_ATTR
267 VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
268                                             uint32_t /*queue_family*/,
269                                             VkSurfaceKHR /*surface*/,
270                                             VkBool32* supported) {
271     *supported = VK_TRUE;
272     return VK_SUCCESS;
273 }
274
275 VKAPI_ATTR
276 VkResult 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
342 VKAPI_ATTR
343 VkResult 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
370 VKAPI_ATTR
371 VkResult 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
390 VKAPI_ATTR
391 VkResult 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
716 VKAPI_ATTR
717 void 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
735 VKAPI_ATTR
736 VkResult 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
759 VKAPI_ATTR
760 VkResult 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
832 static 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
852 VKAPI_ATTR
853 VkResult 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