1 /* 2 * Copyright (C) 2019 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 "VulkanSurface.h" 18 19 #include <SkSurface.h> 20 #include <algorithm> 21 22 #include "VulkanManager.h" 23 #include "utils/Color.h" 24 #include "utils/TraceUtils.h" 25 26 namespace android { 27 namespace uirenderer { 28 namespace renderthread { 29 30 static bool IsTransformSupported(int transform) { 31 // For now, only support pure rotations, not flip or flip-and-rotate, until we have 32 // more time to test them and build sample code. As far as I know we never actually 33 // use anything besides pure rotations anyway. 34 return transform == 0 || transform == NATIVE_WINDOW_TRANSFORM_ROT_90 || 35 transform == NATIVE_WINDOW_TRANSFORM_ROT_180 || 36 transform == NATIVE_WINDOW_TRANSFORM_ROT_270; 37 } 38 39 static int InvertTransform(int transform) { 40 switch (transform) { 41 case NATIVE_WINDOW_TRANSFORM_ROT_90: 42 return NATIVE_WINDOW_TRANSFORM_ROT_270; 43 case NATIVE_WINDOW_TRANSFORM_ROT_180: 44 return NATIVE_WINDOW_TRANSFORM_ROT_180; 45 case NATIVE_WINDOW_TRANSFORM_ROT_270: 46 return NATIVE_WINDOW_TRANSFORM_ROT_90; 47 default: 48 return 0; 49 } 50 } 51 52 static int ConvertVkTransformToNative(VkSurfaceTransformFlagsKHR transform) { 53 switch (transform) { 54 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: 55 return NATIVE_WINDOW_TRANSFORM_ROT_270; 56 case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: 57 return NATIVE_WINDOW_TRANSFORM_ROT_180; 58 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: 59 return NATIVE_WINDOW_TRANSFORM_ROT_90; 60 case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: 61 case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: 62 default: 63 return 0; 64 } 65 } 66 67 static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) { 68 const int width = windowSize.width(); 69 const int height = windowSize.height(); 70 71 switch (transform) { 72 case 0: 73 return SkMatrix::I(); 74 case NATIVE_WINDOW_TRANSFORM_ROT_90: 75 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1); 76 case NATIVE_WINDOW_TRANSFORM_ROT_180: 77 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1); 78 case NATIVE_WINDOW_TRANSFORM_ROT_270: 79 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1); 80 default: 81 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform); 82 } 83 return SkMatrix::I(); 84 } 85 86 void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize, 87 const SkISize& maxSize) { 88 SkISize& windowSize = windowInfo->size; 89 90 // clamp width & height to handle currentExtent of -1 and protect us from broken hints 91 if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width() || 92 windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) { 93 int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width())); 94 int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height())); 95 ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]", windowSize.width(), 96 windowSize.height(), width, height); 97 windowSize.set(width, height); 98 } 99 100 windowInfo->actualSize = windowSize; 101 if (windowInfo->transform & HAL_TRANSFORM_ROT_90) { 102 windowInfo->actualSize.set(windowSize.height(), windowSize.width()); 103 } 104 105 windowInfo->preTransform = GetPreTransformMatrix(windowInfo->size, windowInfo->transform); 106 } 107 108 static bool ResetNativeWindow(ANativeWindow* window) { 109 // -- Reset the native window -- 110 // The native window might have been used previously, and had its properties 111 // changed from defaults. That will affect the answer we get for queries 112 // like MIN_UNDEQUEUED_BUFFERS. Reset to a known/default state before we 113 // attempt such queries. 114 115 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); 116 if (err != 0) { 117 ALOGW("native_window_api_connect failed: %s (%d)", strerror(-err), err); 118 return false; 119 } 120 121 // this will match what we do on GL so pick that here. 122 err = window->setSwapInterval(window, 1); 123 if (err != 0) { 124 ALOGW("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err); 125 return false; 126 } 127 128 err = native_window_set_shared_buffer_mode(window, false); 129 if (err != 0) { 130 ALOGW("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err); 131 return false; 132 } 133 134 err = native_window_set_auto_refresh(window, false); 135 if (err != 0) { 136 ALOGW("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err); 137 return false; 138 } 139 140 return true; 141 } 142 143 class VkSurfaceAutoDeleter { 144 public: 145 VkSurfaceAutoDeleter(VkInstance instance, VkSurfaceKHR surface, 146 PFN_vkDestroySurfaceKHR destroySurfaceKHR) 147 : mInstance(instance), mSurface(surface), mDestroySurfaceKHR(destroySurfaceKHR) {} 148 ~VkSurfaceAutoDeleter() { destroy(); } 149 150 void destroy() { 151 if (mSurface != VK_NULL_HANDLE) { 152 mDestroySurfaceKHR(mInstance, mSurface, nullptr); 153 mSurface = VK_NULL_HANDLE; 154 } 155 } 156 157 private: 158 VkInstance mInstance; 159 VkSurfaceKHR mSurface; 160 PFN_vkDestroySurfaceKHR mDestroySurfaceKHR; 161 }; 162 163 VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, 164 SkColorType colorType, sk_sp<SkColorSpace> colorSpace, 165 GrContext* grContext, const VulkanManager& vkManager, 166 uint32_t extraBuffers) { 167 VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo; 168 memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR)); 169 surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; 170 surfaceCreateInfo.pNext = nullptr; 171 surfaceCreateInfo.flags = 0; 172 surfaceCreateInfo.window = window; 173 174 VkSurfaceKHR vkSurface = VK_NULL_HANDLE; 175 VkResult res = vkManager.mCreateAndroidSurfaceKHR(vkManager.mInstance, &surfaceCreateInfo, 176 nullptr, &vkSurface); 177 if (VK_SUCCESS != res) { 178 ALOGE("VulkanSurface::Create() vkCreateAndroidSurfaceKHR failed (%d)", res); 179 return nullptr; 180 } 181 182 VkSurfaceAutoDeleter vkSurfaceDeleter(vkManager.mInstance, vkSurface, 183 vkManager.mDestroySurfaceKHR); 184 185 SkDEBUGCODE(VkBool32 supported; res = vkManager.mGetPhysicalDeviceSurfaceSupportKHR( 186 vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex, 187 vkSurface, &supported); 188 // All physical devices and queue families on Android must be capable of 189 // presentation with any native window. 190 SkASSERT(VK_SUCCESS == res && supported);); 191 192 // check for capabilities 193 VkSurfaceCapabilitiesKHR caps; 194 res = vkManager.mGetPhysicalDeviceSurfaceCapabilitiesKHR(vkManager.mPhysicalDevice, vkSurface, 195 &caps); 196 if (VK_SUCCESS != res) { 197 ALOGE("VulkanSurface::Create() vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed (%d)", res); 198 return nullptr; 199 } 200 201 LOG_ALWAYS_FATAL_IF(0 == (caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)); 202 203 /* 204 * We must destroy the VK Surface before attempting to update the window as doing so after 205 * will cause the native window to be modified in unexpected ways. 206 */ 207 vkSurfaceDeleter.destroy(); 208 209 /* 210 * Populate Window Info struct 211 */ 212 WindowInfo windowInfo; 213 214 windowInfo.transform = ConvertVkTransformToNative(caps.supportedTransforms); 215 windowInfo.size = SkISize::Make(caps.currentExtent.width, caps.currentExtent.height); 216 217 const SkISize minSize = SkISize::Make(caps.minImageExtent.width, caps.minImageExtent.height); 218 const SkISize maxSize = SkISize::Make(caps.maxImageExtent.width, caps.maxImageExtent.height); 219 ComputeWindowSizeAndTransform(&windowInfo, minSize, maxSize); 220 221 int query_value; 222 int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); 223 if (err != 0 || query_value < 0) { 224 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value); 225 return nullptr; 226 } 227 auto min_undequeued_buffers = static_cast<uint32_t>(query_value); 228 229 windowInfo.bufferCount = min_undequeued_buffers + 230 std::max(sTargetBufferCount + extraBuffers, caps.minImageCount); 231 if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) { 232 // Application must settle for fewer images than desired: 233 windowInfo.bufferCount = caps.maxImageCount; 234 } 235 236 // Currently Skia requires the images to be color attachments and support all transfer 237 // operations. 238 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 239 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 240 VK_IMAGE_USAGE_TRANSFER_DST_BIT; 241 LOG_ALWAYS_FATAL_IF((caps.supportedUsageFlags & usageFlags) != usageFlags); 242 243 windowInfo.dataspace = HAL_DATASPACE_V0_SRGB; 244 if (colorMode == ColorMode::WideColorGamut) { 245 skcms_Matrix3x3 surfaceGamut; 246 LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut), 247 "Could not get gamut matrix from color space"); 248 if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) { 249 windowInfo.dataspace = HAL_DATASPACE_V0_SCRGB; 250 } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) { 251 windowInfo.dataspace = HAL_DATASPACE_DISPLAY_P3; 252 } else { 253 LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); 254 } 255 } 256 257 windowInfo.pixelFormat = ColorTypeToPixelFormat(colorType); 258 VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM; 259 if (windowInfo.pixelFormat == PIXEL_FORMAT_RGBA_FP16) { 260 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT; 261 } 262 263 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2, 264 "vkGetPhysicalDeviceImageFormatProperties2 is missing"); 265 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo; 266 externalImageFormatInfo.sType = 267 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; 268 externalImageFormatInfo.pNext = nullptr; 269 externalImageFormatInfo.handleType = 270 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; 271 272 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo; 273 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; 274 imageFormatInfo.pNext = &externalImageFormatInfo; 275 imageFormatInfo.format = vkPixelFormat; 276 imageFormatInfo.type = VK_IMAGE_TYPE_2D; 277 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 278 imageFormatInfo.usage = usageFlags; 279 imageFormatInfo.flags = 0; 280 281 VkAndroidHardwareBufferUsageANDROID hwbUsage; 282 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID; 283 hwbUsage.pNext = nullptr; 284 285 VkImageFormatProperties2 imgFormProps; 286 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; 287 imgFormProps.pNext = &hwbUsage; 288 289 res = vkManager.mGetPhysicalDeviceImageFormatProperties2(vkManager.mPhysicalDevice, 290 &imageFormatInfo, &imgFormProps); 291 if (VK_SUCCESS != res) { 292 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2"); 293 return nullptr; 294 } 295 296 uint64_t consumerUsage; 297 native_window_get_consumer_usage(window, &consumerUsage); 298 windowInfo.windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage; 299 300 /* 301 * Now we attempt to modify the window! 302 */ 303 if (!UpdateWindow(window, windowInfo)) { 304 return nullptr; 305 } 306 307 return new VulkanSurface(window, windowInfo, minSize, maxSize, grContext); 308 } 309 310 bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) { 311 ATRACE_CALL(); 312 313 if (!ResetNativeWindow(window)) { 314 return false; 315 } 316 317 // -- Configure the native window -- 318 int err = native_window_set_buffers_format(window, windowInfo.pixelFormat); 319 if (err != 0) { 320 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)", 321 windowInfo.pixelFormat, strerror(-err), err); 322 return false; 323 } 324 325 err = native_window_set_buffers_data_space(window, windowInfo.dataspace); 326 if (err != 0) { 327 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) " 328 "failed: %s (%d)", 329 windowInfo.dataspace, strerror(-err), err); 330 return false; 331 } 332 333 const SkISize& size = windowInfo.actualSize; 334 err = native_window_set_buffers_dimensions(window, size.width(), size.height()); 335 if (err != 0) { 336 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) " 337 "failed: %s (%d)", 338 size.width(), size.height(), strerror(-err), err); 339 return false; 340 } 341 342 // native_window_set_buffers_transform() expects the transform the app is requesting that 343 // the compositor perform during composition. With native windows, pre-transform works by 344 // rendering with the same transform the compositor is applying (as in Vulkan), but 345 // then requesting the inverse transform, so that when the compositor does 346 // it's job the two transforms cancel each other out and the compositor ends 347 // up applying an identity transform to the app's buffer. 348 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform)); 349 if (err != 0) { 350 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) " 351 "failed: %s (%d)", 352 windowInfo.transform, strerror(-err), err); 353 return false; 354 } 355 356 // Vulkan defaults to NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, but this is different than 357 // HWUI's expectation 358 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE); 359 if (err != 0) { 360 ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) " 361 "failed: %s (%d)", 362 strerror(-err), err); 363 return false; 364 } 365 366 err = native_window_set_buffer_count(window, windowInfo.bufferCount); 367 if (err != 0) { 368 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)", 369 windowInfo.bufferCount, strerror(-err), err); 370 return false; 371 } 372 373 err = native_window_set_usage(window, windowInfo.windowUsageFlags); 374 if (err != 0) { 375 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)", 376 strerror(-err), err); 377 return false; 378 } 379 380 return err == 0; 381 } 382 383 VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, 384 SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext) 385 : mNativeWindow(window) 386 , mWindowInfo(windowInfo) 387 , mGrContext(grContext) 388 , mMinWindowSize(minWindowSize) 389 , mMaxWindowSize(maxWindowSize) {} 390 391 VulkanSurface::~VulkanSurface() { 392 releaseBuffers(); 393 394 // release the native window to be available for use by other clients 395 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL); 396 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err); 397 } 398 399 void VulkanSurface::releaseBuffers() { 400 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) { 401 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i]; 402 403 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) { 404 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(), 405 bufferInfo.dequeue_fence); 406 if (err != 0) { 407 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err); 408 } 409 bufferInfo.dequeued = false; 410 411 if (bufferInfo.dequeue_fence >= 0) { 412 close(bufferInfo.dequeue_fence); 413 bufferInfo.dequeue_fence = -1; 414 } 415 } 416 417 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued); 418 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1); 419 420 bufferInfo.skSurface.reset(); 421 bufferInfo.buffer.clear(); 422 bufferInfo.hasValidContents = false; 423 bufferInfo.lastPresentedCount = 0; 424 } 425 } 426 427 VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { 428 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct 429 // value at the end of the function if everything dequeued correctly. 430 mCurrentBufferInfo = nullptr; 431 432 // check if the native window has been resized or rotated and update accordingly 433 SkISize newSize = SkISize::MakeEmpty(); 434 int transformHint = 0; 435 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth); 436 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &newSize.fHeight); 437 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); 438 if (newSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) { 439 WindowInfo newWindowInfo = mWindowInfo; 440 newWindowInfo.size = newSize; 441 newWindowInfo.transform = IsTransformSupported(transformHint) ? transformHint : 0; 442 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize); 443 444 int err = 0; 445 if (newWindowInfo.actualSize != mWindowInfo.actualSize) { 446 // reset the native buffers and update the window 447 err = native_window_set_buffers_dimensions(mNativeWindow.get(), 448 newWindowInfo.actualSize.width(), 449 newWindowInfo.actualSize.height()); 450 if (err != 0) { 451 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", 452 newWindowInfo.actualSize.width(), newWindowInfo.actualSize.height(), 453 strerror(-err), err); 454 return nullptr; 455 } 456 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The 457 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer. 458 releaseBuffers(); 459 // TODO should we ask the nativewindow to allocate buffers? 460 } 461 462 if (newWindowInfo.transform != mWindowInfo.transform) { 463 err = native_window_set_buffers_transform(mNativeWindow.get(), 464 InvertTransform(newWindowInfo.transform)); 465 if (err != 0) { 466 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", 467 newWindowInfo.transform, strerror(-err), err); 468 newWindowInfo.transform = mWindowInfo.transform; 469 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize); 470 } 471 } 472 473 mWindowInfo = newWindowInfo; 474 } 475 476 ANativeWindowBuffer* buffer; 477 int fence_fd; 478 int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd); 479 if (err != 0) { 480 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); 481 return nullptr; 482 } 483 484 uint32_t idx; 485 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) { 486 if (mNativeBuffers[idx].buffer.get() == buffer) { 487 mNativeBuffers[idx].dequeued = true; 488 mNativeBuffers[idx].dequeue_fence = fence_fd; 489 break; 490 } else if (mNativeBuffers[idx].buffer.get() == nullptr) { 491 // increasing the number of buffers we have allocated 492 mNativeBuffers[idx].buffer = buffer; 493 mNativeBuffers[idx].dequeued = true; 494 mNativeBuffers[idx].dequeue_fence = fence_fd; 495 break; 496 } 497 } 498 if (idx == mWindowInfo.bufferCount) { 499 ALOGE("dequeueBuffer returned unrecognized buffer"); 500 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd); 501 return nullptr; 502 } 503 504 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx]; 505 506 if (bufferInfo->skSurface.get() == nullptr) { 507 bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer( 508 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()), 509 kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), nullptr); 510 if (bufferInfo->skSurface.get() == nullptr) { 511 ALOGE("SkSurface::MakeFromAHardwareBuffer failed"); 512 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd); 513 return nullptr; 514 } 515 } 516 517 mCurrentBufferInfo = bufferInfo; 518 return bufferInfo; 519 } 520 521 bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) { 522 if (!dirtyRect.isEmpty()) { 523 524 // native_window_set_surface_damage takes a rectangle in prerotated space 525 // with a bottom-left origin. That is, top > bottom. 526 // The dirtyRect is also in prerotated space, so we just need to switch it to 527 // a bottom-left origin space. 528 529 SkIRect irect; 530 dirtyRect.roundOut(&irect); 531 android_native_rect_t aRect; 532 aRect.left = irect.left(); 533 aRect.top = logicalHeight() - irect.top(); 534 aRect.right = irect.right(); 535 aRect.bottom = logicalHeight() - irect.bottom(); 536 537 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1); 538 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err); 539 } 540 541 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo); 542 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo; 543 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence; 544 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd); 545 546 currentBuffer.dequeued = false; 547 // queueBuffer always closes fence, even on error 548 if (err != 0) { 549 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err); 550 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), 551 currentBuffer.dequeue_fence); 552 } else { 553 currentBuffer.hasValidContents = true; 554 currentBuffer.lastPresentedCount = mPresentCount; 555 mPresentCount++; 556 } 557 558 if (currentBuffer.dequeue_fence >= 0) { 559 close(currentBuffer.dequeue_fence); 560 currentBuffer.dequeue_fence = -1; 561 } 562 563 return err == 0; 564 } 565 566 int VulkanSurface::getCurrentBuffersAge() { 567 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo); 568 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo; 569 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0; 570 } 571 572 } /* namespace renderthread */ 573 } /* namespace uirenderer */ 574 } /* namespace android */ 575