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