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 <gui/BufferQueue.h> 20 #include <log/log.h> 21 #include <sync/sync.h> 22 #include <utils/StrongPointer.h> 23 24 #include "driver.h" 25 26 // TODO(jessehall): Currently we don't have a good error code for when a native 27 // window operation fails. Just returning INITIALIZATION_FAILED for now. Later 28 // versions (post SDK 0.9) of the API/extension have a better error code. 29 // When updating to that version, audit all error returns. 30 namespace vulkan { 31 namespace driver { 32 33 namespace { 34 35 const VkSurfaceTransformFlagsKHR kSupportedTransforms = 36 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR | 37 VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | 38 VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | 39 VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR | 40 // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. 41 // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR | 42 // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | 43 // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR | 44 // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR | 45 VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; 46 47 VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) { 48 // Native and Vulkan transforms are isomorphic, but are represented 49 // differently. Vulkan transforms are built up of an optional horizontal 50 // mirror, followed by a clockwise 0/90/180/270-degree rotation. Native 51 // transforms are built up from a horizontal flip, vertical flip, and 52 // 90-degree rotation, all optional but always in that order. 53 54 // TODO(jessehall): For now, only support pure rotations, not 55 // flip or flip-and-rotate, until I have more time to test them and build 56 // sample code. As far as I know we never actually use anything besides 57 // pure rotations anyway. 58 59 switch (native) { 60 case 0: // 0x0 61 return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 62 // case NATIVE_WINDOW_TRANSFORM_FLIP_H: // 0x1 63 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR; 64 // case NATIVE_WINDOW_TRANSFORM_FLIP_V: // 0x2 65 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR; 66 case NATIVE_WINDOW_TRANSFORM_ROT_180: // FLIP_H | FLIP_V 67 return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; 68 case NATIVE_WINDOW_TRANSFORM_ROT_90: // 0x4 69 return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; 70 // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90: 71 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR; 72 // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90: 73 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR; 74 case NATIVE_WINDOW_TRANSFORM_ROT_270: // FLIP_H | FLIP_V | ROT_90 75 return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; 76 case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY: 77 default: 78 return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 79 } 80 } 81 82 int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { 83 switch (transform) { 84 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: 85 return NATIVE_WINDOW_TRANSFORM_ROT_270; 86 case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: 87 return NATIVE_WINDOW_TRANSFORM_ROT_180; 88 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: 89 return NATIVE_WINDOW_TRANSFORM_ROT_90; 90 // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. 91 // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: 92 // return NATIVE_WINDOW_TRANSFORM_FLIP_H; 93 // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: 94 // return NATIVE_WINDOW_TRANSFORM_FLIP_H | 95 // NATIVE_WINDOW_TRANSFORM_ROT_90; 96 // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: 97 // return NATIVE_WINDOW_TRANSFORM_FLIP_V; 98 // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: 99 // return NATIVE_WINDOW_TRANSFORM_FLIP_V | 100 // NATIVE_WINDOW_TRANSFORM_ROT_90; 101 case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: 102 case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: 103 default: 104 return 0; 105 } 106 } 107 108 // ---------------------------------------------------------------------------- 109 110 struct Surface { 111 android::sp<ANativeWindow> window; 112 VkSwapchainKHR swapchain_handle; 113 }; 114 115 VkSurfaceKHR HandleFromSurface(Surface* surface) { 116 return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface)); 117 } 118 119 Surface* SurfaceFromHandle(VkSurfaceKHR handle) { 120 return reinterpret_cast<Surface*>(handle); 121 } 122 123 struct Swapchain { 124 Swapchain(Surface& surface_, uint32_t num_images_) 125 : surface(surface_), num_images(num_images_) {} 126 127 Surface& surface; 128 uint32_t num_images; 129 130 struct Image { 131 Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {} 132 VkImage image; 133 android::sp<ANativeWindowBuffer> buffer; 134 // The fence is only valid when the buffer is dequeued, and should be 135 // -1 any other time. When valid, we own the fd, and must ensure it is 136 // closed: either by closing it explicitly when queueing the buffer, 137 // or by passing ownership e.g. to ANativeWindow::cancelBuffer(). 138 int dequeue_fence; 139 bool dequeued; 140 } images[android::BufferQueue::NUM_BUFFER_SLOTS]; 141 }; 142 143 VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) { 144 return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain)); 145 } 146 147 Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) { 148 return reinterpret_cast<Swapchain*>(handle); 149 } 150 151 void ReleaseSwapchainImage(VkDevice device, 152 ANativeWindow* window, 153 int release_fence, 154 Swapchain::Image& image) { 155 ALOG_ASSERT(release_fence == -1 || image.dequeued, 156 "ReleaseSwapchainImage: can't provide a release fence for " 157 "non-dequeued images"); 158 159 if (image.dequeued) { 160 if (release_fence >= 0) { 161 // We get here from vkQueuePresentKHR. The application is 162 // responsible for creating an execution dependency chain from 163 // vkAcquireNextImage (dequeue_fence) to vkQueuePresentKHR 164 // (release_fence), so we can drop the dequeue_fence here. 165 if (image.dequeue_fence >= 0) 166 close(image.dequeue_fence); 167 } else { 168 // We get here during swapchain destruction, or various serious 169 // error cases e.g. when we can't create the release_fence during 170 // vkQueuePresentKHR. In non-error cases, the dequeue_fence should 171 // have already signalled, since the swapchain images are supposed 172 // to be idle before the swapchain is destroyed. In error cases, 173 // there may be rendering in flight to the image, but since we 174 // weren't able to create a release_fence, waiting for the 175 // dequeue_fence is about the best we can do. 176 release_fence = image.dequeue_fence; 177 } 178 image.dequeue_fence = -1; 179 180 if (window) { 181 window->cancelBuffer(window, image.buffer.get(), release_fence); 182 } else { 183 if (release_fence >= 0) { 184 sync_wait(release_fence, -1 /* forever */); 185 close(release_fence); 186 } 187 } 188 189 image.dequeued = false; 190 } 191 192 if (image.image) { 193 GetData(device).driver.DestroyImage(device, image.image, nullptr); 194 image.image = VK_NULL_HANDLE; 195 } 196 197 image.buffer.clear(); 198 } 199 200 void OrphanSwapchain(VkDevice device, Swapchain* swapchain) { 201 if (swapchain->surface.swapchain_handle != HandleFromSwapchain(swapchain)) 202 return; 203 for (uint32_t i = 0; i < swapchain->num_images; i++) { 204 if (!swapchain->images[i].dequeued) 205 ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]); 206 } 207 swapchain->surface.swapchain_handle = VK_NULL_HANDLE; 208 } 209 210 } // anonymous namespace 211 212 VKAPI_ATTR 213 VkResult CreateAndroidSurfaceKHR( 214 VkInstance instance, 215 const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, 216 const VkAllocationCallbacks* allocator, 217 VkSurfaceKHR* out_surface) { 218 if (!allocator) 219 allocator = &GetData(instance).allocator; 220 void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface), 221 alignof(Surface), 222 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 223 if (!mem) 224 return VK_ERROR_OUT_OF_HOST_MEMORY; 225 Surface* surface = new (mem) Surface; 226 227 surface->window = pCreateInfo->window; 228 surface->swapchain_handle = VK_NULL_HANDLE; 229 230 // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN. 231 int err = 232 native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL); 233 if (err != 0) { 234 // TODO(jessehall): Improve error reporting. Can we enumerate possible 235 // errors and translate them to valid Vulkan result codes? 236 ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err), 237 err); 238 surface->~Surface(); 239 allocator->pfnFree(allocator->pUserData, surface); 240 return VK_ERROR_INITIALIZATION_FAILED; 241 } 242 243 *out_surface = HandleFromSurface(surface); 244 return VK_SUCCESS; 245 } 246 247 VKAPI_ATTR 248 void DestroySurfaceKHR(VkInstance instance, 249 VkSurfaceKHR surface_handle, 250 const VkAllocationCallbacks* allocator) { 251 Surface* surface = SurfaceFromHandle(surface_handle); 252 if (!surface) 253 return; 254 native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL); 255 ALOGV_IF(surface->swapchain_handle != VK_NULL_HANDLE, 256 "destroyed VkSurfaceKHR 0x%" PRIx64 257 " has active VkSwapchainKHR 0x%" PRIx64, 258 reinterpret_cast<uint64_t>(surface_handle), 259 reinterpret_cast<uint64_t>(surface->swapchain_handle)); 260 surface->~Surface(); 261 if (!allocator) 262 allocator = &GetData(instance).allocator; 263 allocator->pfnFree(allocator->pUserData, surface); 264 } 265 266 VKAPI_ATTR 267 VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/, 268 uint32_t /*queue_family*/, 269 VkSurfaceKHR /*surface*/, 270 VkBool32* supported) { 271 *supported = VK_TRUE; 272 return VK_SUCCESS; 273 } 274 275 VKAPI_ATTR 276 VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( 277 VkPhysicalDevice /*pdev*/, 278 VkSurfaceKHR surface, 279 VkSurfaceCapabilitiesKHR* capabilities) { 280 int err; 281 ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); 282 283 int width, height; 284 err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); 285 if (err != 0) { 286 ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", 287 strerror(-err), err); 288 return VK_ERROR_INITIALIZATION_FAILED; 289 } 290 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); 291 if (err != 0) { 292 ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", 293 strerror(-err), err); 294 return VK_ERROR_INITIALIZATION_FAILED; 295 } 296 297 int transform_hint; 298 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint); 299 if (err != 0) { 300 ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", 301 strerror(-err), err); 302 return VK_ERROR_INITIALIZATION_FAILED; 303 } 304 305 // TODO(jessehall): Figure out what the min/max values should be. 306 capabilities->minImageCount = 2; 307 capabilities->maxImageCount = 3; 308 309 capabilities->currentExtent = 310 VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)}; 311 312 // TODO(jessehall): Figure out what the max extent should be. Maximum 313 // texture dimension maybe? 314 capabilities->minImageExtent = VkExtent2D{1, 1}; 315 capabilities->maxImageExtent = VkExtent2D{4096, 4096}; 316 317 capabilities->maxImageArrayLayers = 1; 318 319 capabilities->supportedTransforms = kSupportedTransforms; 320 capabilities->currentTransform = 321 TranslateNativeToVulkanTransform(transform_hint); 322 323 // On Android, window composition is a WindowManager property, not something 324 // associated with the bufferqueue. It can't be changed from here. 325 capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; 326 327 // TODO(jessehall): I think these are right, but haven't thought hard about 328 // it. Do we need to query the driver for support of any of these? 329 // Currently not included: 330 // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable? 331 // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not 332 // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not 333 capabilities->supportedUsageFlags = 334 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | 335 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | 336 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 337 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; 338 339 return VK_SUCCESS; 340 } 341 342 VKAPI_ATTR 343 VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/, 344 VkSurfaceKHR /*surface*/, 345 uint32_t* count, 346 VkSurfaceFormatKHR* formats) { 347 // TODO(jessehall): Fill out the set of supported formats. Longer term, add 348 // a new gralloc method to query whether a (format, usage) pair is 349 // supported, and check that for each gralloc format that corresponds to a 350 // Vulkan format. Shorter term, just add a few more formats to the ones 351 // hardcoded below. 352 353 const VkSurfaceFormatKHR kFormats[] = { 354 {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, 355 {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, 356 {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, 357 }; 358 const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); 359 360 VkResult result = VK_SUCCESS; 361 if (formats) { 362 if (*count < kNumFormats) 363 result = VK_INCOMPLETE; 364 std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats); 365 } 366 *count = kNumFormats; 367 return result; 368 } 369 370 VKAPI_ATTR 371 VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/, 372 VkSurfaceKHR /*surface*/, 373 uint32_t* count, 374 VkPresentModeKHR* modes) { 375 const VkPresentModeKHR kModes[] = { 376 VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR, 377 }; 378 const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]); 379 380 VkResult result = VK_SUCCESS; 381 if (modes) { 382 if (*count < kNumModes) 383 result = VK_INCOMPLETE; 384 std::copy(kModes, kModes + std::min(*count, kNumModes), modes); 385 } 386 *count = kNumModes; 387 return result; 388 } 389 390 VKAPI_ATTR 391 VkResult CreateSwapchainKHR(VkDevice device, 392 const VkSwapchainCreateInfoKHR* create_info, 393 const VkAllocationCallbacks* allocator, 394 VkSwapchainKHR* swapchain_handle) { 395 int err; 396 VkResult result = VK_SUCCESS; 397 398 ALOGV("vkCreateSwapchainKHR: surface=0x%" PRIx64 399 " minImageCount=%u imageFormat=%u imageColorSpace=%u" 400 " imageExtent=%ux%u imageUsage=%#x preTransform=%u presentMode=%u" 401 " oldSwapchain=0x%" PRIx64, 402 reinterpret_cast<uint64_t>(create_info->surface), 403 create_info->minImageCount, create_info->imageFormat, 404 create_info->imageColorSpace, create_info->imageExtent.width, 405 create_info->imageExtent.height, create_info->imageUsage, 406 create_info->preTransform, create_info->presentMode, 407 reinterpret_cast<uint64_t>(create_info->oldSwapchain)); 408 409 if (!allocator) 410 allocator = &GetData(device).allocator; 411 412 ALOGV_IF(create_info->imageArrayLayers != 1, 413 "swapchain imageArrayLayers=%u not supported", 414 create_info->imageArrayLayers); 415 ALOGV_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, 416 "swapchain imageColorSpace=%u not supported", 417 create_info->imageColorSpace); 418 ALOGV_IF((create_info->preTransform & ~kSupportedTransforms) != 0, 419 "swapchain preTransform=%#x not supported", 420 create_info->preTransform); 421 ALOGV_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR || 422 create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR), 423 "swapchain presentMode=%u not supported", 424 create_info->presentMode); 425 426 Surface& surface = *SurfaceFromHandle(create_info->surface); 427 428 if (surface.swapchain_handle != create_info->oldSwapchain) { 429 ALOGV("Can't create a swapchain for VkSurfaceKHR 0x%" PRIx64 430 " because it already has active swapchain 0x%" PRIx64 431 " but VkSwapchainCreateInfo::oldSwapchain=0x%" PRIx64, 432 reinterpret_cast<uint64_t>(create_info->surface), 433 reinterpret_cast<uint64_t>(surface.swapchain_handle), 434 reinterpret_cast<uint64_t>(create_info->oldSwapchain)); 435 return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; 436 } 437 if (create_info->oldSwapchain != VK_NULL_HANDLE) 438 OrphanSwapchain(device, SwapchainFromHandle(create_info->oldSwapchain)); 439 440 // -- Reset the native window -- 441 // The native window might have been used previously, and had its properties 442 // changed from defaults. That will affect the answer we get for queries 443 // like MIN_UNDEQUED_BUFFERS. Reset to a known/default state before we 444 // attempt such queries. 445 446 // The native window only allows dequeueing all buffers before any have 447 // been queued, since after that point at least one is assumed to be in 448 // non-FREE state at any given time. Disconnecting and re-connecting 449 // orphans the previous buffers, getting us back to the state where we can 450 // dequeue all buffers. 451 err = native_window_api_disconnect(surface.window.get(), 452 NATIVE_WINDOW_API_EGL); 453 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", 454 strerror(-err), err); 455 err = 456 native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL); 457 ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)", 458 strerror(-err), err); 459 460 err = native_window_set_buffer_count(surface.window.get(), 0); 461 if (err != 0) { 462 ALOGE("native_window_set_buffer_count(0) failed: %s (%d)", 463 strerror(-err), err); 464 return VK_ERROR_INITIALIZATION_FAILED; 465 } 466 467 err = surface.window->setSwapInterval(surface.window.get(), 1); 468 if (err != 0) { 469 // TODO(jessehall): Improve error reporting. Can we enumerate possible 470 // errors and translate them to valid Vulkan result codes? 471 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", 472 strerror(-err), err); 473 return VK_ERROR_INITIALIZATION_FAILED; 474 } 475 476 // -- Configure the native window -- 477 478 const auto& dispatch = GetData(device).driver; 479 480 int native_format = HAL_PIXEL_FORMAT_RGBA_8888; 481 switch (create_info->imageFormat) { 482 case VK_FORMAT_R8G8B8A8_UNORM: 483 case VK_FORMAT_R8G8B8A8_SRGB: 484 native_format = HAL_PIXEL_FORMAT_RGBA_8888; 485 break; 486 case VK_FORMAT_R5G6B5_UNORM_PACK16: 487 native_format = HAL_PIXEL_FORMAT_RGB_565; 488 break; 489 default: 490 ALOGV("unsupported swapchain format %d", create_info->imageFormat); 491 break; 492 } 493 err = native_window_set_buffers_format(surface.window.get(), native_format); 494 if (err != 0) { 495 // TODO(jessehall): Improve error reporting. Can we enumerate possible 496 // errors and translate them to valid Vulkan result codes? 497 ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)", 498 native_format, strerror(-err), err); 499 return VK_ERROR_INITIALIZATION_FAILED; 500 } 501 err = native_window_set_buffers_data_space(surface.window.get(), 502 HAL_DATASPACE_SRGB_LINEAR); 503 if (err != 0) { 504 // TODO(jessehall): Improve error reporting. Can we enumerate possible 505 // errors and translate them to valid Vulkan result codes? 506 ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)", 507 HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err); 508 return VK_ERROR_INITIALIZATION_FAILED; 509 } 510 511 err = native_window_set_buffers_dimensions( 512 surface.window.get(), static_cast<int>(create_info->imageExtent.width), 513 static_cast<int>(create_info->imageExtent.height)); 514 if (err != 0) { 515 // TODO(jessehall): Improve error reporting. Can we enumerate possible 516 // errors and translate them to valid Vulkan result codes? 517 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", 518 create_info->imageExtent.width, create_info->imageExtent.height, 519 strerror(-err), err); 520 return VK_ERROR_INITIALIZATION_FAILED; 521 } 522 523 // VkSwapchainCreateInfo::preTransform indicates the transformation the app 524 // applied during rendering. native_window_set_transform() expects the 525 // inverse: the transform the app is requesting that the compositor perform 526 // during composition. With native windows, pre-transform works by rendering 527 // with the same transform the compositor is applying (as in Vulkan), but 528 // then requesting the inverse transform, so that when the compositor does 529 // it's job the two transforms cancel each other out and the compositor ends 530 // up applying an identity transform to the app's buffer. 531 err = native_window_set_buffers_transform( 532 surface.window.get(), 533 InvertTransformToNative(create_info->preTransform)); 534 if (err != 0) { 535 // TODO(jessehall): Improve error reporting. Can we enumerate possible 536 // errors and translate them to valid Vulkan result codes? 537 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", 538 InvertTransformToNative(create_info->preTransform), 539 strerror(-err), err); 540 return VK_ERROR_INITIALIZATION_FAILED; 541 } 542 543 err = native_window_set_scaling_mode( 544 surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); 545 if (err != 0) { 546 // TODO(jessehall): Improve error reporting. Can we enumerate possible 547 // errors and translate them to valid Vulkan result codes? 548 ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)", 549 strerror(-err), err); 550 return VK_ERROR_INITIALIZATION_FAILED; 551 } 552 553 int query_value; 554 err = surface.window->query(surface.window.get(), 555 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 556 &query_value); 557 if (err != 0 || query_value < 0) { 558 // TODO(jessehall): Improve error reporting. Can we enumerate possible 559 // errors and translate them to valid Vulkan result codes? 560 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, 561 query_value); 562 return VK_ERROR_INITIALIZATION_FAILED; 563 } 564 uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value); 565 // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using 566 // async mode or not, and assumes not. But in async mode, the BufferQueue 567 // requires an extra undequeued buffer. 568 // See BufferQueueCore::getMinUndequeuedBufferCountLocked(). 569 if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) 570 min_undequeued_buffers += 1; 571 572 uint32_t num_images = 573 (create_info->minImageCount - 1) + min_undequeued_buffers; 574 err = native_window_set_buffer_count(surface.window.get(), num_images); 575 if (err != 0) { 576 // TODO(jessehall): Improve error reporting. Can we enumerate possible 577 // errors and translate them to valid Vulkan result codes? 578 ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images, 579 strerror(-err), err); 580 return VK_ERROR_INITIALIZATION_FAILED; 581 } 582 583 int gralloc_usage = 0; 584 // TODO(jessehall): Remove conditional once all drivers have been updated 585 if (dispatch.GetSwapchainGrallocUsageANDROID) { 586 result = dispatch.GetSwapchainGrallocUsageANDROID( 587 device, create_info->imageFormat, create_info->imageUsage, 588 &gralloc_usage); 589 if (result != VK_SUCCESS) { 590 ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result); 591 return VK_ERROR_INITIALIZATION_FAILED; 592 } 593 } else { 594 gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; 595 } 596 err = native_window_set_usage(surface.window.get(), gralloc_usage); 597 if (err != 0) { 598 // TODO(jessehall): Improve error reporting. Can we enumerate possible 599 // errors and translate them to valid Vulkan result codes? 600 ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err); 601 return VK_ERROR_INITIALIZATION_FAILED; 602 } 603 604 int swap_interval = 605 create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1; 606 err = surface.window->setSwapInterval(surface.window.get(), swap_interval); 607 if (err != 0) { 608 // TODO(jessehall): Improve error reporting. Can we enumerate possible 609 // errors and translate them to valid Vulkan result codes? 610 ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)", 611 swap_interval, strerror(-err), err); 612 return VK_ERROR_INITIALIZATION_FAILED; 613 } 614 615 // -- Allocate our Swapchain object -- 616 // After this point, we must deallocate the swapchain on error. 617 618 void* mem = allocator->pfnAllocation(allocator->pUserData, 619 sizeof(Swapchain), alignof(Swapchain), 620 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 621 if (!mem) 622 return VK_ERROR_OUT_OF_HOST_MEMORY; 623 Swapchain* swapchain = new (mem) Swapchain(surface, num_images); 624 625 // -- Dequeue all buffers and create a VkImage for each -- 626 // Any failures during or after this must cancel the dequeued buffers. 627 628 VkNativeBufferANDROID image_native_buffer = { 629 #pragma clang diagnostic push 630 #pragma clang diagnostic ignored "-Wold-style-cast" 631 .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID, 632 #pragma clang diagnostic pop 633 .pNext = nullptr, 634 }; 635 VkImageCreateInfo image_create = { 636 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 637 .pNext = &image_native_buffer, 638 .imageType = VK_IMAGE_TYPE_2D, 639 .format = create_info->imageFormat, 640 .extent = {0, 0, 1}, 641 .mipLevels = 1, 642 .arrayLayers = 1, 643 .samples = VK_SAMPLE_COUNT_1_BIT, 644 .tiling = VK_IMAGE_TILING_OPTIMAL, 645 .usage = create_info->imageUsage, 646 .flags = 0, 647 .sharingMode = create_info->imageSharingMode, 648 .queueFamilyIndexCount = create_info->queueFamilyIndexCount, 649 .pQueueFamilyIndices = create_info->pQueueFamilyIndices, 650 }; 651 652 for (uint32_t i = 0; i < num_images; i++) { 653 Swapchain::Image& img = swapchain->images[i]; 654 655 ANativeWindowBuffer* buffer; 656 err = surface.window->dequeueBuffer(surface.window.get(), &buffer, 657 &img.dequeue_fence); 658 if (err != 0) { 659 // TODO(jessehall): Improve error reporting. Can we enumerate 660 // possible errors and translate them to valid Vulkan result codes? 661 ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); 662 result = VK_ERROR_INITIALIZATION_FAILED; 663 break; 664 } 665 img.buffer = buffer; 666 img.dequeued = true; 667 668 image_create.extent = 669 VkExtent3D{static_cast<uint32_t>(img.buffer->width), 670 static_cast<uint32_t>(img.buffer->height), 671 1}; 672 image_native_buffer.handle = img.buffer->handle; 673 image_native_buffer.stride = img.buffer->stride; 674 image_native_buffer.format = img.buffer->format; 675 image_native_buffer.usage = img.buffer->usage; 676 677 result = 678 dispatch.CreateImage(device, &image_create, nullptr, &img.image); 679 if (result != VK_SUCCESS) { 680 ALOGD("vkCreateImage w/ native buffer failed: %u", result); 681 break; 682 } 683 } 684 685 // -- Cancel all buffers, returning them to the queue -- 686 // If an error occurred before, also destroy the VkImage and release the 687 // buffer reference. Otherwise, we retain a strong reference to the buffer. 688 // 689 // TODO(jessehall): The error path here is the same as DestroySwapchain, 690 // but not the non-error path. Should refactor/unify. 691 for (uint32_t i = 0; i < num_images; i++) { 692 Swapchain::Image& img = swapchain->images[i]; 693 if (img.dequeued) { 694 surface.window->cancelBuffer(surface.window.get(), img.buffer.get(), 695 img.dequeue_fence); 696 img.dequeue_fence = -1; 697 img.dequeued = false; 698 } 699 if (result != VK_SUCCESS) { 700 if (img.image) 701 dispatch.DestroyImage(device, img.image, nullptr); 702 } 703 } 704 705 if (result != VK_SUCCESS) { 706 swapchain->~Swapchain(); 707 allocator->pfnFree(allocator->pUserData, swapchain); 708 return result; 709 } 710 711 surface.swapchain_handle = HandleFromSwapchain(swapchain); 712 *swapchain_handle = surface.swapchain_handle; 713 return VK_SUCCESS; 714 } 715 716 VKAPI_ATTR 717 void DestroySwapchainKHR(VkDevice device, 718 VkSwapchainKHR swapchain_handle, 719 const VkAllocationCallbacks* allocator) { 720 const auto& dispatch = GetData(device).driver; 721 Swapchain* swapchain = SwapchainFromHandle(swapchain_handle); 722 bool active = swapchain->surface.swapchain_handle == swapchain_handle; 723 ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr; 724 725 for (uint32_t i = 0; i < swapchain->num_images; i++) 726 ReleaseSwapchainImage(device, window, -1, swapchain->images[i]); 727 if (active) 728 swapchain->surface.swapchain_handle = VK_NULL_HANDLE; 729 if (!allocator) 730 allocator = &GetData(device).allocator; 731 swapchain->~Swapchain(); 732 allocator->pfnFree(allocator->pUserData, swapchain); 733 } 734 735 VKAPI_ATTR 736 VkResult GetSwapchainImagesKHR(VkDevice, 737 VkSwapchainKHR swapchain_handle, 738 uint32_t* count, 739 VkImage* images) { 740 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); 741 ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle, 742 "getting images for non-active swapchain 0x%" PRIx64 743 "; only dequeued image handles are valid", 744 reinterpret_cast<uint64_t>(swapchain_handle)); 745 VkResult result = VK_SUCCESS; 746 if (images) { 747 uint32_t n = swapchain.num_images; 748 if (*count < swapchain.num_images) { 749 n = *count; 750 result = VK_INCOMPLETE; 751 } 752 for (uint32_t i = 0; i < n; i++) 753 images[i] = swapchain.images[i].image; 754 } 755 *count = swapchain.num_images; 756 return result; 757 } 758 759 VKAPI_ATTR 760 VkResult AcquireNextImageKHR(VkDevice device, 761 VkSwapchainKHR swapchain_handle, 762 uint64_t timeout, 763 VkSemaphore semaphore, 764 VkFence vk_fence, 765 uint32_t* image_index) { 766 Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); 767 ANativeWindow* window = swapchain.surface.window.get(); 768 VkResult result; 769 int err; 770 771 if (swapchain.surface.swapchain_handle != swapchain_handle) 772 return VK_ERROR_OUT_OF_DATE_KHR; 773 774 ALOGW_IF( 775 timeout != UINT64_MAX, 776 "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented"); 777 778 ANativeWindowBuffer* buffer; 779 int fence_fd; 780 err = window->dequeueBuffer(window, &buffer, &fence_fd); 781 if (err != 0) { 782 // TODO(jessehall): Improve error reporting. Can we enumerate possible 783 // errors and translate them to valid Vulkan result codes? 784 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); 785 return VK_ERROR_INITIALIZATION_FAILED; 786 } 787 788 uint32_t idx; 789 for (idx = 0; idx < swapchain.num_images; idx++) { 790 if (swapchain.images[idx].buffer.get() == buffer) { 791 swapchain.images[idx].dequeued = true; 792 swapchain.images[idx].dequeue_fence = fence_fd; 793 break; 794 } 795 } 796 if (idx == swapchain.num_images) { 797 ALOGE("dequeueBuffer returned unrecognized buffer"); 798 window->cancelBuffer(window, buffer, fence_fd); 799 return VK_ERROR_OUT_OF_DATE_KHR; 800 } 801 802 int fence_clone = -1; 803 if (fence_fd != -1) { 804 fence_clone = dup(fence_fd); 805 if (fence_clone == -1) { 806 ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", 807 strerror(errno), errno); 808 sync_wait(fence_fd, -1 /* forever */); 809 } 810 } 811 812 result = GetData(device).driver.AcquireImageANDROID( 813 device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence); 814 if (result != VK_SUCCESS) { 815 // NOTE: we're relying on AcquireImageANDROID to close fence_clone, 816 // even if the call fails. We could close it ourselves on failure, but 817 // that would create a race condition if the driver closes it on a 818 // failure path: some other thread might create an fd with the same 819 // number between the time the driver closes it and the time we close 820 // it. We must assume one of: the driver *always* closes it even on 821 // failure, or *never* closes it on failure. 822 window->cancelBuffer(window, buffer, fence_fd); 823 swapchain.images[idx].dequeued = false; 824 swapchain.images[idx].dequeue_fence = -1; 825 return result; 826 } 827 828 *image_index = idx; 829 return VK_SUCCESS; 830 } 831 832 static VkResult WorstPresentResult(VkResult a, VkResult b) { 833 // See the error ranking for vkQueuePresentKHR at the end of section 29.6 834 // (in spec version 1.0.14). 835 static const VkResult kWorstToBest[] = { 836 VK_ERROR_DEVICE_LOST, 837 VK_ERROR_SURFACE_LOST_KHR, 838 VK_ERROR_OUT_OF_DATE_KHR, 839 VK_ERROR_OUT_OF_DEVICE_MEMORY, 840 VK_ERROR_OUT_OF_HOST_MEMORY, 841 VK_SUBOPTIMAL_KHR, 842 }; 843 for (auto result : kWorstToBest) { 844 if (a == result || b == result) 845 return result; 846 } 847 ALOG_ASSERT(a == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", a); 848 ALOG_ASSERT(b == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", b); 849 return a != VK_SUCCESS ? a : b; 850 } 851 852 VKAPI_ATTR 853 VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { 854 ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 855 "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d", 856 present_info->sType); 857 ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL"); 858 859 VkDevice device = GetData(queue).driver_device; 860 const auto& dispatch = GetData(queue).driver; 861 VkResult final_result = VK_SUCCESS; 862 863 for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) { 864 Swapchain& swapchain = 865 *SwapchainFromHandle(present_info->pSwapchains[sc]); 866 uint32_t image_idx = present_info->pImageIndices[sc]; 867 Swapchain::Image& img = swapchain.images[image_idx]; 868 VkResult swapchain_result = VK_SUCCESS; 869 VkResult result; 870 int err; 871 872 int fence = -1; 873 result = dispatch.QueueSignalReleaseImageANDROID( 874 queue, present_info->waitSemaphoreCount, 875 present_info->pWaitSemaphores, img.image, &fence); 876 if (result != VK_SUCCESS) { 877 ALOGE("QueueSignalReleaseImageANDROID failed: %d", result); 878 swapchain_result = result; 879 } 880 881 if (swapchain.surface.swapchain_handle == 882 present_info->pSwapchains[sc]) { 883 ANativeWindow* window = swapchain.surface.window.get(); 884 if (swapchain_result == VK_SUCCESS) { 885 err = window->queueBuffer(window, img.buffer.get(), fence); 886 // queueBuffer always closes fence, even on error 887 if (err != 0) { 888 // TODO(jessehall): What now? We should probably cancel the 889 // buffer, I guess? 890 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err); 891 swapchain_result = WorstPresentResult( 892 swapchain_result, VK_ERROR_OUT_OF_DATE_KHR); 893 } 894 if (img.dequeue_fence >= 0) { 895 close(img.dequeue_fence); 896 img.dequeue_fence = -1; 897 } 898 img.dequeued = false; 899 } 900 if (swapchain_result != VK_SUCCESS) { 901 ReleaseSwapchainImage(device, window, fence, img); 902 OrphanSwapchain(device, &swapchain); 903 } 904 } else { 905 ReleaseSwapchainImage(device, nullptr, fence, img); 906 swapchain_result = VK_ERROR_OUT_OF_DATE_KHR; 907 } 908 909 if (present_info->pResults) 910 present_info->pResults[sc] = swapchain_result; 911 912 if (swapchain_result != final_result) 913 final_result = WorstPresentResult(final_result, swapchain_result); 914 } 915 916 return final_result; 917 } 918 919 } // namespace driver 920 } // namespace vulkan 921