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