swapchain.cpp revision 4da65b9bea890864effb0b5bab0a258cb0c6d685
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#include <utils/SortedVector.h> 24 25#include "driver.h" 26 27// TODO(jessehall): Currently we don't have a good error code for when a native 28// window operation fails. Just returning INITIALIZATION_FAILED for now. Later 29// versions (post SDK 0.9) of the API/extension have a better error code. 30// When updating to that version, audit all error returns. 31namespace vulkan { 32namespace driver { 33 34namespace { 35 36const VkSurfaceTransformFlagsKHR kSupportedTransforms = 37 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR | 38 VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | 39 VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | 40 VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR | 41 // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. 42 // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR | 43 // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | 44 // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR | 45 // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR | 46 VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; 47 48VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) { 49 // Native and Vulkan transforms are isomorphic, but are represented 50 // differently. Vulkan transforms are built up of an optional horizontal 51 // mirror, followed by a clockwise 0/90/180/270-degree rotation. Native 52 // transforms are built up from a horizontal flip, vertical flip, and 53 // 90-degree rotation, all optional but always in that order. 54 55 // TODO(jessehall): For now, only support pure rotations, not 56 // flip or flip-and-rotate, until I have more time to test them and build 57 // sample code. As far as I know we never actually use anything besides 58 // pure rotations anyway. 59 60 switch (native) { 61 case 0: // 0x0 62 return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 63 // case NATIVE_WINDOW_TRANSFORM_FLIP_H: // 0x1 64 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR; 65 // case NATIVE_WINDOW_TRANSFORM_FLIP_V: // 0x2 66 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR; 67 case NATIVE_WINDOW_TRANSFORM_ROT_180: // FLIP_H | FLIP_V 68 return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; 69 case NATIVE_WINDOW_TRANSFORM_ROT_90: // 0x4 70 return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; 71 // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90: 72 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR; 73 // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90: 74 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR; 75 case NATIVE_WINDOW_TRANSFORM_ROT_270: // FLIP_H | FLIP_V | ROT_90 76 return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; 77 case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY: 78 default: 79 return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 80 } 81} 82 83int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { 84 switch (transform) { 85 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: 86 return NATIVE_WINDOW_TRANSFORM_ROT_270; 87 case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: 88 return NATIVE_WINDOW_TRANSFORM_ROT_180; 89 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: 90 return NATIVE_WINDOW_TRANSFORM_ROT_90; 91 // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. 92 // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: 93 // return NATIVE_WINDOW_TRANSFORM_FLIP_H; 94 // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: 95 // return NATIVE_WINDOW_TRANSFORM_FLIP_H | 96 // NATIVE_WINDOW_TRANSFORM_ROT_90; 97 // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: 98 // return NATIVE_WINDOW_TRANSFORM_FLIP_V; 99 // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: 100 // return NATIVE_WINDOW_TRANSFORM_FLIP_V | 101 // NATIVE_WINDOW_TRANSFORM_ROT_90; 102 case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: 103 case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: 104 default: 105 return 0; 106 } 107} 108 109class TimingInfo { 110 public: 111 TimingInfo() 112 : vals_{0, 0, 0, 0, 0}, 113 timestamp_desired_present_time_(0), 114 timestamp_actual_present_time_(0), 115 timestamp_render_complete_time_(0), 116 timestamp_composition_latch_time_(0) {} 117 TimingInfo(const VkPresentTimeGOOGLE* qp) 118 : vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0}, 119 timestamp_desired_present_time_(0), 120 timestamp_actual_present_time_(0), 121 timestamp_render_complete_time_(0), 122 timestamp_composition_latch_time_(0) {} 123 bool ready() { 124 return (timestamp_desired_present_time_ && 125 timestamp_actual_present_time_ && 126 timestamp_render_complete_time_ && 127 timestamp_composition_latch_time_); 128 } 129 void calculate(uint64_t rdur) { 130 vals_.actualPresentTime = timestamp_actual_present_time_; 131 uint64_t margin = (timestamp_composition_latch_time_ - 132 timestamp_render_complete_time_); 133 // Calculate vals_.earliestPresentTime, and potentially adjust 134 // vals_.presentMargin. The initial value of vals_.earliestPresentTime 135 // is vals_.actualPresentTime. If we can subtract rdur (the duration 136 // of a refresh cycle) from vals_.earliestPresentTime (and also from 137 // vals_.presentMargin) and still leave a positive margin, then we can 138 // report to the application that it could have presented earlier than 139 // it did (per the extension specification). If for some reason, we 140 // can do this subtraction repeatedly, we do, since 141 // vals_.earliestPresentTime really is supposed to be the "earliest". 142 uint64_t early_time = vals_.actualPresentTime; 143 while ((margin > rdur) && 144 ((early_time - rdur) > timestamp_composition_latch_time_)) { 145 early_time -= rdur; 146 margin -= rdur; 147 } 148 vals_.earliestPresentTime = early_time; 149 vals_.presentMargin = margin; 150 } 151 void get_values(VkPastPresentationTimingGOOGLE* values) { *values = vals_; } 152 153 public: 154 VkPastPresentationTimingGOOGLE vals_; 155 156 uint64_t timestamp_desired_present_time_; 157 uint64_t timestamp_actual_present_time_; 158 uint64_t timestamp_render_complete_time_; 159 uint64_t timestamp_composition_latch_time_; 160}; 161 162static inline int compare_type(const TimingInfo& lhs, const TimingInfo& rhs) { 163 // TODO(ianelliott): Change this from presentID to the frame ID once 164 // brianderson lands the appropriate patch: 165 if (lhs.vals_.presentID < rhs.vals_.presentID) 166 return -1; 167 if (lhs.vals_.presentID > rhs.vals_.presentID) 168 return 1; 169 return 0; 170} 171 172// ---------------------------------------------------------------------------- 173 174struct Surface { 175 android::sp<ANativeWindow> window; 176 VkSwapchainKHR swapchain_handle; 177}; 178 179VkSurfaceKHR HandleFromSurface(Surface* surface) { 180 return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface)); 181} 182 183Surface* SurfaceFromHandle(VkSurfaceKHR handle) { 184 return reinterpret_cast<Surface*>(handle); 185} 186 187// Maximum number of TimingInfo structs to keep per swapchain: 188enum { MAX_TIMING_INFOS = 10 }; 189// Minimum number of frames to look for in the past (so we don't cause 190// syncronous requests to Surface Flinger): 191enum { MIN_NUM_FRAMES_AGO = 5 }; 192 193struct Swapchain { 194 Swapchain(Surface& surface_, uint32_t num_images_) 195 : surface(surface_), 196 num_images(num_images_), 197 frame_timestamps_enabled(false) { 198 timing.clear(); 199 ANativeWindow* window = surface.window.get(); 200 int64_t rdur; 201 native_window_get_refresh_cycle_duration( 202 window, 203 &rdur); 204 refresh_duration = static_cast<uint64_t>(rdur); 205 } 206 207 Surface& surface; 208 uint32_t num_images; 209 bool frame_timestamps_enabled; 210 uint64_t refresh_duration; 211 212 struct Image { 213 Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {} 214 VkImage image; 215 android::sp<ANativeWindowBuffer> buffer; 216 // The fence is only valid when the buffer is dequeued, and should be 217 // -1 any other time. When valid, we own the fd, and must ensure it is 218 // closed: either by closing it explicitly when queueing the buffer, 219 // or by passing ownership e.g. to ANativeWindow::cancelBuffer(). 220 int dequeue_fence; 221 bool dequeued; 222 } images[android::BufferQueue::NUM_BUFFER_SLOTS]; 223 224 android::SortedVector<TimingInfo> timing; 225}; 226 227VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) { 228 return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain)); 229} 230 231Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) { 232 return reinterpret_cast<Swapchain*>(handle); 233} 234 235void ReleaseSwapchainImage(VkDevice device, 236 ANativeWindow* window, 237 int release_fence, 238 Swapchain::Image& image) { 239 ALOG_ASSERT(release_fence == -1 || image.dequeued, 240 "ReleaseSwapchainImage: can't provide a release fence for " 241 "non-dequeued images"); 242 243 if (image.dequeued) { 244 if (release_fence >= 0) { 245 // We get here from vkQueuePresentKHR. The application is 246 // responsible for creating an execution dependency chain from 247 // vkAcquireNextImage (dequeue_fence) to vkQueuePresentKHR 248 // (release_fence), so we can drop the dequeue_fence here. 249 if (image.dequeue_fence >= 0) 250 close(image.dequeue_fence); 251 } else { 252 // We get here during swapchain destruction, or various serious 253 // error cases e.g. when we can't create the release_fence during 254 // vkQueuePresentKHR. In non-error cases, the dequeue_fence should 255 // have already signalled, since the swapchain images are supposed 256 // to be idle before the swapchain is destroyed. In error cases, 257 // there may be rendering in flight to the image, but since we 258 // weren't able to create a release_fence, waiting for the 259 // dequeue_fence is about the best we can do. 260 release_fence = image.dequeue_fence; 261 } 262 image.dequeue_fence = -1; 263 264 if (window) { 265 window->cancelBuffer(window, image.buffer.get(), release_fence); 266 } else { 267 if (release_fence >= 0) { 268 sync_wait(release_fence, -1 /* forever */); 269 close(release_fence); 270 } 271 } 272 273 image.dequeued = false; 274 } 275 276 if (image.image) { 277 GetData(device).driver.DestroyImage(device, image.image, nullptr); 278 image.image = VK_NULL_HANDLE; 279 } 280 281 image.buffer.clear(); 282} 283 284void OrphanSwapchain(VkDevice device, Swapchain* swapchain) { 285 if (swapchain->surface.swapchain_handle != HandleFromSwapchain(swapchain)) 286 return; 287 for (uint32_t i = 0; i < swapchain->num_images; i++) { 288 if (!swapchain->images[i].dequeued) 289 ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]); 290 } 291 swapchain->surface.swapchain_handle = VK_NULL_HANDLE; 292 swapchain->timing.clear(); 293} 294 295uint32_t get_num_ready_timings(Swapchain& swapchain) { 296 uint32_t num_ready = 0; 297 uint32_t num_timings = static_cast<uint32_t>(swapchain.timing.size()); 298 uint32_t frames_ago = num_timings; 299 for (uint32_t i = 0; i < num_timings; i++) { 300 TimingInfo* ti = &swapchain.timing.editItemAt(i); 301 if (ti) { 302 if (ti->ready()) { 303 // This TimingInfo is ready to be reported to the user. Add it 304 // to the num_ready. 305 num_ready++; 306 } else { 307 // This TimingInfo is not yet ready to be reported to the user, 308 // and so we should look for any available timestamps that 309 // might make it ready. 310 int64_t desired_present_time = 0; 311 int64_t render_complete_time = 0; 312 int64_t composition_latch_time = 0; 313 int64_t actual_present_time = 0; 314 for (uint32_t f = MIN_NUM_FRAMES_AGO; f < frames_ago; f++) { 315 // Obtain timestamps: 316 int ret = native_window_get_frame_timestamps( 317 swapchain.surface.window.get(), f, 318 &desired_present_time, &render_complete_time, 319 &composition_latch_time, 320 NULL, //&first_composition_start_time, 321 NULL, //&last_composition_start_time, 322 NULL, //&composition_finish_time, 323 // TODO(ianelliott): Maybe ask if this one is 324 // supported, at startup time (since it may not be 325 // supported): 326 &actual_present_time, 327 NULL, //&display_retire_time, 328 NULL, //&dequeue_ready_time, 329 NULL /*&reads_done_time*/); 330 if (ret) { 331 break; 332 } else if (!ret) { 333 // We obtained at least one valid timestamp. See if it 334 // is for the present represented by this TimingInfo: 335 if (static_cast<uint64_t>(desired_present_time) == 336 ti->vals_.desiredPresentTime) { 337 // Record the timestamp(s) we received, and then 338 // see if this TimingInfo is ready to be reported 339 // to the user: 340 ti->timestamp_desired_present_time_ = 341 static_cast<uint64_t>(desired_present_time); 342 ti->timestamp_actual_present_time_ = 343 static_cast<uint64_t>(actual_present_time); 344 ti->timestamp_render_complete_time_ = 345 static_cast<uint64_t>(render_complete_time); 346 ti->timestamp_composition_latch_time_ = 347 static_cast<uint64_t>(composition_latch_time); 348 349 if (ti->ready()) { 350 // The TimingInfo has received enough 351 // timestamps, and should now use those 352 // timestamps to calculate the info that should 353 // be reported to the user: 354 // 355 ti->calculate(swapchain.refresh_duration); 356 num_ready++; 357 } 358 break; 359 } 360 } 361 } 362 } 363 } 364 } 365 return num_ready; 366} 367 368// TODO(ianelliott): DEAL WITH RETURN VALUE (e.g. VK_INCOMPLETE)!!! 369void copy_ready_timings(Swapchain& swapchain, 370 uint32_t* count, 371 VkPastPresentationTimingGOOGLE* timings) { 372 uint32_t num_copied = 0; 373 uint32_t num_timings = static_cast<uint32_t>(swapchain.timing.size()); 374 if (*count < num_timings) { 375 num_timings = *count; 376 } 377 for (uint32_t i = 0; i < num_timings; i++) { 378 TimingInfo* ti = &swapchain.timing.editItemAt(i); 379 if (ti && ti->ready()) { 380 ti->get_values(&timings[num_copied]); 381 num_copied++; 382 // We only report the values for a given present once, so remove 383 // them from swapchain.timing: 384 // 385 // TODO(ianelliott): SEE WHAT HAPPENS TO THE LOOP WHEN THE 386 // FOLLOWING IS DONE: 387 swapchain.timing.removeAt(i); 388 i--; 389 num_timings--; 390 if (*count == num_copied) { 391 break; 392 } 393 } 394 } 395 *count = num_copied; 396} 397 398} // anonymous namespace 399 400VKAPI_ATTR 401VkResult CreateAndroidSurfaceKHR( 402 VkInstance instance, 403 const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, 404 const VkAllocationCallbacks* allocator, 405 VkSurfaceKHR* out_surface) { 406 if (!allocator) 407 allocator = &GetData(instance).allocator; 408 void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface), 409 alignof(Surface), 410 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 411 if (!mem) 412 return VK_ERROR_OUT_OF_HOST_MEMORY; 413 Surface* surface = new (mem) Surface; 414 415 surface->window = pCreateInfo->window; 416 surface->swapchain_handle = VK_NULL_HANDLE; 417 418 // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN. 419 int err = 420 native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL); 421 if (err != 0) { 422 // TODO(jessehall): Improve error reporting. Can we enumerate possible 423 // errors and translate them to valid Vulkan result codes? 424 ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err), 425 err); 426 surface->~Surface(); 427 allocator->pfnFree(allocator->pUserData, surface); 428 return VK_ERROR_INITIALIZATION_FAILED; 429 } 430 431 *out_surface = HandleFromSurface(surface); 432 return VK_SUCCESS; 433} 434 435VKAPI_ATTR 436void DestroySurfaceKHR(VkInstance instance, 437 VkSurfaceKHR surface_handle, 438 const VkAllocationCallbacks* allocator) { 439 Surface* surface = SurfaceFromHandle(surface_handle); 440 if (!surface) 441 return; 442 native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL); 443 ALOGV_IF(surface->swapchain_handle != VK_NULL_HANDLE, 444 "destroyed VkSurfaceKHR 0x%" PRIx64 445 " has active VkSwapchainKHR 0x%" PRIx64, 446 reinterpret_cast<uint64_t>(surface_handle), 447 reinterpret_cast<uint64_t>(surface->swapchain_handle)); 448 surface->~Surface(); 449 if (!allocator) 450 allocator = &GetData(instance).allocator; 451 allocator->pfnFree(allocator->pUserData, surface); 452} 453 454VKAPI_ATTR 455VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/, 456 uint32_t /*queue_family*/, 457 VkSurfaceKHR /*surface*/, 458 VkBool32* supported) { 459 *supported = VK_TRUE; 460 return VK_SUCCESS; 461} 462 463VKAPI_ATTR 464VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( 465 VkPhysicalDevice /*pdev*/, 466 VkSurfaceKHR surface, 467 VkSurfaceCapabilitiesKHR* capabilities) { 468 int err; 469 ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); 470 471 int width, height; 472 err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); 473 if (err != 0) { 474 ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", 475 strerror(-err), err); 476 return VK_ERROR_INITIALIZATION_FAILED; 477 } 478 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); 479 if (err != 0) { 480 ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", 481 strerror(-err), err); 482 return VK_ERROR_INITIALIZATION_FAILED; 483 } 484 485 int transform_hint; 486 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint); 487 if (err != 0) { 488 ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", 489 strerror(-err), err); 490 return VK_ERROR_INITIALIZATION_FAILED; 491 } 492 493 // TODO(jessehall): Figure out what the min/max values should be. 494 capabilities->minImageCount = 2; 495 capabilities->maxImageCount = 3; 496 497 capabilities->currentExtent = 498 VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)}; 499 500 // TODO(jessehall): Figure out what the max extent should be. Maximum 501 // texture dimension maybe? 502 capabilities->minImageExtent = VkExtent2D{1, 1}; 503 capabilities->maxImageExtent = VkExtent2D{4096, 4096}; 504 505 capabilities->maxImageArrayLayers = 1; 506 507 capabilities->supportedTransforms = kSupportedTransforms; 508 capabilities->currentTransform = 509 TranslateNativeToVulkanTransform(transform_hint); 510 511 // On Android, window composition is a WindowManager property, not something 512 // associated with the bufferqueue. It can't be changed from here. 513 capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; 514 515 // TODO(jessehall): I think these are right, but haven't thought hard about 516 // it. Do we need to query the driver for support of any of these? 517 // Currently not included: 518 // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not 519 // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not 520 capabilities->supportedUsageFlags = 521 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | 522 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | 523 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 524 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; 525 526 return VK_SUCCESS; 527} 528 529VKAPI_ATTR 530VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/, 531 VkSurfaceKHR /*surface*/, 532 uint32_t* count, 533 VkSurfaceFormatKHR* formats) { 534 // TODO(jessehall): Fill out the set of supported formats. Longer term, add 535 // a new gralloc method to query whether a (format, usage) pair is 536 // supported, and check that for each gralloc format that corresponds to a 537 // Vulkan format. Shorter term, just add a few more formats to the ones 538 // hardcoded below. 539 540 const VkSurfaceFormatKHR kFormats[] = { 541 {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, 542 {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, 543 {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, 544 }; 545 const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); 546 547 VkResult result = VK_SUCCESS; 548 if (formats) { 549 if (*count < kNumFormats) 550 result = VK_INCOMPLETE; 551 *count = std::min(*count, kNumFormats); 552 std::copy(kFormats, kFormats + *count, formats); 553 } else { 554 *count = kNumFormats; 555 } 556 return result; 557} 558 559VKAPI_ATTR 560VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/, 561 VkSurfaceKHR /*surface*/, 562 uint32_t* count, 563 VkPresentModeKHR* modes) { 564 const VkPresentModeKHR kModes[] = { 565 VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR, 566 // TODO(chrisforbes): should only expose this if the driver can. 567 VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, 568 VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, 569 }; 570 const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]); 571 572 VkResult result = VK_SUCCESS; 573 if (modes) { 574 if (*count < kNumModes) 575 result = VK_INCOMPLETE; 576 *count = std::min(*count, kNumModes); 577 std::copy(kModes, kModes + *count, modes); 578 } else { 579 *count = kNumModes; 580 } 581 return result; 582} 583 584VKAPI_ATTR 585VkResult CreateSwapchainKHR(VkDevice device, 586 const VkSwapchainCreateInfoKHR* create_info, 587 const VkAllocationCallbacks* allocator, 588 VkSwapchainKHR* swapchain_handle) { 589 int err; 590 VkResult result = VK_SUCCESS; 591 592 ALOGV("vkCreateSwapchainKHR: surface=0x%" PRIx64 593 " minImageCount=%u imageFormat=%u imageColorSpace=%u" 594 " imageExtent=%ux%u imageUsage=%#x preTransform=%u presentMode=%u" 595 " oldSwapchain=0x%" PRIx64, 596 reinterpret_cast<uint64_t>(create_info->surface), 597 create_info->minImageCount, create_info->imageFormat, 598 create_info->imageColorSpace, create_info->imageExtent.width, 599 create_info->imageExtent.height, create_info->imageUsage, 600 create_info->preTransform, create_info->presentMode, 601 reinterpret_cast<uint64_t>(create_info->oldSwapchain)); 602 603 if (!allocator) 604 allocator = &GetData(device).allocator; 605 606 ALOGV_IF(create_info->imageArrayLayers != 1, 607 "swapchain imageArrayLayers=%u not supported", 608 create_info->imageArrayLayers); 609 ALOGV_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, 610 "swapchain imageColorSpace=%u not supported", 611 create_info->imageColorSpace); 612 ALOGV_IF((create_info->preTransform & ~kSupportedTransforms) != 0, 613 "swapchain preTransform=%#x not supported", 614 create_info->preTransform); 615 ALOGV_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR || 616 create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR || 617 create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || 618 create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR), 619 "swapchain presentMode=%u not supported", 620 create_info->presentMode); 621 622 Surface& surface = *SurfaceFromHandle(create_info->surface); 623 624 if (surface.swapchain_handle != create_info->oldSwapchain) { 625 ALOGV("Can't create a swapchain for VkSurfaceKHR 0x%" PRIx64 626 " because it already has active swapchain 0x%" PRIx64 627 " but VkSwapchainCreateInfo::oldSwapchain=0x%" PRIx64, 628 reinterpret_cast<uint64_t>(create_info->surface), 629 reinterpret_cast<uint64_t>(surface.swapchain_handle), 630 reinterpret_cast<uint64_t>(create_info->oldSwapchain)); 631 return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; 632 } 633 if (create_info->oldSwapchain != VK_NULL_HANDLE) 634 OrphanSwapchain(device, SwapchainFromHandle(create_info->oldSwapchain)); 635 636 // -- Reset the native window -- 637 // The native window might have been used previously, and had its properties 638 // changed from defaults. That will affect the answer we get for queries 639 // like MIN_UNDEQUED_BUFFERS. Reset to a known/default state before we 640 // attempt such queries. 641 642 // The native window only allows dequeueing all buffers before any have 643 // been queued, since after that point at least one is assumed to be in 644 // non-FREE state at any given time. Disconnecting and re-connecting 645 // orphans the previous buffers, getting us back to the state where we can 646 // dequeue all buffers. 647 err = native_window_api_disconnect(surface.window.get(), 648 NATIVE_WINDOW_API_EGL); 649 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", 650 strerror(-err), err); 651 err = 652 native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL); 653 ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)", 654 strerror(-err), err); 655 656 err = native_window_set_buffer_count(surface.window.get(), 0); 657 if (err != 0) { 658 ALOGE("native_window_set_buffer_count(0) failed: %s (%d)", 659 strerror(-err), err); 660 return VK_ERROR_INITIALIZATION_FAILED; 661 } 662 663 err = surface.window->setSwapInterval(surface.window.get(), 1); 664 if (err != 0) { 665 // TODO(jessehall): Improve error reporting. Can we enumerate possible 666 // errors and translate them to valid Vulkan result codes? 667 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", 668 strerror(-err), err); 669 return VK_ERROR_INITIALIZATION_FAILED; 670 } 671 672 err = native_window_set_shared_buffer_mode(surface.window.get(), false); 673 if (err != 0) { 674 ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", 675 strerror(-err), err); 676 return VK_ERROR_INITIALIZATION_FAILED; 677 } 678 679 err = native_window_set_auto_refresh(surface.window.get(), false); 680 if (err != 0) { 681 ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", 682 strerror(-err), err); 683 return VK_ERROR_INITIALIZATION_FAILED; 684 } 685 686 // -- Configure the native window -- 687 688 const auto& dispatch = GetData(device).driver; 689 690 int native_format = HAL_PIXEL_FORMAT_RGBA_8888; 691 switch (create_info->imageFormat) { 692 case VK_FORMAT_R8G8B8A8_UNORM: 693 case VK_FORMAT_R8G8B8A8_SRGB: 694 native_format = HAL_PIXEL_FORMAT_RGBA_8888; 695 break; 696 case VK_FORMAT_R5G6B5_UNORM_PACK16: 697 native_format = HAL_PIXEL_FORMAT_RGB_565; 698 break; 699 default: 700 ALOGV("unsupported swapchain format %d", create_info->imageFormat); 701 break; 702 } 703 err = native_window_set_buffers_format(surface.window.get(), native_format); 704 if (err != 0) { 705 // TODO(jessehall): Improve error reporting. Can we enumerate possible 706 // errors and translate them to valid Vulkan result codes? 707 ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)", 708 native_format, strerror(-err), err); 709 return VK_ERROR_INITIALIZATION_FAILED; 710 } 711 err = native_window_set_buffers_data_space(surface.window.get(), 712 HAL_DATASPACE_SRGB_LINEAR); 713 if (err != 0) { 714 // TODO(jessehall): Improve error reporting. Can we enumerate possible 715 // errors and translate them to valid Vulkan result codes? 716 ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)", 717 HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err); 718 return VK_ERROR_INITIALIZATION_FAILED; 719 } 720 721 err = native_window_set_buffers_dimensions( 722 surface.window.get(), static_cast<int>(create_info->imageExtent.width), 723 static_cast<int>(create_info->imageExtent.height)); 724 if (err != 0) { 725 // TODO(jessehall): Improve error reporting. Can we enumerate possible 726 // errors and translate them to valid Vulkan result codes? 727 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", 728 create_info->imageExtent.width, create_info->imageExtent.height, 729 strerror(-err), err); 730 return VK_ERROR_INITIALIZATION_FAILED; 731 } 732 733 // VkSwapchainCreateInfo::preTransform indicates the transformation the app 734 // applied during rendering. native_window_set_transform() expects the 735 // inverse: the transform the app is requesting that the compositor perform 736 // during composition. With native windows, pre-transform works by rendering 737 // with the same transform the compositor is applying (as in Vulkan), but 738 // then requesting the inverse transform, so that when the compositor does 739 // it's job the two transforms cancel each other out and the compositor ends 740 // up applying an identity transform to the app's buffer. 741 err = native_window_set_buffers_transform( 742 surface.window.get(), 743 InvertTransformToNative(create_info->preTransform)); 744 if (err != 0) { 745 // TODO(jessehall): Improve error reporting. Can we enumerate possible 746 // errors and translate them to valid Vulkan result codes? 747 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", 748 InvertTransformToNative(create_info->preTransform), 749 strerror(-err), err); 750 return VK_ERROR_INITIALIZATION_FAILED; 751 } 752 753 err = native_window_set_scaling_mode( 754 surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); 755 if (err != 0) { 756 // TODO(jessehall): Improve error reporting. Can we enumerate possible 757 // errors and translate them to valid Vulkan result codes? 758 ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)", 759 strerror(-err), err); 760 return VK_ERROR_INITIALIZATION_FAILED; 761 } 762 763 int query_value; 764 err = surface.window->query(surface.window.get(), 765 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 766 &query_value); 767 if (err != 0 || query_value < 0) { 768 // TODO(jessehall): Improve error reporting. Can we enumerate possible 769 // errors and translate them to valid Vulkan result codes? 770 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, 771 query_value); 772 return VK_ERROR_INITIALIZATION_FAILED; 773 } 774 uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value); 775 // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using 776 // async mode or not, and assumes not. But in async mode, the BufferQueue 777 // requires an extra undequeued buffer. 778 // See BufferQueueCore::getMinUndequeuedBufferCountLocked(). 779 if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) 780 min_undequeued_buffers += 1; 781 782 uint32_t num_images = 783 (create_info->minImageCount - 1) + min_undequeued_buffers; 784 err = native_window_set_buffer_count(surface.window.get(), num_images); 785 if (err != 0) { 786 // TODO(jessehall): Improve error reporting. Can we enumerate possible 787 // errors and translate them to valid Vulkan result codes? 788 ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images, 789 strerror(-err), err); 790 return VK_ERROR_INITIALIZATION_FAILED; 791 } 792 793 VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0; 794 if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || 795 create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { 796 swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID; 797 798 err = native_window_set_shared_buffer_mode(surface.window.get(), true); 799 if (err != 0) { 800 ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err); 801 return VK_ERROR_INITIALIZATION_FAILED; 802 } 803 } 804 805 if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { 806 err = native_window_set_auto_refresh(surface.window.get(), true); 807 if (err != 0) { 808 ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err); 809 return VK_ERROR_INITIALIZATION_FAILED; 810 } 811 } 812 813 int gralloc_usage = 0; 814 if (dispatch.GetSwapchainGrallocUsage2ANDROID) { 815 result = dispatch.GetSwapchainGrallocUsage2ANDROID( 816 device, create_info->imageFormat, create_info->imageUsage, 817 swapchain_image_usage, &gralloc_usage); 818 if (result != VK_SUCCESS) { 819 ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result); 820 return VK_ERROR_INITIALIZATION_FAILED; 821 } 822 } else if (dispatch.GetSwapchainGrallocUsageANDROID) { 823 result = dispatch.GetSwapchainGrallocUsageANDROID( 824 device, create_info->imageFormat, create_info->imageUsage, 825 &gralloc_usage); 826 if (result != VK_SUCCESS) { 827 ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result); 828 return VK_ERROR_INITIALIZATION_FAILED; 829 } 830 } else { 831 gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; 832 } 833 err = native_window_set_usage(surface.window.get(), gralloc_usage); 834 if (err != 0) { 835 // TODO(jessehall): Improve error reporting. Can we enumerate possible 836 // errors and translate them to valid Vulkan result codes? 837 ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err); 838 return VK_ERROR_INITIALIZATION_FAILED; 839 } 840 841 int swap_interval = 842 create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1; 843 err = surface.window->setSwapInterval(surface.window.get(), swap_interval); 844 if (err != 0) { 845 // TODO(jessehall): Improve error reporting. Can we enumerate possible 846 // errors and translate them to valid Vulkan result codes? 847 ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)", 848 swap_interval, strerror(-err), err); 849 return VK_ERROR_INITIALIZATION_FAILED; 850 } 851 852 // -- Allocate our Swapchain object -- 853 // After this point, we must deallocate the swapchain on error. 854 855 void* mem = allocator->pfnAllocation(allocator->pUserData, 856 sizeof(Swapchain), alignof(Swapchain), 857 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 858 if (!mem) 859 return VK_ERROR_OUT_OF_HOST_MEMORY; 860 Swapchain* swapchain = new (mem) Swapchain(surface, num_images); 861 862 // -- Dequeue all buffers and create a VkImage for each -- 863 // Any failures during or after this must cancel the dequeued buffers. 864 865 VkSwapchainImageCreateInfoANDROID swapchain_image_create = { 866#pragma clang diagnostic push 867#pragma clang diagnostic ignored "-Wold-style-cast" 868 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID, 869#pragma clang diagnostic pop 870 .pNext = nullptr, 871 .usage = swapchain_image_usage, 872 }; 873 VkNativeBufferANDROID image_native_buffer = { 874#pragma clang diagnostic push 875#pragma clang diagnostic ignored "-Wold-style-cast" 876 .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID, 877#pragma clang diagnostic pop 878 .pNext = &swapchain_image_create, 879 }; 880 VkImageCreateInfo image_create = { 881 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 882 .pNext = &image_native_buffer, 883 .imageType = VK_IMAGE_TYPE_2D, 884 .format = create_info->imageFormat, 885 .extent = {0, 0, 1}, 886 .mipLevels = 1, 887 .arrayLayers = 1, 888 .samples = VK_SAMPLE_COUNT_1_BIT, 889 .tiling = VK_IMAGE_TILING_OPTIMAL, 890 .usage = create_info->imageUsage, 891 .flags = 0, 892 .sharingMode = create_info->imageSharingMode, 893 .queueFamilyIndexCount = create_info->queueFamilyIndexCount, 894 .pQueueFamilyIndices = create_info->pQueueFamilyIndices, 895 }; 896 897 for (uint32_t i = 0; i < num_images; i++) { 898 Swapchain::Image& img = swapchain->images[i]; 899 900 ANativeWindowBuffer* buffer; 901 err = surface.window->dequeueBuffer(surface.window.get(), &buffer, 902 &img.dequeue_fence); 903 if (err != 0) { 904 // TODO(jessehall): Improve error reporting. Can we enumerate 905 // possible errors and translate them to valid Vulkan result codes? 906 ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); 907 result = VK_ERROR_INITIALIZATION_FAILED; 908 break; 909 } 910 img.buffer = buffer; 911 img.dequeued = true; 912 913 image_create.extent = 914 VkExtent3D{static_cast<uint32_t>(img.buffer->width), 915 static_cast<uint32_t>(img.buffer->height), 916 1}; 917 image_native_buffer.handle = img.buffer->handle; 918 image_native_buffer.stride = img.buffer->stride; 919 image_native_buffer.format = img.buffer->format; 920 image_native_buffer.usage = img.buffer->usage; 921 922 result = 923 dispatch.CreateImage(device, &image_create, nullptr, &img.image); 924 if (result != VK_SUCCESS) { 925 ALOGD("vkCreateImage w/ native buffer failed: %u", result); 926 break; 927 } 928 } 929 930 // -- Cancel all buffers, returning them to the queue -- 931 // If an error occurred before, also destroy the VkImage and release the 932 // buffer reference. Otherwise, we retain a strong reference to the buffer. 933 // 934 // TODO(jessehall): The error path here is the same as DestroySwapchain, 935 // but not the non-error path. Should refactor/unify. 936 for (uint32_t i = 0; i < num_images; i++) { 937 Swapchain::Image& img = swapchain->images[i]; 938 if (img.dequeued) { 939 surface.window->cancelBuffer(surface.window.get(), img.buffer.get(), 940 img.dequeue_fence); 941 img.dequeue_fence = -1; 942 img.dequeued = false; 943 } 944 if (result != VK_SUCCESS) { 945 if (img.image) 946 dispatch.DestroyImage(device, img.image, nullptr); 947 } 948 } 949 950 if (result != VK_SUCCESS) { 951 swapchain->~Swapchain(); 952 allocator->pfnFree(allocator->pUserData, swapchain); 953 return result; 954 } 955 956 surface.swapchain_handle = HandleFromSwapchain(swapchain); 957 *swapchain_handle = surface.swapchain_handle; 958 return VK_SUCCESS; 959} 960 961VKAPI_ATTR 962void DestroySwapchainKHR(VkDevice device, 963 VkSwapchainKHR swapchain_handle, 964 const VkAllocationCallbacks* allocator) { 965 const auto& dispatch = GetData(device).driver; 966 Swapchain* swapchain = SwapchainFromHandle(swapchain_handle); 967 if (!swapchain) 968 return; 969 bool active = swapchain->surface.swapchain_handle == swapchain_handle; 970 ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr; 971 972 if (swapchain->frame_timestamps_enabled) { 973 native_window_enable_frame_timestamps(window, false); 974 } 975 for (uint32_t i = 0; i < swapchain->num_images; i++) 976 ReleaseSwapchainImage(device, window, -1, swapchain->images[i]); 977 if (active) 978 swapchain->surface.swapchain_handle = VK_NULL_HANDLE; 979 if (!allocator) 980 allocator = &GetData(device).allocator; 981 swapchain->~Swapchain(); 982 allocator->pfnFree(allocator->pUserData, swapchain); 983} 984 985VKAPI_ATTR 986VkResult GetSwapchainImagesKHR(VkDevice, 987 VkSwapchainKHR swapchain_handle, 988 uint32_t* count, 989 VkImage* images) { 990 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); 991 ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle, 992 "getting images for non-active swapchain 0x%" PRIx64 993 "; only dequeued image handles are valid", 994 reinterpret_cast<uint64_t>(swapchain_handle)); 995 VkResult result = VK_SUCCESS; 996 if (images) { 997 uint32_t n = swapchain.num_images; 998 if (*count < swapchain.num_images) { 999 n = *count; 1000 result = VK_INCOMPLETE; 1001 } 1002 for (uint32_t i = 0; i < n; i++) 1003 images[i] = swapchain.images[i].image; 1004 *count = n; 1005 } else { 1006 *count = swapchain.num_images; 1007 } 1008 return result; 1009} 1010 1011VKAPI_ATTR 1012VkResult AcquireNextImageKHR(VkDevice device, 1013 VkSwapchainKHR swapchain_handle, 1014 uint64_t timeout, 1015 VkSemaphore semaphore, 1016 VkFence vk_fence, 1017 uint32_t* image_index) { 1018 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); 1019 ANativeWindow* window = swapchain.surface.window.get(); 1020 VkResult result; 1021 int err; 1022 1023 if (swapchain.surface.swapchain_handle != swapchain_handle) 1024 return VK_ERROR_OUT_OF_DATE_KHR; 1025 1026 ALOGW_IF( 1027 timeout != UINT64_MAX, 1028 "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented"); 1029 1030 ANativeWindowBuffer* buffer; 1031 int fence_fd; 1032 err = window->dequeueBuffer(window, &buffer, &fence_fd); 1033 if (err != 0) { 1034 // TODO(jessehall): Improve error reporting. Can we enumerate possible 1035 // errors and translate them to valid Vulkan result codes? 1036 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); 1037 return VK_ERROR_INITIALIZATION_FAILED; 1038 } 1039 1040 uint32_t idx; 1041 for (idx = 0; idx < swapchain.num_images; idx++) { 1042 if (swapchain.images[idx].buffer.get() == buffer) { 1043 swapchain.images[idx].dequeued = true; 1044 swapchain.images[idx].dequeue_fence = fence_fd; 1045 break; 1046 } 1047 } 1048 if (idx == swapchain.num_images) { 1049 ALOGE("dequeueBuffer returned unrecognized buffer"); 1050 window->cancelBuffer(window, buffer, fence_fd); 1051 return VK_ERROR_OUT_OF_DATE_KHR; 1052 } 1053 1054 int fence_clone = -1; 1055 if (fence_fd != -1) { 1056 fence_clone = dup(fence_fd); 1057 if (fence_clone == -1) { 1058 ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", 1059 strerror(errno), errno); 1060 sync_wait(fence_fd, -1 /* forever */); 1061 } 1062 } 1063 1064 result = GetData(device).driver.AcquireImageANDROID( 1065 device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence); 1066 if (result != VK_SUCCESS) { 1067 // NOTE: we're relying on AcquireImageANDROID to close fence_clone, 1068 // even if the call fails. We could close it ourselves on failure, but 1069 // that would create a race condition if the driver closes it on a 1070 // failure path: some other thread might create an fd with the same 1071 // number between the time the driver closes it and the time we close 1072 // it. We must assume one of: the driver *always* closes it even on 1073 // failure, or *never* closes it on failure. 1074 window->cancelBuffer(window, buffer, fence_fd); 1075 swapchain.images[idx].dequeued = false; 1076 swapchain.images[idx].dequeue_fence = -1; 1077 return result; 1078 } 1079 1080 *image_index = idx; 1081 return VK_SUCCESS; 1082} 1083 1084static VkResult WorstPresentResult(VkResult a, VkResult b) { 1085 // See the error ranking for vkQueuePresentKHR at the end of section 29.6 1086 // (in spec version 1.0.14). 1087 static const VkResult kWorstToBest[] = { 1088 VK_ERROR_DEVICE_LOST, 1089 VK_ERROR_SURFACE_LOST_KHR, 1090 VK_ERROR_OUT_OF_DATE_KHR, 1091 VK_ERROR_OUT_OF_DEVICE_MEMORY, 1092 VK_ERROR_OUT_OF_HOST_MEMORY, 1093 VK_SUBOPTIMAL_KHR, 1094 }; 1095 for (auto result : kWorstToBest) { 1096 if (a == result || b == result) 1097 return result; 1098 } 1099 ALOG_ASSERT(a == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", a); 1100 ALOG_ASSERT(b == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", b); 1101 return a != VK_SUCCESS ? a : b; 1102} 1103 1104VKAPI_ATTR 1105VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { 1106 ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 1107 "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d", 1108 present_info->sType); 1109 1110 VkDevice device = GetData(queue).driver_device; 1111 const auto& dispatch = GetData(queue).driver; 1112 VkResult final_result = VK_SUCCESS; 1113 1114 // Look at the pNext chain for supported extension structs: 1115 const VkPresentRegionsKHR* present_regions = nullptr; 1116 const VkPresentTimesInfoGOOGLE* present_times = nullptr; 1117 const VkPresentRegionsKHR* next = 1118 reinterpret_cast<const VkPresentRegionsKHR*>(present_info->pNext); 1119 while (next) { 1120 switch (next->sType) { 1121 case VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR: 1122 present_regions = next; 1123 break; 1124 case VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE: 1125 present_times = 1126 reinterpret_cast<const VkPresentTimesInfoGOOGLE*>(next); 1127 break; 1128 default: 1129 ALOGV("QueuePresentKHR ignoring unrecognized pNext->sType = %x", 1130 next->sType); 1131 break; 1132 } 1133 next = reinterpret_cast<const VkPresentRegionsKHR*>(next->pNext); 1134 } 1135 ALOGV_IF( 1136 present_regions && 1137 present_regions->swapchainCount != present_info->swapchainCount, 1138 "VkPresentRegions::swapchainCount != VkPresentInfo::swapchainCount"); 1139 ALOGV_IF(present_times && 1140 present_times->swapchainCount != present_info->swapchainCount, 1141 "VkPresentTimesInfoGOOGLE::swapchainCount != " 1142 "VkPresentInfo::swapchainCount"); 1143 const VkPresentRegionKHR* regions = 1144 (present_regions) ? present_regions->pRegions : nullptr; 1145 const VkPresentTimeGOOGLE* times = 1146 (present_times) ? present_times->pTimes : nullptr; 1147 const VkAllocationCallbacks* allocator = &GetData(device).allocator; 1148 android_native_rect_t* rects = nullptr; 1149 uint32_t nrects = 0; 1150 1151 for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) { 1152 Swapchain& swapchain = 1153 *SwapchainFromHandle(present_info->pSwapchains[sc]); 1154 uint32_t image_idx = present_info->pImageIndices[sc]; 1155 Swapchain::Image& img = swapchain.images[image_idx]; 1156 const VkPresentRegionKHR* region = (regions) ? ®ions[sc] : nullptr; 1157 const VkPresentTimeGOOGLE* time = (times) ? ×[sc] : nullptr; 1158 VkResult swapchain_result = VK_SUCCESS; 1159 VkResult result; 1160 int err; 1161 1162 int fence = -1; 1163 result = dispatch.QueueSignalReleaseImageANDROID( 1164 queue, present_info->waitSemaphoreCount, 1165 present_info->pWaitSemaphores, img.image, &fence); 1166 if (result != VK_SUCCESS) { 1167 ALOGE("QueueSignalReleaseImageANDROID failed: %d", result); 1168 swapchain_result = result; 1169 } 1170 1171 if (swapchain.surface.swapchain_handle == 1172 present_info->pSwapchains[sc]) { 1173 ANativeWindow* window = swapchain.surface.window.get(); 1174 if (swapchain_result == VK_SUCCESS) { 1175 if (region) { 1176 // Process the incremental-present hint for this swapchain: 1177 uint32_t rcount = region->rectangleCount; 1178 if (rcount > nrects) { 1179 android_native_rect_t* new_rects = 1180 static_cast<android_native_rect_t*>( 1181 allocator->pfnReallocation( 1182 allocator->pUserData, rects, 1183 sizeof(android_native_rect_t) * rcount, 1184 alignof(android_native_rect_t), 1185 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); 1186 if (new_rects) { 1187 rects = new_rects; 1188 nrects = rcount; 1189 } else { 1190 rcount = 0; // Ignore the hint for this swapchain 1191 } 1192 } 1193 for (uint32_t r = 0; r < rcount; ++r) { 1194 if (region->pRectangles[r].layer > 0) { 1195 ALOGV( 1196 "vkQueuePresentKHR ignoring invalid layer " 1197 "(%u); using layer 0 instead", 1198 region->pRectangles[r].layer); 1199 } 1200 int x = region->pRectangles[r].offset.x; 1201 int y = region->pRectangles[r].offset.y; 1202 int width = static_cast<int>( 1203 region->pRectangles[r].extent.width); 1204 int height = static_cast<int>( 1205 region->pRectangles[r].extent.height); 1206 android_native_rect_t* cur_rect = &rects[r]; 1207 cur_rect->left = x; 1208 cur_rect->top = y + height; 1209 cur_rect->right = x + width; 1210 cur_rect->bottom = y; 1211 } 1212 native_window_set_surface_damage(window, rects, rcount); 1213 } 1214 if (time) { 1215 if (!swapchain.frame_timestamps_enabled) { 1216 ALOGV( 1217 "Calling " 1218 "native_window_enable_frame_timestamps(true)"); 1219 native_window_enable_frame_timestamps(window, true); 1220 swapchain.frame_timestamps_enabled = true; 1221 } 1222 // Record this presentID and desiredPresentTime so it can 1223 // be later correlated to this present. 1224 TimingInfo timing_record(time); 1225 swapchain.timing.add(timing_record); 1226 uint32_t num_timings = 1227 static_cast<uint32_t>(swapchain.timing.size()); 1228 if (num_timings > MAX_TIMING_INFOS) { 1229 swapchain.timing.removeAt(0); 1230 } 1231 if (time->desiredPresentTime) { 1232 // Set the desiredPresentTime: 1233 ALOGV( 1234 "Calling " 1235 "native_window_set_buffers_timestamp(%" PRId64 ")", 1236 time->desiredPresentTime); 1237 native_window_set_buffers_timestamp( 1238 window, 1239 static_cast<int64_t>(time->desiredPresentTime)); 1240 } 1241 } 1242 err = window->queueBuffer(window, img.buffer.get(), fence); 1243 // queueBuffer always closes fence, even on error 1244 if (err != 0) { 1245 // TODO(jessehall): What now? We should probably cancel the 1246 // buffer, I guess? 1247 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err); 1248 swapchain_result = WorstPresentResult( 1249 swapchain_result, VK_ERROR_OUT_OF_DATE_KHR); 1250 } 1251 if (img.dequeue_fence >= 0) { 1252 close(img.dequeue_fence); 1253 img.dequeue_fence = -1; 1254 } 1255 img.dequeued = false; 1256 } 1257 if (swapchain_result != VK_SUCCESS) { 1258 ReleaseSwapchainImage(device, window, fence, img); 1259 OrphanSwapchain(device, &swapchain); 1260 } 1261 } else { 1262 ReleaseSwapchainImage(device, nullptr, fence, img); 1263 swapchain_result = VK_ERROR_OUT_OF_DATE_KHR; 1264 } 1265 1266 if (present_info->pResults) 1267 present_info->pResults[sc] = swapchain_result; 1268 1269 if (swapchain_result != final_result) 1270 final_result = WorstPresentResult(final_result, swapchain_result); 1271 } 1272 if (rects) { 1273 allocator->pfnFree(allocator->pUserData, rects); 1274 } 1275 1276 return final_result; 1277} 1278 1279VKAPI_ATTR 1280VkResult GetRefreshCycleDurationGOOGLE( 1281 VkDevice, 1282 VkSwapchainKHR swapchain_handle, 1283 VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) { 1284 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); 1285 VkResult result = VK_SUCCESS; 1286 1287 pDisplayTimingProperties->refreshDuration = swapchain.refresh_duration; 1288 1289 return result; 1290} 1291 1292VKAPI_ATTR 1293VkResult GetPastPresentationTimingGOOGLE( 1294 VkDevice, 1295 VkSwapchainKHR swapchain_handle, 1296 uint32_t* count, 1297 VkPastPresentationTimingGOOGLE* timings) { 1298 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); 1299 ANativeWindow* window = swapchain.surface.window.get(); 1300 VkResult result = VK_SUCCESS; 1301 1302 if (!swapchain.frame_timestamps_enabled) { 1303 ALOGV("Calling native_window_enable_frame_timestamps(true)"); 1304 native_window_enable_frame_timestamps(window, true); 1305 swapchain.frame_timestamps_enabled = true; 1306 } 1307 1308 if (timings) { 1309 // TODO(ianelliott): plumb return value (e.g. VK_INCOMPLETE) 1310 copy_ready_timings(swapchain, count, timings); 1311 } else { 1312 *count = get_num_ready_timings(swapchain); 1313 } 1314 1315 return result; 1316} 1317 1318VKAPI_ATTR 1319VkResult GetSwapchainStatusKHR( 1320 VkDevice, 1321 VkSwapchainKHR swapchain_handle) { 1322 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); 1323 VkResult result = VK_SUCCESS; 1324 1325 if (swapchain.surface.swapchain_handle != swapchain_handle) { 1326 return VK_ERROR_OUT_OF_DATE_KHR; 1327 } 1328 1329 // TODO(chrisforbes): Implement this function properly 1330 1331 return result; 1332} 1333 1334} // namespace driver 1335} // namespace vulkan 1336