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