blob: 4f64da79c3fb99aee013d247ddd14d839bd833e2 [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
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050019#include <SkSurface.h>
John Reck0fa0cbc2019-04-05 16:57:46 -070020#include <algorithm>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050021
22#include "VulkanManager.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050023#include "utils/Color.h"
John Reck0fa0cbc2019-04-05 16:57:46 -070024#include "utils/TraceUtils.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050025
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.
John Reck0fa0cbc2019-04-05 16:57:46 -070034 return transform == 0 || transform == NATIVE_WINDOW_TRANSFORM_ROT_90 ||
35 transform == NATIVE_WINDOW_TRANSFORM_ROT_180 ||
36 transform == NATIVE_WINDOW_TRANSFORM_ROT_270;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050037}
38
39static 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
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050052static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
53 const int width = windowSize.width();
54 const int height = windowSize.height();
55
56 switch (transform) {
57 case 0:
58 return SkMatrix::I();
59 case NATIVE_WINDOW_TRANSFORM_ROT_90:
60 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
61 case NATIVE_WINDOW_TRANSFORM_ROT_180:
62 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
63 case NATIVE_WINDOW_TRANSFORM_ROT_270:
64 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
65 default:
66 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
67 }
68 return SkMatrix::I();
69}
70
71void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize,
John Reck0fa0cbc2019-04-05 16:57:46 -070072 const SkISize& maxSize) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050073 SkISize& windowSize = windowInfo->size;
74
75 // clamp width & height to handle currentExtent of -1 and protect us from broken hints
John Reck0fa0cbc2019-04-05 16:57:46 -070076 if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width() ||
77 windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050078 int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width()));
79 int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height()));
John Reck0fa0cbc2019-04-05 16:57:46 -070080 ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]", windowSize.width(),
81 windowSize.height(), width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050082 windowSize.set(width, height);
83 }
84
85 windowInfo->actualSize = windowSize;
Yiwei Zhang68daf672019-06-26 22:02:41 -070086 if (windowInfo->transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050087 windowInfo->actualSize.set(windowSize.height(), windowSize.width());
88 }
89
90 windowInfo->preTransform = GetPreTransformMatrix(windowInfo->size, windowInfo->transform);
91}
92
Yiwei Zhang68daf672019-06-26 22:02:41 -070093static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
94 ATRACE_CALL();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050095
96 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
97 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070098 ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050099 return false;
100 }
101
102 // this will match what we do on GL so pick that here.
103 err = window->setSwapInterval(window, 1);
104 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700105 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500106 return false;
107 }
108
109 err = native_window_set_shared_buffer_mode(window, false);
110 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700111 ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500112 return false;
113 }
114
115 err = native_window_set_auto_refresh(window, false);
116 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700117 ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
118 return false;
119 }
120
121 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
122 if (err != 0) {
123 ALOGE("native_window_set_scaling_mode(NATIVE_WINDOW_SCALING_MODE_FREEZE) failed: %s (%d)",
124 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500125 return false;
126 }
127
128 return true;
129}
130
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500131VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700132 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
133 GrContext* grContext, const VulkanManager& vkManager,
134 uint32_t extraBuffers) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700135 // TODO(http://b/134182502)
136 const SkISize minSize = SkISize::Make(1, 1);
137 const SkISize maxSize = SkISize::Make(4096, 4096);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500138
Yiwei Zhang68daf672019-06-26 22:02:41 -0700139 // Connect and set native window to default configurations.
140 if (!ConnectAndSetWindowDefaults(window)) {
141 return nullptr;
142 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500143
Yiwei Zhang68daf672019-06-26 22:02:41 -0700144 // Initialize WindowInfo struct.
145 WindowInfo windowInfo;
146 if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
147 extraBuffers, minSize, maxSize, &windowInfo)) {
148 return nullptr;
149 }
150
151 // Now we attempt to modify the window.
152 if (!UpdateWindow(window, windowInfo)) {
153 return nullptr;
154 }
155
156 return new VulkanSurface(window, windowInfo, minSize, maxSize, grContext);
157}
158
159bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
160 SkColorType colorType,
161 sk_sp<SkColorSpace> colorSpace,
162 const VulkanManager& vkManager,
163 uint32_t extraBuffers, const SkISize& minSize,
164 const SkISize& maxSize, WindowInfo* outWindowInfo) {
165 ATRACE_CALL();
166
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700167 int width, height;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700168 int err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700169 if (err != 0 || width < 0) {
170 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, width);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700171 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700172 }
173 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
174 if (err != 0 || height < 0) {
175 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, height);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700176 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700177 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700178 outWindowInfo->size = SkISize::Make(width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500179
John Reckac513c22019-03-28 16:57:38 -0700180 int query_value;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700181 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &query_value);
John Reckac513c22019-03-28 16:57:38 -0700182 if (err != 0 || query_value < 0) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700183 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700184 return false;
John Reckac513c22019-03-28 16:57:38 -0700185 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700186 outWindowInfo->transform = query_value;
John Reckac513c22019-03-28 16:57:38 -0700187
Yiwei Zhang68daf672019-06-26 22:02:41 -0700188 ComputeWindowSizeAndTransform(outWindowInfo, minSize, maxSize);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700189
190 err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
191 if (err != 0 || query_value < 0) {
192 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700193 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500194 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700195 outWindowInfo->bufferCount =
196 static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500197
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700198 err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
199 if (err != 0 || query_value < 0) {
200 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700201 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700202 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700203 if (outWindowInfo->bufferCount > static_cast<uint32_t>(query_value)) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700204 // Application must settle for fewer images than desired:
Yiwei Zhang68daf672019-06-26 22:02:41 -0700205 outWindowInfo->bufferCount = static_cast<uint32_t>(query_value);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700206 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500207
Yiwei Zhang68daf672019-06-26 22:02:41 -0700208 outWindowInfo->dataspace = HAL_DATASPACE_V0_SRGB;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500209 if (colorMode == ColorMode::WideColorGamut) {
210 skcms_Matrix3x3 surfaceGamut;
211 LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut),
212 "Could not get gamut matrix from color space");
213 if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700214 outWindowInfo->dataspace = HAL_DATASPACE_V0_SCRGB;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500215 } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700216 outWindowInfo->dataspace = HAL_DATASPACE_DISPLAY_P3;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500217 } else {
218 LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
219 }
220 }
221
Yiwei Zhang68daf672019-06-26 22:02:41 -0700222 outWindowInfo->pixelFormat = ColorTypeToPixelFormat(colorType);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500223 VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700224 if (outWindowInfo->pixelFormat == PIXEL_FORMAT_RGBA_FP16) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500225 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
226 }
227
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400228 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
229 "vkGetPhysicalDeviceImageFormatProperties2 is missing");
230 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
231 externalImageFormatInfo.sType =
232 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
233 externalImageFormatInfo.pNext = nullptr;
234 externalImageFormatInfo.handleType =
235 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400236
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400237 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
238 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
239 imageFormatInfo.pNext = &externalImageFormatInfo;
240 imageFormatInfo.format = vkPixelFormat;
241 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
242 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700243 // Currently Skia requires the images to be color attachments and support all transfer
244 // operations.
245 imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
246 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400247 imageFormatInfo.flags = 0;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400248
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400249 VkAndroidHardwareBufferUsageANDROID hwbUsage;
250 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
251 hwbUsage.pNext = nullptr;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400252
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400253 VkImageFormatProperties2 imgFormProps;
254 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
255 imgFormProps.pNext = &hwbUsage;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400256
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700257 VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
258 vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400259 if (VK_SUCCESS != res) {
260 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
Yiwei Zhang68daf672019-06-26 22:02:41 -0700261 return false;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400262 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500263
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400264 uint64_t consumerUsage;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700265 err = native_window_get_consumer_usage(window, &consumerUsage);
266 if (err != 0) {
267 ALOGE("native_window_get_consumer_usage failed: %s (%d)", strerror(-err), err);
268 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500269 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700270 outWindowInfo->windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500271
Yiwei Zhang68daf672019-06-26 22:02:41 -0700272 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500273}
274
275bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
276 ATRACE_CALL();
277
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500278 int err = native_window_set_buffers_format(window, windowInfo.pixelFormat);
279 if (err != 0) {
280 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
281 windowInfo.pixelFormat, strerror(-err), err);
282 return false;
283 }
284
285 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
286 if (err != 0) {
287 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700288 "failed: %s (%d)",
289 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500290 return false;
291 }
292
293 const SkISize& size = windowInfo.actualSize;
294 err = native_window_set_buffers_dimensions(window, size.width(), size.height());
295 if (err != 0) {
296 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700297 "failed: %s (%d)",
298 size.width(), size.height(), strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500299 return false;
300 }
301
302 // native_window_set_buffers_transform() expects the transform the app is requesting that
303 // the compositor perform during composition. With native windows, pre-transform works by
304 // rendering with the same transform the compositor is applying (as in Vulkan), but
305 // then requesting the inverse transform, so that when the compositor does
306 // it's job the two transforms cancel each other out and the compositor ends
307 // up applying an identity transform to the app's buffer.
308 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
309 if (err != 0) {
310 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700311 "failed: %s (%d)",
312 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500313 return false;
314 }
315
John Reckac513c22019-03-28 16:57:38 -0700316 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500317 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700318 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500319 windowInfo.bufferCount, strerror(-err), err);
320 return false;
321 }
322
323 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
324 if (err != 0) {
325 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
326 strerror(-err), err);
327 return false;
328 }
329
Yiwei Zhang68daf672019-06-26 22:02:41 -0700330 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500331}
332
333VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
John Reck0fa0cbc2019-04-05 16:57:46 -0700334 SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500335 : mNativeWindow(window)
336 , mWindowInfo(windowInfo)
337 , mGrContext(grContext)
338 , mMinWindowSize(minWindowSize)
John Reck0fa0cbc2019-04-05 16:57:46 -0700339 , mMaxWindowSize(maxWindowSize) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500340
341VulkanSurface::~VulkanSurface() {
342 releaseBuffers();
343
344 // release the native window to be available for use by other clients
345 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
346 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
347}
348
349void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700350 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500351 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
352
353 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
354 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
355 bufferInfo.dequeue_fence);
356 if (err != 0) {
357 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
358 }
359 bufferInfo.dequeued = false;
360
361 if (bufferInfo.dequeue_fence >= 0) {
362 close(bufferInfo.dequeue_fence);
363 bufferInfo.dequeue_fence = -1;
364 }
365 }
366
367 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
368 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
369
370 bufferInfo.skSurface.reset();
371 bufferInfo.buffer.clear();
372 bufferInfo.hasValidContents = false;
373 bufferInfo.lastPresentedCount = 0;
374 }
375}
376
377VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400378 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500379 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400380 mCurrentBufferInfo = nullptr;
381
John Reck0fa0cbc2019-04-05 16:57:46 -0700382 // check if the native window has been resized or rotated and update accordingly
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500383 SkISize newSize = SkISize::MakeEmpty();
384 int transformHint = 0;
385 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth);
386 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &newSize.fHeight);
387 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
388 if (newSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
389 WindowInfo newWindowInfo = mWindowInfo;
390 newWindowInfo.size = newSize;
391 newWindowInfo.transform = IsTransformSupported(transformHint) ? transformHint : 0;
392 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
393
394 int err = 0;
395 if (newWindowInfo.actualSize != mWindowInfo.actualSize) {
396 // reset the native buffers and update the window
397 err = native_window_set_buffers_dimensions(mNativeWindow.get(),
398 newWindowInfo.actualSize.width(),
399 newWindowInfo.actualSize.height());
400 if (err != 0) {
401 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
John Reck0fa0cbc2019-04-05 16:57:46 -0700402 newWindowInfo.actualSize.width(), newWindowInfo.actualSize.height(),
403 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500404 return nullptr;
405 }
406 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
407 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
408 releaseBuffers();
409 // TODO should we ask the nativewindow to allocate buffers?
410 }
411
412 if (newWindowInfo.transform != mWindowInfo.transform) {
413 err = native_window_set_buffers_transform(mNativeWindow.get(),
John Reck0fa0cbc2019-04-05 16:57:46 -0700414 InvertTransform(newWindowInfo.transform));
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500415 if (err != 0) {
416 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
417 newWindowInfo.transform, strerror(-err), err);
418 newWindowInfo.transform = mWindowInfo.transform;
419 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
420 }
421 }
422
423 mWindowInfo = newWindowInfo;
424 }
425
426 ANativeWindowBuffer* buffer;
427 int fence_fd;
428 int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
429 if (err != 0) {
430 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
431 return nullptr;
432 }
433
434 uint32_t idx;
435 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
436 if (mNativeBuffers[idx].buffer.get() == buffer) {
437 mNativeBuffers[idx].dequeued = true;
438 mNativeBuffers[idx].dequeue_fence = fence_fd;
439 break;
440 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
441 // increasing the number of buffers we have allocated
442 mNativeBuffers[idx].buffer = buffer;
443 mNativeBuffers[idx].dequeued = true;
444 mNativeBuffers[idx].dequeue_fence = fence_fd;
445 break;
446 }
447 }
448 if (idx == mWindowInfo.bufferCount) {
449 ALOGE("dequeueBuffer returned unrecognized buffer");
450 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
451 return nullptr;
452 }
453
454 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
455
456 if (bufferInfo->skSurface.get() == nullptr) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700457 bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
458 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
459 kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), nullptr);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500460 if (bufferInfo->skSurface.get() == nullptr) {
461 ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
462 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
463 return nullptr;
464 }
465 }
466
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400467 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500468 return bufferInfo;
469}
470
471bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
472 if (!dirtyRect.isEmpty()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500473
John Reck321d8e52019-04-12 13:06:11 -0700474 // native_window_set_surface_damage takes a rectangle in prerotated space
475 // with a bottom-left origin. That is, top > bottom.
476 // The dirtyRect is also in prerotated space, so we just need to switch it to
477 // a bottom-left origin space.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500478
John Reck321d8e52019-04-12 13:06:11 -0700479 SkIRect irect;
480 dirtyRect.roundOut(&irect);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500481 android_native_rect_t aRect;
John Reck321d8e52019-04-12 13:06:11 -0700482 aRect.left = irect.left();
483 aRect.top = logicalHeight() - irect.top();
484 aRect.right = irect.right();
485 aRect.bottom = logicalHeight() - irect.bottom();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500486
487 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
488 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
489 }
490
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400491 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
492 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500493 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
494 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
495
496 currentBuffer.dequeued = false;
497 // queueBuffer always closes fence, even on error
498 if (err != 0) {
499 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
500 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
501 currentBuffer.dequeue_fence);
502 } else {
503 currentBuffer.hasValidContents = true;
504 currentBuffer.lastPresentedCount = mPresentCount;
505 mPresentCount++;
506 }
507
508 if (currentBuffer.dequeue_fence >= 0) {
509 close(currentBuffer.dequeue_fence);
510 currentBuffer.dequeue_fence = -1;
511 }
512
513 return err == 0;
514}
515
516int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400517 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
518 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500519 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
520}
521
522} /* namespace renderthread */
523} /* namespace uirenderer */
524} /* namespace android */