blob: 02d951530d4e8efdb5714f6d5b8c21e3f8368814 [file] [log] [blame]
Jesse Hallb1352bc2015-09-04 16:12:33 -07001/*
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
Jesse Halld7b994a2015-09-07 14:17:37 -070017// #define LOG_NDEBUG 0
18
19#include <algorithm>
20#include <memory>
21
22#include <gui/BufferQueue.h>
Jesse Hallb1352bc2015-09-04 16:12:33 -070023#include <log/log.h>
Jesse Halld7b994a2015-09-07 14:17:37 -070024#include <sync/sync.h>
25
26#include "loader.h"
27
28using namespace vulkan;
29
Jesse Hall5ae3abb2015-10-08 14:00:22 -070030// TODO(jessehall): Currently we don't have a good error code for when a native
31// window operation fails. Just returning INITIALIZATION_FAILED for now. Later
32// versions (post SDK 0.9) of the API/extension have a better error code.
33// When updating to that version, audit all error returns.
34
Jesse Halld7b994a2015-09-07 14:17:37 -070035namespace {
36
37// ----------------------------------------------------------------------------
38// These functions/classes form an adaptor that allows objects to be refcounted
39// by both android::sp<> and std::shared_ptr<> simultaneously, and delegates
40// allocation of the shared_ptr<> control structure to VkAllocCallbacks. The
41// platform holds a reference to the ANativeWindow using its embedded reference
42// count, and the ANativeWindow implementation holds references to the
43// ANativeWindowBuffers using their embedded reference counts, so the
44// shared_ptr *must* cooperate with these and hold at least one reference to
45// the object using the embedded reference count.
46
47template <typename T>
48struct NativeBaseDeleter {
49 void operator()(T* obj) { obj->common.decRef(&obj->common); }
50};
51
52template <typename T>
53class VulkanAllocator {
54 public:
55 typedef T value_type;
56
57 explicit VulkanAllocator(VkDevice device) : device_(device) {}
58
59 template <typename U>
60 explicit VulkanAllocator(const VulkanAllocator<U>& other)
61 : device_(other.device_) {}
62
63 T* allocate(size_t n) const {
64 return static_cast<T*>(AllocDeviceMem(
65 device_, n * sizeof(T), alignof(T), VK_SYSTEM_ALLOC_TYPE_INTERNAL));
66 }
67 void deallocate(T* p, size_t) const { return FreeDeviceMem(device_, p); }
68
69 private:
70 template <typename U>
71 friend class VulkanAllocator;
72 VkDevice device_;
73};
74
75template <typename T>
76std::shared_ptr<T> InitSharedPtr(VkDevice device, T* obj) {
77 obj->common.incRef(&obj->common);
78 return std::shared_ptr<T>(obj, NativeBaseDeleter<T>(),
79 VulkanAllocator<T>(device));
80}
81
82// ----------------------------------------------------------------------------
83
84struct Swapchain {
85 Swapchain(std::shared_ptr<ANativeWindow> window_, uint32_t num_images_)
86 : window(window_), num_images(num_images_) {}
87
88 std::shared_ptr<ANativeWindow> window;
89 uint32_t num_images;
90
91 struct Image {
92 Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
93 VkImage image;
94 std::shared_ptr<ANativeWindowBuffer> buffer;
95 // The fence is only valid when the buffer is dequeued, and should be
96 // -1 any other time. When valid, we own the fd, and must ensure it is
97 // closed: either by closing it explicitly when queueing the buffer,
98 // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
99 int dequeue_fence;
100 bool dequeued;
101 } images[android::BufferQueue::NUM_BUFFER_SLOTS];
102};
103
104VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
105 return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
106}
107
108Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) {
109 return reinterpret_cast<Swapchain*>(handle.handle);
110}
111
112} // anonymous namespace
Jesse Hallb1352bc2015-09-04 16:12:33 -0700113
114namespace vulkan {
115
116VkResult GetPhysicalDeviceSurfaceSupportKHR(
117 VkPhysicalDevice /*pdev*/,
118 uint32_t /*queue_family*/,
119 const VkSurfaceDescriptionKHR* surface_desc,
120 VkBool32* supported) {
121// TODO(jessehall): Fix the header, preferrably upstream, so values added to
122// existing enums don't trigger warnings like this.
123#pragma clang diagnostic push
124#pragma clang diagnostic ignored "-Wold-style-cast"
125#pragma clang diagnostic ignored "-Wsign-conversion"
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700126 ALOGE_IF(
127 surface_desc->sType != VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR,
128 "vkGetPhysicalDeviceSurfaceSupportKHR: pSurfaceDescription->sType=%#x "
129 "not supported",
130 surface_desc->sType);
Jesse Hallb1352bc2015-09-04 16:12:33 -0700131#pragma clang diagnostic pop
132
133 const VkSurfaceDescriptionWindowKHR* window_desc =
134 reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(surface_desc);
135
136 // TODO(jessehall): Also check whether the physical device exports the
137 // VK_EXT_ANDROID_native_buffer extension. For now, assume it does.
138 *supported = (window_desc->platform == VK_PLATFORM_ANDROID_KHR &&
139 !window_desc->pPlatformHandle &&
140 static_cast<ANativeWindow*>(window_desc->pPlatformWindow)
141 ->common.magic == ANDROID_NATIVE_WINDOW_MAGIC);
142
143 return VK_SUCCESS;
144}
145
Jesse Halld7b994a2015-09-07 14:17:37 -0700146VkResult GetSurfacePropertiesKHR(VkDevice /*device*/,
Jesse Hallb1352bc2015-09-04 16:12:33 -0700147 const VkSurfaceDescriptionKHR* surface_desc,
148 VkSurfacePropertiesKHR* properties) {
Jesse Halld7b994a2015-09-07 14:17:37 -0700149 const VkSurfaceDescriptionWindowKHR* window_desc =
150 reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(surface_desc);
151 ANativeWindow* window =
152 static_cast<ANativeWindow*>(window_desc->pPlatformWindow);
153
154 int err;
155
156 // TODO(jessehall): Currently the window must be connected for several
157 // queries -- including default dimensions -- to work, since Surface caches
158 // the queried values at connect() and queueBuffer(), and query() returns
159 // those cached values.
160 //
161 // The proposed refactoring to create a VkSurface object (bug 14596) will
162 // give us a place to connect once per window. If that doesn't end up
163 // happening, we'll probably need to maintain an internal list of windows
164 // that have swapchains created for them, search that list here, and
165 // only temporarily connect if the window doesn't have a swapchain.
166
167 bool disconnect = true;
168 err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
169 if (err == -EINVAL) {
170 // This is returned if the window is already connected, among other
171 // things. We'll just assume we're already connected and charge ahead.
172 // See TODO above, this is not cool.
173 ALOGW(
174 "vkGetSurfacePropertiesKHR: native_window_api_connect returned "
175 "-EINVAL, assuming already connected");
176 err = 0;
177 disconnect = false;
178 } else if (err != 0) {
179 // TODO(jessehall): Improve error reporting. Can we enumerate possible
180 // errors and translate them to valid Vulkan result codes?
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700181 return VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700182 }
183
184 int width, height;
185 err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
186 if (err != 0) {
187 ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
188 strerror(-err), err);
189 if (disconnect)
190 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700191 return VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700192 }
193 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
194 if (err != 0) {
195 ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
196 strerror(-err), err);
197 if (disconnect)
198 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700199 return VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700200 }
201
202 if (disconnect)
203 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
204
205 properties->currentExtent = VkExtent2D{width, height};
206
207 // TODO(jessehall): Figure out what the min/max values should be.
208 properties->minImageCount = 2;
209 properties->maxImageCount = 3;
210
211 // TODO(jessehall): Figure out what the max extent should be. Maximum
212 // texture dimension maybe?
213 properties->minImageExtent = VkExtent2D{1, 1};
214 properties->maxImageExtent = VkExtent2D{4096, 4096};
215
216 // TODO(jessehall): We can support all transforms, fix this once
217 // implemented.
218 properties->supportedTransforms = VK_SURFACE_TRANSFORM_NONE_BIT_KHR;
219
220 // TODO(jessehall): Implement based on NATIVE_WINDOW_TRANSFORM_HINT.
221 properties->currentTransform = VK_SURFACE_TRANSFORM_NONE_KHR;
222
223 properties->maxImageArraySize = 1;
224
225 // TODO(jessehall): I think these are right, but haven't thought hard about
226 // it. Do we need to query the driver for support of any of these?
227 // Currently not included:
228 // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
229 // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
230 // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
231 properties->supportedUsageFlags =
232 VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT |
233 VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
234 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
235 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
236
Jesse Hallb1352bc2015-09-04 16:12:33 -0700237 return VK_SUCCESS;
238}
239
Jesse Halld7b994a2015-09-07 14:17:37 -0700240VkResult GetSurfaceFormatsKHR(VkDevice /*device*/,
241 const VkSurfaceDescriptionKHR* /*surface_desc*/,
Jesse Hallb1352bc2015-09-04 16:12:33 -0700242 uint32_t* count,
243 VkSurfaceFormatKHR* formats) {
Jesse Halld7b994a2015-09-07 14:17:37 -0700244 // TODO(jessehall): Fill out the set of supported formats. Open question
245 // whether we should query the driver for support -- how does it know what
246 // the consumer can support? Should we support formats that don't
247 // correspond to gralloc formats?
248
249 const VkSurfaceFormatKHR kFormats[] = {
250 {VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
251 {VK_FORMAT_R8G8B8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
252 };
253 const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
254
255 VkResult result = VK_SUCCESS;
256 if (formats) {
257 if (*count < kNumFormats)
258 result = VK_INCOMPLETE;
259 std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
260 }
261 *count = kNumFormats;
262 return result;
Jesse Hallb1352bc2015-09-04 16:12:33 -0700263}
264
Jesse Halld7b994a2015-09-07 14:17:37 -0700265VkResult GetSurfacePresentModesKHR(
266 VkDevice /*device*/,
267 const VkSurfaceDescriptionKHR* /*surface_desc*/,
268 uint32_t* count,
269 VkPresentModeKHR* modes) {
270 const VkPresentModeKHR kModes[] = {
271 VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
272 };
273 const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
274
275 VkResult result = VK_SUCCESS;
276 if (modes) {
277 if (*count < kNumModes)
278 result = VK_INCOMPLETE;
279 std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
280 }
281 *count = kNumModes;
282 return result;
Jesse Hallb1352bc2015-09-04 16:12:33 -0700283}
284
285VkResult CreateSwapchainKHR(VkDevice device,
286 const VkSwapchainCreateInfoKHR* create_info,
Jesse Halld7b994a2015-09-07 14:17:37 -0700287 VkSwapchainKHR* swapchain_handle) {
288 int err;
289 VkResult result = VK_SUCCESS;
290
291 ALOGV_IF(create_info->imageArraySize != 1,
292 "Swapchain imageArraySize (%u) != 1 not supported",
293 create_info->imageArraySize);
294
295 ALOGE_IF(create_info->imageFormat != VK_FORMAT_R8G8B8A8_UNORM,
296 "swapchain formats other than R8G8B8A8_UNORM not yet implemented");
297 ALOGE_IF(create_info->imageColorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR,
298 "color spaces other than SRGB_NONLINEAR not yet implemented");
299 ALOGE_IF(create_info->oldSwapchain,
300 "swapchain re-creation not yet implemented");
301 ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_NONE_KHR,
302 "swapchain preTransform not yet implemented");
303 ALOGE_IF(create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR,
304 "present modes other than FIFO are not yet implemented");
305
306 // -- Configure the native window --
307 // Failure paths from here on need to disconnect the window.
308
Jesse Hall70f93352015-11-04 09:41:31 -0800309 const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
310
Jesse Halld7b994a2015-09-07 14:17:37 -0700311 std::shared_ptr<ANativeWindow> window = InitSharedPtr(
312 device, static_cast<ANativeWindow*>(
313 reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>(
Jesse Hall606a54e2015-11-19 22:17:28 -0800314 create_info->pSurfaceDescription)->pPlatformWindow));
Jesse Halld7b994a2015-09-07 14:17:37 -0700315
316 // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
317 err = native_window_api_connect(window.get(), NATIVE_WINDOW_API_EGL);
318 if (err != 0) {
319 // TODO(jessehall): Improve error reporting. Can we enumerate possible
320 // errors and translate them to valid Vulkan result codes?
321 ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
322 err);
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700323 return VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700324 }
325
326 err = native_window_set_buffers_dimensions(window.get(),
327 create_info->imageExtent.width,
328 create_info->imageExtent.height);
329 if (err != 0) {
330 // TODO(jessehall): Improve error reporting. Can we enumerate possible
331 // errors and translate them to valid Vulkan result codes?
332 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
333 create_info->imageExtent.width, create_info->imageExtent.height,
334 strerror(-err), err);
335 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700336 return VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700337 }
338
Jesse Hallf64ca122015-11-03 16:11:10 -0800339 err = native_window_set_scaling_mode(
340 window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
341 if (err != 0) {
342 // TODO(jessehall): Improve error reporting. Can we enumerate possible
343 // errors and translate them to valid Vulkan result codes?
344 ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
345 strerror(-err), err);
346 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
347 return VK_ERROR_INITIALIZATION_FAILED;
348 }
349
Jesse Halld7b994a2015-09-07 14:17:37 -0700350 uint32_t min_undequeued_buffers;
351 err = window->query(window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
352 reinterpret_cast<int*>(&min_undequeued_buffers));
353 if (err != 0) {
354 // TODO(jessehall): Improve error reporting. Can we enumerate possible
355 // errors and translate them to valid Vulkan result codes?
356 ALOGE("window->query failed: %s (%d)", strerror(-err), err);
357 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700358 return VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700359 }
360 uint32_t num_images =
361 (create_info->minImageCount - 1) + min_undequeued_buffers;
362 err = native_window_set_buffer_count(window.get(), num_images);
363 if (err != 0) {
364 // TODO(jessehall): Improve error reporting. Can we enumerate possible
365 // errors and translate them to valid Vulkan result codes?
366 ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
367 err);
368 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700369 return VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700370 }
371
Jesse Hall70f93352015-11-04 09:41:31 -0800372 int gralloc_usage = 0;
373 // TODO(jessehall): Remove conditional once all drivers have been updated
374 if (driver_vtbl.GetSwapchainGrallocUsageANDROID) {
375 result = driver_vtbl.GetSwapchainGrallocUsageANDROID(
376 device, create_info->imageFormat, create_info->imageUsageFlags,
377 &gralloc_usage);
378 if (result != VK_SUCCESS) {
379 ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
380 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
381 return VK_ERROR_INITIALIZATION_FAILED;
382 }
383 } else {
384 gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
385 }
386 err = native_window_set_usage(window.get(), gralloc_usage);
387 if (err != 0) {
388 // TODO(jessehall): Improve error reporting. Can we enumerate possible
389 // errors and translate them to valid Vulkan result codes?
390 ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
391 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
392 return VK_ERROR_INITIALIZATION_FAILED;
393 }
Jesse Halld7b994a2015-09-07 14:17:37 -0700394
395 // -- Allocate our Swapchain object --
396 // After this point, we must deallocate the swapchain on error.
397
398 void* mem = AllocDeviceMem(device, sizeof(Swapchain), alignof(Swapchain),
399 VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
400 if (!mem) {
401 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
402 return VK_ERROR_OUT_OF_HOST_MEMORY;
403 }
404 Swapchain* swapchain = new (mem) Swapchain(window, num_images);
405
406 // -- Dequeue all buffers and create a VkImage for each --
407 // Any failures during or after this must cancel the dequeued buffers.
408
409 VkNativeBufferANDROID image_native_buffer = {
410// TODO(jessehall): Figure out how to make extension headers not horrible.
411#pragma clang diagnostic push
412#pragma clang diagnostic ignored "-Wold-style-cast"
413 .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
414#pragma clang diagnostic pop
415 .pNext = nullptr,
416 };
417 VkImageCreateInfo image_create = {
418 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
419 .pNext = &image_native_buffer,
420 .imageType = VK_IMAGE_TYPE_2D,
421 .format = VK_FORMAT_R8G8B8A8_UNORM, // TODO(jessehall)
422 .extent = {0, 0, 1},
423 .mipLevels = 1,
424 .arraySize = 1,
425 .samples = 1,
426 .tiling = VK_IMAGE_TILING_OPTIMAL,
427 .usage = create_info->imageUsageFlags,
428 .flags = 0,
429 .sharingMode = create_info->sharingMode,
430 .queueFamilyCount = create_info->queueFamilyCount,
431 .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
432 };
433
Jesse Halld7b994a2015-09-07 14:17:37 -0700434 for (uint32_t i = 0; i < num_images; i++) {
435 Swapchain::Image& img = swapchain->images[i];
436
437 ANativeWindowBuffer* buffer;
438 err = window->dequeueBuffer(window.get(), &buffer, &img.dequeue_fence);
439 if (err != 0) {
440 // TODO(jessehall): Improve error reporting. Can we enumerate
441 // possible errors and translate them to valid Vulkan result codes?
442 ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700443 result = VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700444 break;
445 }
446 img.buffer = InitSharedPtr(device, buffer);
447 img.dequeued = true;
448
449 image_create.extent =
450 VkExtent3D{img.buffer->width, img.buffer->height, 1};
451 image_native_buffer.handle = img.buffer->handle;
452 image_native_buffer.stride = img.buffer->stride;
453 image_native_buffer.format = img.buffer->format;
454 image_native_buffer.usage = img.buffer->usage;
455
456 result = driver_vtbl.CreateImage(device, &image_create, &img.image);
457 if (result != VK_SUCCESS) {
458 ALOGD("vkCreateImage w/ native buffer failed: %u", result);
459 break;
460 }
461 }
462
463 // -- Cancel all buffers, returning them to the queue --
464 // If an error occurred before, also destroy the VkImage and release the
465 // buffer reference. Otherwise, we retain a strong reference to the buffer.
466 //
467 // TODO(jessehall): The error path here is the same as DestroySwapchain,
468 // but not the non-error path. Should refactor/unify.
469 for (uint32_t i = 0; i < num_images; i++) {
470 Swapchain::Image& img = swapchain->images[i];
471 if (img.dequeued) {
472 window->cancelBuffer(window.get(), img.buffer.get(),
473 img.dequeue_fence);
474 img.dequeue_fence = -1;
475 img.dequeued = false;
476 }
477 if (result != VK_SUCCESS) {
478 if (img.image)
479 driver_vtbl.DestroyImage(device, img.image);
480 }
481 }
482
483 if (result != VK_SUCCESS) {
484 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
485 swapchain->~Swapchain();
486 FreeDeviceMem(device, swapchain);
487 return result;
488 }
489
490 *swapchain_handle = HandleFromSwapchain(swapchain);
Jesse Hallb1352bc2015-09-04 16:12:33 -0700491 return VK_SUCCESS;
492}
493
Jesse Halld7b994a2015-09-07 14:17:37 -0700494VkResult DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle) {
495 const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
496 Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
497 const std::shared_ptr<ANativeWindow>& window = swapchain->window;
498
499 for (uint32_t i = 0; i < swapchain->num_images; i++) {
500 Swapchain::Image& img = swapchain->images[i];
501 if (img.dequeued) {
502 window->cancelBuffer(window.get(), img.buffer.get(),
503 img.dequeue_fence);
504 img.dequeue_fence = -1;
505 img.dequeued = false;
506 }
507 if (img.image) {
508 driver_vtbl.DestroyImage(device, img.image);
509 }
510 }
511
512 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL);
513 swapchain->~Swapchain();
514 FreeDeviceMem(device, swapchain);
515
Jesse Hallb1352bc2015-09-04 16:12:33 -0700516 return VK_SUCCESS;
517}
518
Jesse Halld7b994a2015-09-07 14:17:37 -0700519VkResult GetSwapchainImagesKHR(VkDevice,
520 VkSwapchainKHR swapchain_handle,
Jesse Hallb1352bc2015-09-04 16:12:33 -0700521 uint32_t* count,
Jesse Halld7b994a2015-09-07 14:17:37 -0700522 VkImage* images) {
523 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
524 VkResult result = VK_SUCCESS;
525 if (images) {
526 uint32_t n = swapchain.num_images;
527 if (*count < swapchain.num_images) {
528 n = *count;
529 result = VK_INCOMPLETE;
530 }
531 for (uint32_t i = 0; i < n; i++)
532 images[i] = swapchain.images[i].image;
533 }
534 *count = swapchain.num_images;
535 return result;
Jesse Hallb1352bc2015-09-04 16:12:33 -0700536}
537
538VkResult AcquireNextImageKHR(VkDevice device,
Jesse Halld7b994a2015-09-07 14:17:37 -0700539 VkSwapchainKHR swapchain_handle,
Jesse Hallb1352bc2015-09-04 16:12:33 -0700540 uint64_t timeout,
541 VkSemaphore semaphore,
542 uint32_t* image_index) {
Jesse Halld7b994a2015-09-07 14:17:37 -0700543 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
544 VkResult result;
545 int err;
546
547 ALOGW_IF(
548 timeout != UINT64_MAX,
549 "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
550
551 ANativeWindowBuffer* buffer;
552 int fence;
553 err = swapchain.window->dequeueBuffer(swapchain.window.get(), &buffer,
554 &fence);
555 if (err != 0) {
556 // TODO(jessehall): Improve error reporting. Can we enumerate possible
557 // errors and translate them to valid Vulkan result codes?
558 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700559 return VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700560 }
561
562 uint32_t idx;
563 for (idx = 0; idx < swapchain.num_images; idx++) {
564 if (swapchain.images[idx].buffer.get() == buffer) {
565 swapchain.images[idx].dequeued = true;
566 swapchain.images[idx].dequeue_fence = fence;
567 break;
568 }
569 }
570 if (idx == swapchain.num_images) {
571 ALOGE("dequeueBuffer returned unrecognized buffer");
572 swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence);
573#pragma clang diagnostic push
574#pragma clang diagnostic ignored "-Wold-style-cast"
575 return VK_ERROR_OUT_OF_DATE_KHR;
576#pragma clang diagnostic pop
577 }
578
579 int fence_clone = -1;
580 if (fence != -1) {
581 fence_clone = dup(fence);
582 if (fence_clone == -1) {
583 ALOGE("dup(fence) failed, stalling until signalled: %s (%d)",
584 strerror(errno), errno);
585 sync_wait(fence, -1 /* forever */);
586 }
587 }
588
589 const DeviceVtbl& driver_vtbl = GetDriverVtbl(device);
Jesse Hallab9aeef2015-11-04 10:56:20 -0800590 if (driver_vtbl.AcquireImageANDROID) {
591 result = driver_vtbl.AcquireImageANDROID(
592 device, swapchain.images[idx].image, fence_clone, semaphore);
593 } else {
594 ALOG_ASSERT(driver_vtbl.ImportNativeFenceANDROID,
595 "Have neither vkAcquireImageANDROID nor "
596 "vkImportNativeFenceANDROID");
597 result = driver_vtbl.ImportNativeFenceANDROID(device, semaphore,
598 fence_clone);
599 }
Jesse Halld7b994a2015-09-07 14:17:37 -0700600 if (result != VK_SUCCESS) {
Jesse Hallab9aeef2015-11-04 10:56:20 -0800601 // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
602 // even if the call fails. We could close it ourselves on failure, but
603 // that would create a race condition if the driver closes it on a
604 // failure path: some other thread might create an fd with the same
605 // number between the time the driver closes it and the time we close
606 // it. We must assume one of: the driver *always* closes it even on
607 // failure, or *never* closes it on failure.
Jesse Halld7b994a2015-09-07 14:17:37 -0700608 swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence);
609 swapchain.images[idx].dequeued = false;
610 swapchain.images[idx].dequeue_fence = -1;
611 return result;
612 }
613
614 *image_index = idx;
Jesse Hallb1352bc2015-09-04 16:12:33 -0700615 return VK_SUCCESS;
616}
617
618VkResult QueuePresentKHR(VkQueue queue, VkPresentInfoKHR* present_info) {
Jesse Halld7b994a2015-09-07 14:17:37 -0700619#pragma clang diagnostic push
620#pragma clang diagnostic ignored "-Wold-style-cast"
621#pragma clang diagnostic ignored "-Wsign-conversion"
622 ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
623 "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
624 present_info->sType);
Jesse Hallb1352bc2015-09-04 16:12:33 -0700625#pragma clang diagnostic pop
Jesse Halld7b994a2015-09-07 14:17:37 -0700626 ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
627
628 const DeviceVtbl& driver_vtbl = GetDriverVtbl(queue);
629 VkResult final_result = VK_SUCCESS;
630 for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
631 Swapchain& swapchain =
632 *SwapchainFromHandle(present_info->swapchains[sc]);
633 uint32_t image_idx = present_info->imageIndices[sc];
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700634 Swapchain::Image& img = swapchain.images[image_idx];
Jesse Halld7b994a2015-09-07 14:17:37 -0700635 VkResult result;
636 int err;
637
Jesse Halld7b994a2015-09-07 14:17:37 -0700638 int fence = -1;
Jesse Hallab9aeef2015-11-04 10:56:20 -0800639 if (driver_vtbl.QueueSignalReleaseImageANDROID) {
640 result = driver_vtbl.QueueSignalReleaseImageANDROID(
641 queue, img.image, &fence);
642 } else {
643 ALOG_ASSERT(driver_vtbl.QueueSignalNativeFenceANDROID,
644 "Have neither vkQueueSignalReleaseImageANDROID nor "
645 "vkQueueSignalNativeFenceANDROID");
646 result = driver_vtbl.QueueSignalNativeFenceANDROID(queue, &fence);
647 }
Jesse Halld7b994a2015-09-07 14:17:37 -0700648 if (result != VK_SUCCESS) {
Jesse Hallab9aeef2015-11-04 10:56:20 -0800649 ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
Jesse Halld7b994a2015-09-07 14:17:37 -0700650 if (final_result == VK_SUCCESS)
651 final_result = result;
652 // TODO(jessehall): What happens to the buffer here? Does the app
653 // still own it or not, i.e. should we cancel the buffer? Hard to
654 // do correctly without synchronizing, though I guess we could wait
655 // for the queue to idle.
656 continue;
657 }
658
659 err = swapchain.window->queueBuffer(swapchain.window.get(),
660 img.buffer.get(), fence);
661 if (err != 0) {
662 // TODO(jessehall): What now? We should probably cancel the buffer,
663 // I guess?
664 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
665 if (final_result == VK_SUCCESS)
Jesse Hall5ae3abb2015-10-08 14:00:22 -0700666 final_result = VK_ERROR_INITIALIZATION_FAILED;
Jesse Halld7b994a2015-09-07 14:17:37 -0700667 continue;
668 }
669
670 if (img.dequeue_fence != -1) {
671 close(img.dequeue_fence);
672 img.dequeue_fence = -1;
673 }
674 img.dequeued = false;
675 }
676
677 return final_result;
678}
Jesse Hallb1352bc2015-09-04 16:12:33 -0700679
680} // namespace vulkan