blob: 9cbb754be9b939bf9aa402fa996411f985a219f3 [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
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050030static int InvertTransform(int transform) {
31 switch (transform) {
Alec Mouria5a0c962019-12-10 15:10:14 -080032 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
33 return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
34 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
35 return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
36 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
37 return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050038 default:
39 return 0;
40 }
41}
42
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050043static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
44 const int width = windowSize.width();
45 const int height = windowSize.height();
46
47 switch (transform) {
48 case 0:
49 return SkMatrix::I();
Alec Mouria5a0c962019-12-10 15:10:14 -080050 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050051 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080052 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050053 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080054 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050055 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
56 default:
57 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
58 }
59 return SkMatrix::I();
60}
61
Yiwei Zhang68daf672019-06-26 22:02:41 -070062static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
63 ATRACE_CALL();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050064
65 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
66 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070067 ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050068 return false;
69 }
70
71 // this will match what we do on GL so pick that here.
72 err = window->setSwapInterval(window, 1);
73 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070074 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050075 return false;
76 }
77
78 err = native_window_set_shared_buffer_mode(window, false);
79 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070080 ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050081 return false;
82 }
83
84 err = native_window_set_auto_refresh(window, false);
85 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070086 ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
87 return false;
88 }
89
90 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
91 if (err != 0) {
92 ALOGE("native_window_set_scaling_mode(NATIVE_WINDOW_SCALING_MODE_FREEZE) failed: %s (%d)",
93 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050094 return false;
95 }
96
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -070097 // Let consumer drive the size of the buffers.
98 err = native_window_set_buffers_dimensions(window, 0, 0);
99 if (err != 0) {
100 ALOGE("native_window_set_buffers_dimensions(0,0) failed: %s (%d)", strerror(-err), err);
101 return false;
102 }
103
104 // Enable auto prerotation, so when buffer size is driven by the consumer
105 // and the transform hint specifies a 90 or 270 degree rotation, the width
106 // and height used for buffer pre-allocation and dequeueBuffer will be
107 // additionally swapped.
108 err = native_window_set_auto_prerotation(window, true);
109 if (err != 0) {
110 ALOGE("VulkanSurface::UpdateWindow() native_window_set_auto_prerotation failed: %s (%d)",
111 strerror(-err), err);
112 return false;
113 }
114
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500115 return true;
116}
117
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500118VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700119 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
120 GrContext* grContext, const VulkanManager& vkManager,
121 uint32_t extraBuffers) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700122 // Connect and set native window to default configurations.
123 if (!ConnectAndSetWindowDefaults(window)) {
124 return nullptr;
125 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500126
Yiwei Zhang68daf672019-06-26 22:02:41 -0700127 // Initialize WindowInfo struct.
128 WindowInfo windowInfo;
129 if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700130 extraBuffers, &windowInfo)) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700131 return nullptr;
132 }
133
134 // Now we attempt to modify the window.
135 if (!UpdateWindow(window, windowInfo)) {
136 return nullptr;
137 }
138
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700139 return new VulkanSurface(window, windowInfo, grContext);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700140}
141
142bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
143 SkColorType colorType,
144 sk_sp<SkColorSpace> colorSpace,
145 const VulkanManager& vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700146 uint32_t extraBuffers, WindowInfo* outWindowInfo) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700147 ATRACE_CALL();
148
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700149 int width, height;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700150 int err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700151 if (err != 0 || width < 0) {
152 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, width);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700153 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700154 }
155 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
156 if (err != 0 || height < 0) {
157 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, height);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700158 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700159 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700160 outWindowInfo->size = SkISize::Make(width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500161
John Reckac513c22019-03-28 16:57:38 -0700162 int query_value;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700163 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &query_value);
John Reckac513c22019-03-28 16:57:38 -0700164 if (err != 0 || query_value < 0) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700165 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700166 return false;
John Reckac513c22019-03-28 16:57:38 -0700167 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700168 outWindowInfo->transform = query_value;
John Reckac513c22019-03-28 16:57:38 -0700169
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700170 outWindowInfo->actualSize = outWindowInfo->size;
Alec Mouria5a0c962019-12-10 15:10:14 -0800171 if (outWindowInfo->transform & ANATIVEWINDOW_TRANSFORM_ROTATE_90) {
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700172 outWindowInfo->actualSize.set(outWindowInfo->size.height(), outWindowInfo->size.width());
173 }
174
175 outWindowInfo->preTransform =
176 GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700177
178 err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
179 if (err != 0 || query_value < 0) {
180 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700181 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500182 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700183 outWindowInfo->bufferCount =
184 static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500185
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700186 err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
187 if (err != 0 || query_value < 0) {
188 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700189 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700190 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700191 if (outWindowInfo->bufferCount > static_cast<uint32_t>(query_value)) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700192 // Application must settle for fewer images than desired:
Yiwei Zhang68daf672019-06-26 22:02:41 -0700193 outWindowInfo->bufferCount = static_cast<uint32_t>(query_value);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700194 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500195
Yiwei Zhang68daf672019-06-26 22:02:41 -0700196 outWindowInfo->dataspace = HAL_DATASPACE_V0_SRGB;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500197 if (colorMode == ColorMode::WideColorGamut) {
198 skcms_Matrix3x3 surfaceGamut;
199 LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut),
200 "Could not get gamut matrix from color space");
201 if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700202 outWindowInfo->dataspace = HAL_DATASPACE_V0_SCRGB;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500203 } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700204 outWindowInfo->dataspace = HAL_DATASPACE_DISPLAY_P3;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500205 } else {
206 LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
207 }
208 }
209
Alec Mouri45238012020-01-29 11:04:40 -0800210 outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500211 VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
Alec Mouri45238012020-01-29 11:04:40 -0800212 if (outWindowInfo->bufferFormat == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500213 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
214 }
215
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400216 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
217 "vkGetPhysicalDeviceImageFormatProperties2 is missing");
218 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
219 externalImageFormatInfo.sType =
220 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
221 externalImageFormatInfo.pNext = nullptr;
222 externalImageFormatInfo.handleType =
223 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400224
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400225 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
226 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
227 imageFormatInfo.pNext = &externalImageFormatInfo;
228 imageFormatInfo.format = vkPixelFormat;
229 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
230 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700231 // Currently Skia requires the images to be color attachments and support all transfer
232 // operations.
233 imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
234 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400235 imageFormatInfo.flags = 0;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400236
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400237 VkAndroidHardwareBufferUsageANDROID hwbUsage;
238 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
239 hwbUsage.pNext = nullptr;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400240
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400241 VkImageFormatProperties2 imgFormProps;
242 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
243 imgFormProps.pNext = &hwbUsage;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400244
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700245 VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
246 vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400247 if (VK_SUCCESS != res) {
248 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
Yiwei Zhang68daf672019-06-26 22:02:41 -0700249 return false;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400250 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500251
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400252 uint64_t consumerUsage;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700253 err = native_window_get_consumer_usage(window, &consumerUsage);
254 if (err != 0) {
255 ALOGE("native_window_get_consumer_usage failed: %s (%d)", strerror(-err), err);
256 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500257 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700258 outWindowInfo->windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500259
Yiwei Zhang68daf672019-06-26 22:02:41 -0700260 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500261}
262
263bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
264 ATRACE_CALL();
265
Alec Mouri45238012020-01-29 11:04:40 -0800266 int err = native_window_set_buffers_format(window, windowInfo.bufferFormat);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500267 if (err != 0) {
268 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
Alec Mouri45238012020-01-29 11:04:40 -0800269 windowInfo.bufferFormat, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500270 return false;
271 }
272
273 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
274 if (err != 0) {
275 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700276 "failed: %s (%d)",
277 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500278 return false;
279 }
280
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500281 // native_window_set_buffers_transform() expects the transform the app is requesting that
282 // the compositor perform during composition. With native windows, pre-transform works by
283 // rendering with the same transform the compositor is applying (as in Vulkan), but
284 // then requesting the inverse transform, so that when the compositor does
285 // it's job the two transforms cancel each other out and the compositor ends
286 // up applying an identity transform to the app's buffer.
287 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
288 if (err != 0) {
289 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700290 "failed: %s (%d)",
291 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500292 return false;
293 }
294
John Reckac513c22019-03-28 16:57:38 -0700295 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500296 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700297 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500298 windowInfo.bufferCount, strerror(-err), err);
299 return false;
300 }
301
302 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
303 if (err != 0) {
304 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
305 strerror(-err), err);
306 return false;
307 }
308
Yiwei Zhang68daf672019-06-26 22:02:41 -0700309 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500310}
311
312VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700313 GrContext* grContext)
314 : mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500315
316VulkanSurface::~VulkanSurface() {
317 releaseBuffers();
318
319 // release the native window to be available for use by other clients
320 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
321 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
322}
323
324void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700325 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500326 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
327
328 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
329 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
330 bufferInfo.dequeue_fence);
331 if (err != 0) {
332 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
333 }
334 bufferInfo.dequeued = false;
335
336 if (bufferInfo.dequeue_fence >= 0) {
337 close(bufferInfo.dequeue_fence);
338 bufferInfo.dequeue_fence = -1;
339 }
340 }
341
342 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
343 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
344
345 bufferInfo.skSurface.reset();
346 bufferInfo.buffer.clear();
347 bufferInfo.hasValidContents = false;
348 bufferInfo.lastPresentedCount = 0;
349 }
350}
351
352VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400353 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500354 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400355 mCurrentBufferInfo = nullptr;
356
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700357 // Query the transform hint synced from the initial Surface connect or last queueBuffer. The
358 // auto prerotation on the buffer is based on the same transform hint in use by the producer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500359 int transformHint = 0;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700360 int err =
361 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500362
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700363 // Since auto pre-rotation is enabled, dequeueBuffer to get the consumer driven buffer size
364 // from ANativeWindowBuffer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500365 ANativeWindowBuffer* buffer;
366 int fence_fd;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700367 err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500368 if (err != 0) {
369 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
370 return nullptr;
371 }
372
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700373 SkISize actualSize = SkISize::Make(buffer->width, buffer->height);
374 if (actualSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
375 if (actualSize != mWindowInfo.actualSize) {
376 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
377 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
378 mWindowInfo.actualSize = actualSize;
379 releaseBuffers();
380 }
381
382 if (transformHint != mWindowInfo.transform) {
383 err = native_window_set_buffers_transform(mNativeWindow.get(),
384 InvertTransform(transformHint));
385 if (err != 0) {
386 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", transformHint,
387 strerror(-err), err);
388 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
389 return nullptr;
390 }
391 mWindowInfo.transform = transformHint;
392 }
393
394 mWindowInfo.size = actualSize;
395 if (mWindowInfo.transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
396 mWindowInfo.size.set(actualSize.height(), actualSize.width());
397 }
398
399 mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
400 }
401
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500402 uint32_t idx;
403 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
404 if (mNativeBuffers[idx].buffer.get() == buffer) {
405 mNativeBuffers[idx].dequeued = true;
406 mNativeBuffers[idx].dequeue_fence = fence_fd;
407 break;
408 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
409 // increasing the number of buffers we have allocated
410 mNativeBuffers[idx].buffer = buffer;
411 mNativeBuffers[idx].dequeued = true;
412 mNativeBuffers[idx].dequeue_fence = fence_fd;
413 break;
414 }
415 }
416 if (idx == mWindowInfo.bufferCount) {
417 ALOGE("dequeueBuffer returned unrecognized buffer");
418 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
419 return nullptr;
420 }
421
422 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
423
424 if (bufferInfo->skSurface.get() == nullptr) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700425 bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
426 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
427 kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), nullptr);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500428 if (bufferInfo->skSurface.get() == nullptr) {
429 ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
430 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
431 return nullptr;
432 }
433 }
434
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400435 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500436 return bufferInfo;
437}
438
439bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
440 if (!dirtyRect.isEmpty()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500441
John Reck321d8e52019-04-12 13:06:11 -0700442 // native_window_set_surface_damage takes a rectangle in prerotated space
443 // with a bottom-left origin. That is, top > bottom.
444 // The dirtyRect is also in prerotated space, so we just need to switch it to
445 // a bottom-left origin space.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500446
John Reck321d8e52019-04-12 13:06:11 -0700447 SkIRect irect;
448 dirtyRect.roundOut(&irect);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500449 android_native_rect_t aRect;
John Reck321d8e52019-04-12 13:06:11 -0700450 aRect.left = irect.left();
451 aRect.top = logicalHeight() - irect.top();
452 aRect.right = irect.right();
453 aRect.bottom = logicalHeight() - irect.bottom();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500454
455 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
456 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
457 }
458
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400459 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
460 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500461 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
462 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
463
464 currentBuffer.dequeued = false;
465 // queueBuffer always closes fence, even on error
466 if (err != 0) {
467 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
468 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
469 currentBuffer.dequeue_fence);
470 } else {
471 currentBuffer.hasValidContents = true;
472 currentBuffer.lastPresentedCount = mPresentCount;
473 mPresentCount++;
474 }
475
476 if (currentBuffer.dequeue_fence >= 0) {
477 close(currentBuffer.dequeue_fence);
478 currentBuffer.dequeue_fence = -1;
479 }
480
481 return err == 0;
482}
483
484int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400485 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
486 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500487 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
488}
489
490} /* namespace renderthread */
491} /* namespace uirenderer */
492} /* namespace android */