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