OSDN Git Service

Merge "libgui: Check slot received from IGBP in Surface" into lmp-dev am: 98e3c06010...
[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 <log/log.h>
20 #include <gui/BufferQueue.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         *count = std::min(*count, kNumFormats);
365         std::copy(kFormats, kFormats + *count, formats);
366     } else {
367         *count = kNumFormats;
368     }
369     return result;
370 }
371
372 VKAPI_ATTR
373 VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/,
374                                                  VkSurfaceKHR /*surface*/,
375                                                  uint32_t* count,
376                                                  VkPresentModeKHR* modes) {
377     const VkPresentModeKHR kModes[] = {
378         VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
379     };
380     const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
381
382     VkResult result = VK_SUCCESS;
383     if (modes) {
384         if (*count < kNumModes)
385             result = VK_INCOMPLETE;
386         *count = std::min(*count, kNumModes);
387         std::copy(kModes, kModes + *count, modes);
388     } else {
389         *count = kNumModes;
390     }
391     return result;
392 }
393
394 VKAPI_ATTR
395 VkResult CreateSwapchainKHR(VkDevice device,
396                             const VkSwapchainCreateInfoKHR* create_info,
397                             const VkAllocationCallbacks* allocator,
398                             VkSwapchainKHR* swapchain_handle) {
399     int err;
400     VkResult result = VK_SUCCESS;
401
402     ALOGV("vkCreateSwapchainKHR: surface=0x%" PRIx64
403           " minImageCount=%u imageFormat=%u imageColorSpace=%u"
404           " imageExtent=%ux%u imageUsage=%#x preTransform=%u presentMode=%u"
405           " oldSwapchain=0x%" PRIx64,
406           reinterpret_cast<uint64_t>(create_info->surface),
407           create_info->minImageCount, create_info->imageFormat,
408           create_info->imageColorSpace, create_info->imageExtent.width,
409           create_info->imageExtent.height, create_info->imageUsage,
410           create_info->preTransform, create_info->presentMode,
411           reinterpret_cast<uint64_t>(create_info->oldSwapchain));
412
413     if (!allocator)
414         allocator = &GetData(device).allocator;
415
416     ALOGV_IF(create_info->imageArrayLayers != 1,
417              "swapchain imageArrayLayers=%u not supported",
418              create_info->imageArrayLayers);
419     ALOGV_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
420              "swapchain imageColorSpace=%u not supported",
421              create_info->imageColorSpace);
422     ALOGV_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
423              "swapchain preTransform=%#x not supported",
424              create_info->preTransform);
425     ALOGV_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
426                create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
427              "swapchain presentMode=%u not supported",
428              create_info->presentMode);
429
430     Surface& surface = *SurfaceFromHandle(create_info->surface);
431
432     if (surface.swapchain_handle != create_info->oldSwapchain) {
433         ALOGV("Can't create a swapchain for VkSurfaceKHR 0x%" PRIx64
434               " because it already has active swapchain 0x%" PRIx64
435               " but VkSwapchainCreateInfo::oldSwapchain=0x%" PRIx64,
436               reinterpret_cast<uint64_t>(create_info->surface),
437               reinterpret_cast<uint64_t>(surface.swapchain_handle),
438               reinterpret_cast<uint64_t>(create_info->oldSwapchain));
439         return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
440     }
441     if (create_info->oldSwapchain != VK_NULL_HANDLE)
442         OrphanSwapchain(device, SwapchainFromHandle(create_info->oldSwapchain));
443
444     // -- Reset the native window --
445     // The native window might have been used previously, and had its properties
446     // changed from defaults. That will affect the answer we get for queries
447     // like MIN_UNDEQUED_BUFFERS. Reset to a known/default state before we
448     // attempt such queries.
449
450     // The native window only allows dequeueing all buffers before any have
451     // been queued, since after that point at least one is assumed to be in
452     // non-FREE state at any given time. Disconnecting and re-connecting
453     // orphans the previous buffers, getting us back to the state where we can
454     // dequeue all buffers.
455     err = native_window_api_disconnect(surface.window.get(),
456                                        NATIVE_WINDOW_API_EGL);
457     ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)",
458              strerror(-err), err);
459     err =
460         native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL);
461     ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)",
462              strerror(-err), err);
463
464     err = native_window_set_buffer_count(surface.window.get(), 0);
465     if (err != 0) {
466         ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
467               strerror(-err), err);
468         return VK_ERROR_INITIALIZATION_FAILED;
469     }
470
471     err = surface.window->setSwapInterval(surface.window.get(), 1);
472     if (err != 0) {
473         // TODO(jessehall): Improve error reporting. Can we enumerate possible
474         // errors and translate them to valid Vulkan result codes?
475         ALOGE("native_window->setSwapInterval(1) failed: %s (%d)",
476               strerror(-err), err);
477         return VK_ERROR_INITIALIZATION_FAILED;
478     }
479
480     // -- Configure the native window --
481
482     const auto& dispatch = GetData(device).driver;
483
484     int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
485     switch (create_info->imageFormat) {
486         case VK_FORMAT_R8G8B8A8_UNORM:
487         case VK_FORMAT_R8G8B8A8_SRGB:
488             native_format = HAL_PIXEL_FORMAT_RGBA_8888;
489             break;
490         case VK_FORMAT_R5G6B5_UNORM_PACK16:
491             native_format = HAL_PIXEL_FORMAT_RGB_565;
492             break;
493         default:
494             ALOGV("unsupported swapchain format %d", create_info->imageFormat);
495             break;
496     }
497     err = native_window_set_buffers_format(surface.window.get(), native_format);
498     if (err != 0) {
499         // TODO(jessehall): Improve error reporting. Can we enumerate possible
500         // errors and translate them to valid Vulkan result codes?
501         ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
502               native_format, strerror(-err), err);
503         return VK_ERROR_INITIALIZATION_FAILED;
504     }
505     err = native_window_set_buffers_data_space(surface.window.get(),
506                                                HAL_DATASPACE_SRGB_LINEAR);
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_buffers_data_space(%d) failed: %s (%d)",
511               HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err);
512         return VK_ERROR_INITIALIZATION_FAILED;
513     }
514
515     err = native_window_set_buffers_dimensions(
516         surface.window.get(), static_cast<int>(create_info->imageExtent.width),
517         static_cast<int>(create_info->imageExtent.height));
518     if (err != 0) {
519         // TODO(jessehall): Improve error reporting. Can we enumerate possible
520         // errors and translate them to valid Vulkan result codes?
521         ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
522               create_info->imageExtent.width, create_info->imageExtent.height,
523               strerror(-err), err);
524         return VK_ERROR_INITIALIZATION_FAILED;
525     }
526
527     // VkSwapchainCreateInfo::preTransform indicates the transformation the app
528     // applied during rendering. native_window_set_transform() expects the
529     // inverse: the transform the app is requesting that the compositor perform
530     // during composition. With native windows, pre-transform works by rendering
531     // with the same transform the compositor is applying (as in Vulkan), but
532     // then requesting the inverse transform, so that when the compositor does
533     // it's job the two transforms cancel each other out and the compositor ends
534     // up applying an identity transform to the app's buffer.
535     err = native_window_set_buffers_transform(
536         surface.window.get(),
537         InvertTransformToNative(create_info->preTransform));
538     if (err != 0) {
539         // TODO(jessehall): Improve error reporting. Can we enumerate possible
540         // errors and translate them to valid Vulkan result codes?
541         ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
542               InvertTransformToNative(create_info->preTransform),
543               strerror(-err), err);
544         return VK_ERROR_INITIALIZATION_FAILED;
545     }
546
547     err = native_window_set_scaling_mode(
548         surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
549     if (err != 0) {
550         // TODO(jessehall): Improve error reporting. Can we enumerate possible
551         // errors and translate them to valid Vulkan result codes?
552         ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
553               strerror(-err), err);
554         return VK_ERROR_INITIALIZATION_FAILED;
555     }
556
557     int query_value;
558     err = surface.window->query(surface.window.get(),
559                                 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
560                                 &query_value);
561     if (err != 0 || query_value < 0) {
562         // TODO(jessehall): Improve error reporting. Can we enumerate possible
563         // errors and translate them to valid Vulkan result codes?
564         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
565               query_value);
566         return VK_ERROR_INITIALIZATION_FAILED;
567     }
568     uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
569     // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
570     // async mode or not, and assumes not. But in async mode, the BufferQueue
571     // requires an extra undequeued buffer.
572     // See BufferQueueCore::getMinUndequeuedBufferCountLocked().
573     if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
574         min_undequeued_buffers += 1;
575
576     uint32_t num_images =
577         (create_info->minImageCount - 1) + min_undequeued_buffers;
578     err = native_window_set_buffer_count(surface.window.get(), num_images);
579     if (err != 0) {
580         // TODO(jessehall): Improve error reporting. Can we enumerate possible
581         // errors and translate them to valid Vulkan result codes?
582         ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
583               strerror(-err), err);
584         return VK_ERROR_INITIALIZATION_FAILED;
585     }
586
587     int gralloc_usage = 0;
588     // TODO(jessehall): Remove conditional once all drivers have been updated
589     if (dispatch.GetSwapchainGrallocUsageANDROID) {
590         result = dispatch.GetSwapchainGrallocUsageANDROID(
591             device, create_info->imageFormat, create_info->imageUsage,
592             &gralloc_usage);
593         if (result != VK_SUCCESS) {
594             ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
595             return VK_ERROR_INITIALIZATION_FAILED;
596         }
597     } else {
598         gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
599     }
600     err = native_window_set_usage(surface.window.get(), gralloc_usage);
601     if (err != 0) {
602         // TODO(jessehall): Improve error reporting. Can we enumerate possible
603         // errors and translate them to valid Vulkan result codes?
604         ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
605         return VK_ERROR_INITIALIZATION_FAILED;
606     }
607
608     int swap_interval =
609         create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
610     err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
611     if (err != 0) {
612         // TODO(jessehall): Improve error reporting. Can we enumerate possible
613         // errors and translate them to valid Vulkan result codes?
614         ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)",
615               swap_interval, strerror(-err), err);
616         return VK_ERROR_INITIALIZATION_FAILED;
617     }
618
619     // -- Allocate our Swapchain object --
620     // After this point, we must deallocate the swapchain on error.
621
622     void* mem = allocator->pfnAllocation(allocator->pUserData,
623                                          sizeof(Swapchain), alignof(Swapchain),
624                                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
625     if (!mem)
626         return VK_ERROR_OUT_OF_HOST_MEMORY;
627     Swapchain* swapchain = new (mem) Swapchain(surface, num_images);
628
629     // -- Dequeue all buffers and create a VkImage for each --
630     // Any failures during or after this must cancel the dequeued buffers.
631
632     VkNativeBufferANDROID image_native_buffer = {
633 #pragma clang diagnostic push
634 #pragma clang diagnostic ignored "-Wold-style-cast"
635         .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
636 #pragma clang diagnostic pop
637         .pNext = nullptr,
638     };
639     VkImageCreateInfo image_create = {
640         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
641         .pNext = &image_native_buffer,
642         .imageType = VK_IMAGE_TYPE_2D,
643         .format = create_info->imageFormat,
644         .extent = {0, 0, 1},
645         .mipLevels = 1,
646         .arrayLayers = 1,
647         .samples = VK_SAMPLE_COUNT_1_BIT,
648         .tiling = VK_IMAGE_TILING_OPTIMAL,
649         .usage = create_info->imageUsage,
650         .flags = 0,
651         .sharingMode = create_info->imageSharingMode,
652         .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
653         .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
654     };
655
656     for (uint32_t i = 0; i < num_images; i++) {
657         Swapchain::Image& img = swapchain->images[i];
658
659         ANativeWindowBuffer* buffer;
660         err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
661                                             &img.dequeue_fence);
662         if (err != 0) {
663             // TODO(jessehall): Improve error reporting. Can we enumerate
664             // possible errors and translate them to valid Vulkan result codes?
665             ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
666             result = VK_ERROR_INITIALIZATION_FAILED;
667             break;
668         }
669         img.buffer = buffer;
670         img.dequeued = true;
671
672         image_create.extent =
673             VkExtent3D{static_cast<uint32_t>(img.buffer->width),
674                        static_cast<uint32_t>(img.buffer->height),
675                        1};
676         image_native_buffer.handle = img.buffer->handle;
677         image_native_buffer.stride = img.buffer->stride;
678         image_native_buffer.format = img.buffer->format;
679         image_native_buffer.usage = img.buffer->usage;
680
681         result =
682             dispatch.CreateImage(device, &image_create, nullptr, &img.image);
683         if (result != VK_SUCCESS) {
684             ALOGD("vkCreateImage w/ native buffer failed: %u", result);
685             break;
686         }
687     }
688
689     // -- Cancel all buffers, returning them to the queue --
690     // If an error occurred before, also destroy the VkImage and release the
691     // buffer reference. Otherwise, we retain a strong reference to the buffer.
692     //
693     // TODO(jessehall): The error path here is the same as DestroySwapchain,
694     // but not the non-error path. Should refactor/unify.
695     for (uint32_t i = 0; i < num_images; i++) {
696         Swapchain::Image& img = swapchain->images[i];
697         if (img.dequeued) {
698             surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
699                                          img.dequeue_fence);
700             img.dequeue_fence = -1;
701             img.dequeued = false;
702         }
703         if (result != VK_SUCCESS) {
704             if (img.image)
705                 dispatch.DestroyImage(device, img.image, nullptr);
706         }
707     }
708
709     if (result != VK_SUCCESS) {
710         swapchain->~Swapchain();
711         allocator->pfnFree(allocator->pUserData, swapchain);
712         return result;
713     }
714
715     surface.swapchain_handle = HandleFromSwapchain(swapchain);
716     *swapchain_handle = surface.swapchain_handle;
717     return VK_SUCCESS;
718 }
719
720 VKAPI_ATTR
721 void DestroySwapchainKHR(VkDevice device,
722                          VkSwapchainKHR swapchain_handle,
723                          const VkAllocationCallbacks* allocator) {
724     const auto& dispatch = GetData(device).driver;
725     Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
726     if (!swapchain)
727         return;
728     bool active = swapchain->surface.swapchain_handle == swapchain_handle;
729     ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr;
730
731     for (uint32_t i = 0; i < swapchain->num_images; i++)
732         ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
733     if (active)
734         swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
735     if (!allocator)
736         allocator = &GetData(device).allocator;
737     swapchain->~Swapchain();
738     allocator->pfnFree(allocator->pUserData, swapchain);
739 }
740
741 VKAPI_ATTR
742 VkResult GetSwapchainImagesKHR(VkDevice,
743                                VkSwapchainKHR swapchain_handle,
744                                uint32_t* count,
745                                VkImage* images) {
746     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
747     ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle,
748              "getting images for non-active swapchain 0x%" PRIx64
749              "; only dequeued image handles are valid",
750              reinterpret_cast<uint64_t>(swapchain_handle));
751     VkResult result = VK_SUCCESS;
752     if (images) {
753         uint32_t n = swapchain.num_images;
754         if (*count < swapchain.num_images) {
755             n = *count;
756             result = VK_INCOMPLETE;
757         }
758         for (uint32_t i = 0; i < n; i++)
759             images[i] = swapchain.images[i].image;
760         *count = n;
761     } else {
762         *count = swapchain.num_images;
763     }
764     return result;
765 }
766
767 VKAPI_ATTR
768 VkResult AcquireNextImageKHR(VkDevice device,
769                              VkSwapchainKHR swapchain_handle,
770                              uint64_t timeout,
771                              VkSemaphore semaphore,
772                              VkFence vk_fence,
773                              uint32_t* image_index) {
774     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
775     ANativeWindow* window = swapchain.surface.window.get();
776     VkResult result;
777     int err;
778
779     if (swapchain.surface.swapchain_handle != swapchain_handle)
780         return VK_ERROR_OUT_OF_DATE_KHR;
781
782     ALOGW_IF(
783         timeout != UINT64_MAX,
784         "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
785
786     ANativeWindowBuffer* buffer;
787     int fence_fd;
788     err = window->dequeueBuffer(window, &buffer, &fence_fd);
789     if (err != 0) {
790         // TODO(jessehall): Improve error reporting. Can we enumerate possible
791         // errors and translate them to valid Vulkan result codes?
792         ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
793         return VK_ERROR_INITIALIZATION_FAILED;
794     }
795
796     uint32_t idx;
797     for (idx = 0; idx < swapchain.num_images; idx++) {
798         if (swapchain.images[idx].buffer.get() == buffer) {
799             swapchain.images[idx].dequeued = true;
800             swapchain.images[idx].dequeue_fence = fence_fd;
801             break;
802         }
803     }
804     if (idx == swapchain.num_images) {
805         ALOGE("dequeueBuffer returned unrecognized buffer");
806         window->cancelBuffer(window, buffer, fence_fd);
807         return VK_ERROR_OUT_OF_DATE_KHR;
808     }
809
810     int fence_clone = -1;
811     if (fence_fd != -1) {
812         fence_clone = dup(fence_fd);
813         if (fence_clone == -1) {
814             ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
815                   strerror(errno), errno);
816             sync_wait(fence_fd, -1 /* forever */);
817         }
818     }
819
820     result = GetData(device).driver.AcquireImageANDROID(
821         device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
822     if (result != VK_SUCCESS) {
823         // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
824         // even if the call fails. We could close it ourselves on failure, but
825         // that would create a race condition if the driver closes it on a
826         // failure path: some other thread might create an fd with the same
827         // number between the time the driver closes it and the time we close
828         // it. We must assume one of: the driver *always* closes it even on
829         // failure, or *never* closes it on failure.
830         window->cancelBuffer(window, buffer, fence_fd);
831         swapchain.images[idx].dequeued = false;
832         swapchain.images[idx].dequeue_fence = -1;
833         return result;
834     }
835
836     *image_index = idx;
837     return VK_SUCCESS;
838 }
839
840 static VkResult WorstPresentResult(VkResult a, VkResult b) {
841     // See the error ranking for vkQueuePresentKHR at the end of section 29.6
842     // (in spec version 1.0.14).
843     static const VkResult kWorstToBest[] = {
844         VK_ERROR_DEVICE_LOST,
845         VK_ERROR_SURFACE_LOST_KHR,
846         VK_ERROR_OUT_OF_DATE_KHR,
847         VK_ERROR_OUT_OF_DEVICE_MEMORY,
848         VK_ERROR_OUT_OF_HOST_MEMORY,
849         VK_SUBOPTIMAL_KHR,
850     };
851     for (auto result : kWorstToBest) {
852         if (a == result || b == result)
853             return result;
854     }
855     ALOG_ASSERT(a == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", a);
856     ALOG_ASSERT(b == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", b);
857     return a != VK_SUCCESS ? a : b;
858 }
859
860 VKAPI_ATTR
861 VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
862     ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
863              "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
864              present_info->sType);
865     ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
866
867     VkDevice device = GetData(queue).driver_device;
868     const auto& dispatch = GetData(queue).driver;
869     VkResult final_result = VK_SUCCESS;
870
871     for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
872         Swapchain& swapchain =
873             *SwapchainFromHandle(present_info->pSwapchains[sc]);
874         uint32_t image_idx = present_info->pImageIndices[sc];
875         Swapchain::Image& img = swapchain.images[image_idx];
876         VkResult swapchain_result = VK_SUCCESS;
877         VkResult result;
878         int err;
879
880         int fence = -1;
881         result = dispatch.QueueSignalReleaseImageANDROID(
882             queue, present_info->waitSemaphoreCount,
883             present_info->pWaitSemaphores, img.image, &fence);
884         if (result != VK_SUCCESS) {
885             ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
886             swapchain_result = result;
887         }
888
889         if (swapchain.surface.swapchain_handle ==
890             present_info->pSwapchains[sc]) {
891             ANativeWindow* window = swapchain.surface.window.get();
892             if (swapchain_result == VK_SUCCESS) {
893                 err = window->queueBuffer(window, img.buffer.get(), fence);
894                 // queueBuffer always closes fence, even on error
895                 if (err != 0) {
896                     // TODO(jessehall): What now? We should probably cancel the
897                     // buffer, I guess?
898                     ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
899                     swapchain_result = WorstPresentResult(
900                         swapchain_result, VK_ERROR_OUT_OF_DATE_KHR);
901                 }
902                 if (img.dequeue_fence >= 0) {
903                     close(img.dequeue_fence);
904                     img.dequeue_fence = -1;
905                 }
906                 img.dequeued = false;
907             }
908             if (swapchain_result != VK_SUCCESS) {
909                 ReleaseSwapchainImage(device, window, fence, img);
910                 OrphanSwapchain(device, &swapchain);
911             }
912         } else {
913             ReleaseSwapchainImage(device, nullptr, fence, img);
914             swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
915         }
916
917         if (present_info->pResults)
918             present_info->pResults[sc] = swapchain_result;
919
920         if (swapchain_result != final_result)
921             final_result = WorstPresentResult(final_result, swapchain_result);
922     }
923
924     return final_result;
925 }
926
927 }  // namespace driver
928 }  // namespace vulkan