blob: 3fed6b09ede2662d30a1d71834c7f1c6560b76a5 [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
John Reckac513c22019-03-28 16:57:38 -0700225 int query_value;
226 int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
227 if (err != 0 || query_value < 0) {
228 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
229 query_value);
230 return nullptr;
231 }
232 auto min_undequeued_buffers = static_cast<uint32_t>(query_value);
233
234 windowInfo.bufferCount = min_undequeued_buffers
235 + std::max(VulkanSurface::sTargetBufferCount, caps.minImageCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500236 if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) {
237 // Application must settle for fewer images than desired:
238 windowInfo.bufferCount = caps.maxImageCount;
239 }
240
241 // Currently Skia requires the images to be color attachments and support all transfer
242 // operations.
243 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
244 VK_IMAGE_USAGE_SAMPLED_BIT |
245 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
246 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
247 LOG_ALWAYS_FATAL_IF((caps.supportedUsageFlags & usageFlags) != usageFlags);
248
249 windowInfo.dataspace = HAL_DATASPACE_V0_SRGB;
250 if (colorMode == ColorMode::WideColorGamut) {
251 skcms_Matrix3x3 surfaceGamut;
252 LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut),
253 "Could not get gamut matrix from color space");
254 if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
255 windowInfo.dataspace = HAL_DATASPACE_V0_SCRGB;
256 } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
257 windowInfo.dataspace = HAL_DATASPACE_DISPLAY_P3;
258 } else {
259 LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
260 }
261 }
262
263 windowInfo.pixelFormat = ColorTypeToPixelFormat(colorType);
264 VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
265 if (windowInfo.pixelFormat == PIXEL_FORMAT_RGBA_FP16) {
266 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
267 }
268
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400269 if (nullptr != vkManager.mGetPhysicalDeviceImageFormatProperties2) {
270 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
271 externalImageFormatInfo.sType =
272 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
273 externalImageFormatInfo.pNext = nullptr;
274 externalImageFormatInfo.handleType =
275 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
276
277 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
278 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
279 imageFormatInfo.pNext = &externalImageFormatInfo;
280 imageFormatInfo.format = vkPixelFormat;
281 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
282 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
283 imageFormatInfo.usage = usageFlags;
284 imageFormatInfo.flags = 0;
285
286 VkAndroidHardwareBufferUsageANDROID hwbUsage;
287 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
288 hwbUsage.pNext = nullptr;
289
290 VkImageFormatProperties2 imgFormProps;
291 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
292 imgFormProps.pNext = &hwbUsage;
293
294 res = vkManager.mGetPhysicalDeviceImageFormatProperties2(vkManager.mPhysicalDevice,
295 &imageFormatInfo, &imgFormProps);
296 if (VK_SUCCESS != res) {
297 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
298 return nullptr;
299 }
300
301 windowInfo.windowUsageFlags = hwbUsage.androidHardwareBufferUsage;
302
303 } else {
304 ALOGE("VulkanSurface::Create() vkmGetPhysicalDeviceImageFormatProperties2 is missing");
305 return nullptr;
306 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500307
308 /*
309 * Now we attempt to modify the window!
310 */
311 if (!UpdateWindow(window, windowInfo)) {
312 return nullptr;
313 }
314
315 return new VulkanSurface(window, windowInfo, minSize, maxSize, grContext);
316}
317
318bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
319 ATRACE_CALL();
320
321 if (!ResetNativeWindow(window)) {
322 return false;
323 }
324
325 // -- Configure the native window --
326 int err = native_window_set_buffers_format(window, windowInfo.pixelFormat);
327 if (err != 0) {
328 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
329 windowInfo.pixelFormat, strerror(-err), err);
330 return false;
331 }
332
333 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
334 if (err != 0) {
335 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
336 "failed: %s (%d)", windowInfo.dataspace, strerror(-err), err);
337 return false;
338 }
339
340 const SkISize& size = windowInfo.actualSize;
341 err = native_window_set_buffers_dimensions(window, size.width(), size.height());
342 if (err != 0) {
343 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) "
344 "failed: %s (%d)", size.width(), size.height(), strerror(-err), err);
345 return false;
346 }
347
348 // native_window_set_buffers_transform() expects the transform the app is requesting that
349 // the compositor perform during composition. With native windows, pre-transform works by
350 // rendering with the same transform the compositor is applying (as in Vulkan), but
351 // then requesting the inverse transform, so that when the compositor does
352 // it's job the two transforms cancel each other out and the compositor ends
353 // up applying an identity transform to the app's buffer.
354 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
355 if (err != 0) {
356 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
357 "failed: %s (%d)", windowInfo.transform, strerror(-err), err);
358 return false;
359 }
360
361 // Vulkan defaults to NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, but this is different than
362 // HWUI's expectation
363 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
364 if (err != 0) {
365 ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) "
366 "failed: %s (%d)", strerror(-err), err);
367 return false;
368 }
369
John Reckac513c22019-03-28 16:57:38 -0700370 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500371 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700372 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500373 windowInfo.bufferCount, strerror(-err), err);
374 return false;
375 }
376
377 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
378 if (err != 0) {
379 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
380 strerror(-err), err);
381 return false;
382 }
383
384 return err == 0;
385}
386
387VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
388 SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
389 : mNativeWindow(window)
390 , mWindowInfo(windowInfo)
391 , mGrContext(grContext)
392 , mMinWindowSize(minWindowSize)
393 , mMaxWindowSize(maxWindowSize) { }
394
395VulkanSurface::~VulkanSurface() {
396 releaseBuffers();
397
398 // release the native window to be available for use by other clients
399 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
400 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
401}
402
403void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700404 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500405 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
406
407 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
408 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
409 bufferInfo.dequeue_fence);
410 if (err != 0) {
411 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
412 }
413 bufferInfo.dequeued = false;
414
415 if (bufferInfo.dequeue_fence >= 0) {
416 close(bufferInfo.dequeue_fence);
417 bufferInfo.dequeue_fence = -1;
418 }
419 }
420
421 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
422 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
423
424 bufferInfo.skSurface.reset();
425 bufferInfo.buffer.clear();
426 bufferInfo.hasValidContents = false;
427 bufferInfo.lastPresentedCount = 0;
428 }
429}
430
431VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400432 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500433 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400434 mCurrentBufferInfo = nullptr;
435
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500436
437 //check if the native window has been resized or rotated and update accordingly
438 SkISize newSize = SkISize::MakeEmpty();
439 int transformHint = 0;
440 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth);
441 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &newSize.fHeight);
442 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
443 if (newSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
444 WindowInfo newWindowInfo = mWindowInfo;
445 newWindowInfo.size = newSize;
446 newWindowInfo.transform = IsTransformSupported(transformHint) ? transformHint : 0;
447 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
448
449 int err = 0;
450 if (newWindowInfo.actualSize != mWindowInfo.actualSize) {
451 // reset the native buffers and update the window
452 err = native_window_set_buffers_dimensions(mNativeWindow.get(),
453 newWindowInfo.actualSize.width(),
454 newWindowInfo.actualSize.height());
455 if (err != 0) {
456 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
457 newWindowInfo.actualSize.width(),
458 newWindowInfo.actualSize.height(), strerror(-err), err);
459 return nullptr;
460 }
461 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
462 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
463 releaseBuffers();
464 // TODO should we ask the nativewindow to allocate buffers?
465 }
466
467 if (newWindowInfo.transform != mWindowInfo.transform) {
468 err = native_window_set_buffers_transform(mNativeWindow.get(),
469 InvertTransform(newWindowInfo.transform));
470 if (err != 0) {
471 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
472 newWindowInfo.transform, strerror(-err), err);
473 newWindowInfo.transform = mWindowInfo.transform;
474 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
475 }
476 }
477
478 mWindowInfo = newWindowInfo;
479 }
480
481 ANativeWindowBuffer* buffer;
482 int fence_fd;
483 int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
484 if (err != 0) {
485 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
486 return nullptr;
487 }
488
489 uint32_t idx;
490 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
491 if (mNativeBuffers[idx].buffer.get() == buffer) {
492 mNativeBuffers[idx].dequeued = true;
493 mNativeBuffers[idx].dequeue_fence = fence_fd;
494 break;
495 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
496 // increasing the number of buffers we have allocated
497 mNativeBuffers[idx].buffer = buffer;
498 mNativeBuffers[idx].dequeued = true;
499 mNativeBuffers[idx].dequeue_fence = fence_fd;
500 break;
501 }
502 }
503 if (idx == mWindowInfo.bufferCount) {
504 ALOGE("dequeueBuffer returned unrecognized buffer");
505 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
506 return nullptr;
507 }
508
509 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
510
511 if (bufferInfo->skSurface.get() == nullptr) {
512 bufferInfo->skSurface =
513 SkSurface::MakeFromAHardwareBuffer(mGrContext,
514 ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
515 kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace),
516 nullptr);
517 if (bufferInfo->skSurface.get() == nullptr) {
518 ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
519 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
520 return nullptr;
521 }
522 }
523
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400524 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500525 return bufferInfo;
526}
527
528bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
529 if (!dirtyRect.isEmpty()) {
530 SkRect transformedRect;
531 mWindowInfo.preTransform.mapRect(&transformedRect, dirtyRect);
532
533 SkIRect transformedIRect;
534 transformedRect.roundOut(&transformedIRect);
535 transformedIRect.intersect(0, 0, mWindowInfo.size.fWidth, mWindowInfo.size.fHeight);
536
537 // map to bottom-left coordinate system
538 android_native_rect_t aRect;
539 aRect.left = transformedIRect.x();
540 aRect.top = mWindowInfo.size.fHeight - (transformedIRect.y() + transformedIRect.height());
541 aRect.right = aRect.left + transformedIRect.width();
542 aRect.bottom = aRect.top - transformedIRect.height();
543
544 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
545 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
546 }
547
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400548 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
549 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500550 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
551 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
552
553 currentBuffer.dequeued = false;
554 // queueBuffer always closes fence, even on error
555 if (err != 0) {
556 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
557 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
558 currentBuffer.dequeue_fence);
559 } else {
560 currentBuffer.hasValidContents = true;
561 currentBuffer.lastPresentedCount = mPresentCount;
562 mPresentCount++;
563 }
564
565 if (currentBuffer.dequeue_fence >= 0) {
566 close(currentBuffer.dequeue_fence);
567 currentBuffer.dequeue_fence = -1;
568 }
569
570 return err == 0;
571}
572
573int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400574 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
575 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500576 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
577}
578
579} /* namespace renderthread */
580} /* namespace uirenderer */
581} /* namespace android */