swapchain.cpp revision 5ae3abb3ca6728de04935b0c81bcdbdfc37b0d47
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// #define LOG_NDEBUG 0 18 19#include <algorithm> 20#include <memory> 21 22#include <gui/BufferQueue.h> 23#include <log/log.h> 24#include <sync/sync.h> 25 26#include "loader.h" 27 28using namespace vulkan; 29 30// 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 35namespace { 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 113 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" 126 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); 131#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 146VkResult GetSurfacePropertiesKHR(VkDevice /*device*/, 147 const VkSurfaceDescriptionKHR* surface_desc, 148 VkSurfacePropertiesKHR* properties) { 149 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? 181 return VK_ERROR_INITIALIZATION_FAILED; 182 } 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); 191 return VK_ERROR_INITIALIZATION_FAILED; 192 } 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); 199 return VK_ERROR_INITIALIZATION_FAILED; 200 } 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 237 return VK_SUCCESS; 238} 239 240VkResult GetSurfaceFormatsKHR(VkDevice /*device*/, 241 const VkSurfaceDescriptionKHR* /*surface_desc*/, 242 uint32_t* count, 243 VkSurfaceFormatKHR* formats) { 244 // 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; 263} 264 265VkResult 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; 283} 284 285VkResult CreateSwapchainKHR(VkDevice device, 286 const VkSwapchainCreateInfoKHR* create_info, 287 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 309 std::shared_ptr<ANativeWindow> window = InitSharedPtr( 310 device, static_cast<ANativeWindow*>( 311 reinterpret_cast<const VkSurfaceDescriptionWindowKHR*>( 312 create_info->pSurfaceDescription) 313 ->pPlatformWindow)); 314 315 // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN. 316 err = native_window_api_connect(window.get(), NATIVE_WINDOW_API_EGL); 317 if (err != 0) { 318 // TODO(jessehall): Improve error reporting. Can we enumerate possible 319 // errors and translate them to valid Vulkan result codes? 320 ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err), 321 err); 322 return VK_ERROR_INITIALIZATION_FAILED; 323 } 324 325 err = native_window_set_buffers_dimensions(window.get(), 326 create_info->imageExtent.width, 327 create_info->imageExtent.height); 328 if (err != 0) { 329 // TODO(jessehall): Improve error reporting. Can we enumerate possible 330 // errors and translate them to valid Vulkan result codes? 331 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", 332 create_info->imageExtent.width, create_info->imageExtent.height, 333 strerror(-err), err); 334 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL); 335 return VK_ERROR_INITIALIZATION_FAILED; 336 } 337 338 uint32_t min_undequeued_buffers; 339 err = window->query(window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 340 reinterpret_cast<int*>(&min_undequeued_buffers)); 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("window->query failed: %s (%d)", strerror(-err), err); 345 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL); 346 return VK_ERROR_INITIALIZATION_FAILED; 347 } 348 uint32_t num_images = 349 (create_info->minImageCount - 1) + min_undequeued_buffers; 350 err = native_window_set_buffer_count(window.get(), num_images); 351 if (err != 0) { 352 // TODO(jessehall): Improve error reporting. Can we enumerate possible 353 // errors and translate them to valid Vulkan result codes? 354 ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), 355 err); 356 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL); 357 return VK_ERROR_INITIALIZATION_FAILED; 358 } 359 360 // TODO(jessehall): Do we need to call modify native_window_set_usage() 361 // based on create_info->imageUsageFlags? 362 363 // -- Allocate our Swapchain object -- 364 // After this point, we must deallocate the swapchain on error. 365 366 void* mem = AllocDeviceMem(device, sizeof(Swapchain), alignof(Swapchain), 367 VK_SYSTEM_ALLOC_TYPE_API_OBJECT); 368 if (!mem) { 369 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL); 370 return VK_ERROR_OUT_OF_HOST_MEMORY; 371 } 372 Swapchain* swapchain = new (mem) Swapchain(window, num_images); 373 374 // -- Dequeue all buffers and create a VkImage for each -- 375 // Any failures during or after this must cancel the dequeued buffers. 376 377 VkNativeBufferANDROID image_native_buffer = { 378// TODO(jessehall): Figure out how to make extension headers not horrible. 379#pragma clang diagnostic push 380#pragma clang diagnostic ignored "-Wold-style-cast" 381 .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID, 382#pragma clang diagnostic pop 383 .pNext = nullptr, 384 }; 385 VkImageCreateInfo image_create = { 386 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 387 .pNext = &image_native_buffer, 388 .imageType = VK_IMAGE_TYPE_2D, 389 .format = VK_FORMAT_R8G8B8A8_UNORM, // TODO(jessehall) 390 .extent = {0, 0, 1}, 391 .mipLevels = 1, 392 .arraySize = 1, 393 .samples = 1, 394 .tiling = VK_IMAGE_TILING_OPTIMAL, 395 .usage = create_info->imageUsageFlags, 396 .flags = 0, 397 .sharingMode = create_info->sharingMode, 398 .queueFamilyCount = create_info->queueFamilyCount, 399 .pQueueFamilyIndices = create_info->pQueueFamilyIndices, 400 }; 401 402 const DeviceVtbl& driver_vtbl = GetDriverVtbl(device); 403 for (uint32_t i = 0; i < num_images; i++) { 404 Swapchain::Image& img = swapchain->images[i]; 405 406 ANativeWindowBuffer* buffer; 407 err = window->dequeueBuffer(window.get(), &buffer, &img.dequeue_fence); 408 if (err != 0) { 409 // TODO(jessehall): Improve error reporting. Can we enumerate 410 // possible errors and translate them to valid Vulkan result codes? 411 ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); 412 result = VK_ERROR_INITIALIZATION_FAILED; 413 break; 414 } 415 img.buffer = InitSharedPtr(device, buffer); 416 img.dequeued = true; 417 418 image_create.extent = 419 VkExtent3D{img.buffer->width, img.buffer->height, 1}; 420 image_native_buffer.handle = img.buffer->handle; 421 image_native_buffer.stride = img.buffer->stride; 422 image_native_buffer.format = img.buffer->format; 423 image_native_buffer.usage = img.buffer->usage; 424 425 result = driver_vtbl.CreateImage(device, &image_create, &img.image); 426 if (result != VK_SUCCESS) { 427 ALOGD("vkCreateImage w/ native buffer failed: %u", result); 428 break; 429 } 430 } 431 432 // -- Cancel all buffers, returning them to the queue -- 433 // If an error occurred before, also destroy the VkImage and release the 434 // buffer reference. Otherwise, we retain a strong reference to the buffer. 435 // 436 // TODO(jessehall): The error path here is the same as DestroySwapchain, 437 // but not the non-error path. Should refactor/unify. 438 for (uint32_t i = 0; i < num_images; i++) { 439 Swapchain::Image& img = swapchain->images[i]; 440 if (img.dequeued) { 441 window->cancelBuffer(window.get(), img.buffer.get(), 442 img.dequeue_fence); 443 img.dequeue_fence = -1; 444 img.dequeued = false; 445 } 446 if (result != VK_SUCCESS) { 447 if (img.image) 448 driver_vtbl.DestroyImage(device, img.image); 449 } 450 } 451 452 if (result != VK_SUCCESS) { 453 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL); 454 swapchain->~Swapchain(); 455 FreeDeviceMem(device, swapchain); 456 return result; 457 } 458 459 *swapchain_handle = HandleFromSwapchain(swapchain); 460 return VK_SUCCESS; 461} 462 463VkResult DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle) { 464 const DeviceVtbl& driver_vtbl = GetDriverVtbl(device); 465 Swapchain* swapchain = SwapchainFromHandle(swapchain_handle); 466 const std::shared_ptr<ANativeWindow>& window = swapchain->window; 467 468 for (uint32_t i = 0; i < swapchain->num_images; i++) { 469 Swapchain::Image& img = swapchain->images[i]; 470 if (img.dequeued) { 471 window->cancelBuffer(window.get(), img.buffer.get(), 472 img.dequeue_fence); 473 img.dequeue_fence = -1; 474 img.dequeued = false; 475 } 476 if (img.image) { 477 driver_vtbl.DestroyImage(device, img.image); 478 } 479 } 480 481 native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_EGL); 482 swapchain->~Swapchain(); 483 FreeDeviceMem(device, swapchain); 484 485 return VK_SUCCESS; 486} 487 488VkResult GetSwapchainImagesKHR(VkDevice, 489 VkSwapchainKHR swapchain_handle, 490 uint32_t* count, 491 VkImage* images) { 492 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); 493 VkResult result = VK_SUCCESS; 494 if (images) { 495 uint32_t n = swapchain.num_images; 496 if (*count < swapchain.num_images) { 497 n = *count; 498 result = VK_INCOMPLETE; 499 } 500 for (uint32_t i = 0; i < n; i++) 501 images[i] = swapchain.images[i].image; 502 } 503 *count = swapchain.num_images; 504 return result; 505} 506 507VkResult AcquireNextImageKHR(VkDevice device, 508 VkSwapchainKHR swapchain_handle, 509 uint64_t timeout, 510 VkSemaphore semaphore, 511 uint32_t* image_index) { 512 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); 513 VkResult result; 514 int err; 515 516 ALOGW_IF( 517 timeout != UINT64_MAX, 518 "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented"); 519 520 ANativeWindowBuffer* buffer; 521 int fence; 522 err = swapchain.window->dequeueBuffer(swapchain.window.get(), &buffer, 523 &fence); 524 if (err != 0) { 525 // TODO(jessehall): Improve error reporting. Can we enumerate possible 526 // errors and translate them to valid Vulkan result codes? 527 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); 528 return VK_ERROR_INITIALIZATION_FAILED; 529 } 530 531 uint32_t idx; 532 for (idx = 0; idx < swapchain.num_images; idx++) { 533 if (swapchain.images[idx].buffer.get() == buffer) { 534 swapchain.images[idx].dequeued = true; 535 swapchain.images[idx].dequeue_fence = fence; 536 break; 537 } 538 } 539 if (idx == swapchain.num_images) { 540 ALOGE("dequeueBuffer returned unrecognized buffer"); 541 swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence); 542#pragma clang diagnostic push 543#pragma clang diagnostic ignored "-Wold-style-cast" 544 return VK_ERROR_OUT_OF_DATE_KHR; 545#pragma clang diagnostic pop 546 } 547 548 int fence_clone = -1; 549 if (fence != -1) { 550 fence_clone = dup(fence); 551 if (fence_clone == -1) { 552 ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", 553 strerror(errno), errno); 554 sync_wait(fence, -1 /* forever */); 555 } 556 } 557 558 const DeviceVtbl& driver_vtbl = GetDriverVtbl(device); 559 result = 560 driver_vtbl.ImportNativeFenceANDROID(device, semaphore, fence_clone); 561 if (result != VK_SUCCESS) { 562 // NOTE: we're relying on ImportNativeFenceANDROID to close 563 // fence_clone, even if the call fails. We could close it ourselves on 564 // failure, but that would create a race condition if the driver closes 565 // it on a failure path. We must assume one of: the driver *always* 566 // closes it even on failure, or *never* closes it on failure. 567 swapchain.window->cancelBuffer(swapchain.window.get(), buffer, fence); 568 swapchain.images[idx].dequeued = false; 569 swapchain.images[idx].dequeue_fence = -1; 570 return result; 571 } 572 573 *image_index = idx; 574 return VK_SUCCESS; 575} 576 577VkResult QueuePresentKHR(VkQueue queue, VkPresentInfoKHR* present_info) { 578#pragma clang diagnostic push 579#pragma clang diagnostic ignored "-Wold-style-cast" 580#pragma clang diagnostic ignored "-Wsign-conversion" 581 ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 582 "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d", 583 present_info->sType); 584#pragma clang diagnostic pop 585 ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL"); 586 587 const DeviceVtbl& driver_vtbl = GetDriverVtbl(queue); 588 VkResult final_result = VK_SUCCESS; 589 for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) { 590 Swapchain& swapchain = 591 *SwapchainFromHandle(present_info->swapchains[sc]); 592 uint32_t image_idx = present_info->imageIndices[sc]; 593 Swapchain::Image& img = swapchain.images[image_idx]; 594 VkResult result; 595 int err; 596 597 int fence = -1; 598 result = driver_vtbl.QueueSignalNativeFenceANDROID(queue, &fence); 599 if (result != VK_SUCCESS) { 600 ALOGE("vkQueueSignalNativeFenceANDROID failed: %d", result); 601 if (final_result == VK_SUCCESS) 602 final_result = result; 603 // TODO(jessehall): What happens to the buffer here? Does the app 604 // still own it or not, i.e. should we cancel the buffer? Hard to 605 // do correctly without synchronizing, though I guess we could wait 606 // for the queue to idle. 607 continue; 608 } 609 610 err = swapchain.window->queueBuffer(swapchain.window.get(), 611 img.buffer.get(), fence); 612 if (err != 0) { 613 // TODO(jessehall): What now? We should probably cancel the buffer, 614 // I guess? 615 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err); 616 if (final_result == VK_SUCCESS) 617 final_result = VK_ERROR_INITIALIZATION_FAILED; 618 continue; 619 } 620 621 if (img.dequeue_fence != -1) { 622 close(img.dequeue_fence); 623 img.dequeue_fence = -1; 624 } 625 img.dequeued = false; 626 } 627 628 return final_result; 629} 630 631} // namespace vulkan 632