blob: 474d2ccf8600a2f3a66d8be3818c9c075ccbbc3e [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
Adlai Hollerd2345212020-10-07 14:16:40 -040019#include <GrDirectContext.h>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050020#include <SkSurface.h>
John Reck0fa0cbc2019-04-05 16:57:46 -070021#include <algorithm>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050022
23#include "VulkanManager.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050024#include "utils/Color.h"
John Reck0fa0cbc2019-04-05 16:57:46 -070025#include "utils/TraceUtils.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050026
27namespace android {
28namespace uirenderer {
29namespace renderthread {
30
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050031static int InvertTransform(int transform) {
32 switch (transform) {
Alec Mouria5a0c962019-12-10 15:10:14 -080033 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
34 return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
35 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
36 return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
37 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
38 return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050039 default:
40 return 0;
41 }
42}
43
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050044static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
45 const int width = windowSize.width();
46 const int height = windowSize.height();
47
48 switch (transform) {
49 case 0:
50 return SkMatrix::I();
Alec Mouria5a0c962019-12-10 15:10:14 -080051 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050052 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080053 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050054 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080055 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050056 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
57 default:
58 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
59 }
60 return SkMatrix::I();
61}
62
Yiwei Zhang68daf672019-06-26 22:02:41 -070063static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
64 ATRACE_CALL();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050065
66 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
67 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070068 ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050069 return false;
70 }
71
72 // this will match what we do on GL so pick that here.
73 err = window->setSwapInterval(window, 1);
74 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070075 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050076 return false;
77 }
78
79 err = native_window_set_shared_buffer_mode(window, false);
80 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070081 ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050082 return false;
83 }
84
85 err = native_window_set_auto_refresh(window, false);
86 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070087 ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
88 return false;
89 }
90
91 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
92 if (err != 0) {
93 ALOGE("native_window_set_scaling_mode(NATIVE_WINDOW_SCALING_MODE_FREEZE) failed: %s (%d)",
94 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050095 return false;
96 }
97
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -070098 // Let consumer drive the size of the buffers.
99 err = native_window_set_buffers_dimensions(window, 0, 0);
100 if (err != 0) {
101 ALOGE("native_window_set_buffers_dimensions(0,0) failed: %s (%d)", strerror(-err), err);
102 return false;
103 }
104
105 // Enable auto prerotation, so when buffer size is driven by the consumer
106 // and the transform hint specifies a 90 or 270 degree rotation, the width
107 // and height used for buffer pre-allocation and dequeueBuffer will be
108 // additionally swapped.
109 err = native_window_set_auto_prerotation(window, true);
110 if (err != 0) {
111 ALOGE("VulkanSurface::UpdateWindow() native_window_set_auto_prerotation failed: %s (%d)",
112 strerror(-err), err);
113 return false;
114 }
115
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500116 return true;
117}
118
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500119VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700120 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
Adlai Hollerd2345212020-10-07 14:16:40 -0400121 GrDirectContext* grContext, const VulkanManager& vkManager,
John Reck0fa0cbc2019-04-05 16:57:46 -0700122 uint32_t extraBuffers) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700123 // Connect and set native window to default configurations.
124 if (!ConnectAndSetWindowDefaults(window)) {
125 return nullptr;
126 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500127
Yiwei Zhang68daf672019-06-26 22:02:41 -0700128 // Initialize WindowInfo struct.
129 WindowInfo windowInfo;
130 if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700131 extraBuffers, &windowInfo)) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700132 return nullptr;
133 }
134
135 // Now we attempt to modify the window.
136 if (!UpdateWindow(window, windowInfo)) {
137 return nullptr;
138 }
139
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700140 return new VulkanSurface(window, windowInfo, grContext);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700141}
142
143bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
144 SkColorType colorType,
145 sk_sp<SkColorSpace> colorSpace,
146 const VulkanManager& vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700147 uint32_t extraBuffers, WindowInfo* outWindowInfo) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700148 ATRACE_CALL();
149
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700150 int width, height;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700151 int err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700152 if (err != 0 || width < 0) {
153 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, width);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700154 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700155 }
156 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
157 if (err != 0 || height < 0) {
158 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, height);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700159 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700160 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700161 outWindowInfo->size = SkISize::Make(width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500162
John Reckac513c22019-03-28 16:57:38 -0700163 int query_value;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700164 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &query_value);
John Reckac513c22019-03-28 16:57:38 -0700165 if (err != 0 || query_value < 0) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700166 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700167 return false;
John Reckac513c22019-03-28 16:57:38 -0700168 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700169 outWindowInfo->transform = query_value;
John Reckac513c22019-03-28 16:57:38 -0700170
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700171 outWindowInfo->actualSize = outWindowInfo->size;
Alec Mouria5a0c962019-12-10 15:10:14 -0800172 if (outWindowInfo->transform & ANATIVEWINDOW_TRANSFORM_ROTATE_90) {
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700173 outWindowInfo->actualSize.set(outWindowInfo->size.height(), outWindowInfo->size.width());
174 }
175
176 outWindowInfo->preTransform =
177 GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700178
179 err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
180 if (err != 0 || query_value < 0) {
181 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700182 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500183 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700184 outWindowInfo->bufferCount =
185 static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500186
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700187 err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
188 if (err != 0 || query_value < 0) {
189 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700190 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700191 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700192 if (outWindowInfo->bufferCount > static_cast<uint32_t>(query_value)) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700193 // Application must settle for fewer images than desired:
Yiwei Zhang68daf672019-06-26 22:02:41 -0700194 outWindowInfo->bufferCount = static_cast<uint32_t>(query_value);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700195 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500196
Alec Mouri45238012020-01-29 11:04:40 -0800197 outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400198 outWindowInfo->colorspace = colorSpace;
199 outWindowInfo->dataspace = ColorSpaceToADataSpace(colorSpace.get(), colorType);
200 LOG_ALWAYS_FATAL_IF(outWindowInfo->dataspace == HAL_DATASPACE_UNKNOWN,
201 "Unsupported colorspace");
202
203 VkFormat vkPixelFormat;
204 switch (colorType) {
205 case kRGBA_8888_SkColorType:
206 vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
207 break;
208 case kRGBA_F16_SkColorType:
209 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
210 break;
211 case kRGBA_1010102_SkColorType:
212 vkPixelFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
213 break;
214 default:
215 LOG_ALWAYS_FATAL("Unsupported colorType: %d", (int)colorType);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500216 }
217
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400218 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
219 "vkGetPhysicalDeviceImageFormatProperties2 is missing");
220 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
221 externalImageFormatInfo.sType =
222 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
223 externalImageFormatInfo.pNext = nullptr;
224 externalImageFormatInfo.handleType =
225 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400226
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400227 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
228 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
229 imageFormatInfo.pNext = &externalImageFormatInfo;
230 imageFormatInfo.format = vkPixelFormat;
231 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
232 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700233 // Currently Skia requires the images to be color attachments and support all transfer
234 // operations.
235 imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
236 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400237 imageFormatInfo.flags = 0;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400238
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400239 VkAndroidHardwareBufferUsageANDROID hwbUsage;
240 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
241 hwbUsage.pNext = nullptr;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400242
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400243 VkImageFormatProperties2 imgFormProps;
244 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
245 imgFormProps.pNext = &hwbUsage;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400246
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700247 VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
248 vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400249 if (VK_SUCCESS != res) {
250 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
Yiwei Zhang68daf672019-06-26 22:02:41 -0700251 return false;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400252 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500253
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400254 uint64_t consumerUsage;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700255 err = native_window_get_consumer_usage(window, &consumerUsage);
256 if (err != 0) {
257 ALOGE("native_window_get_consumer_usage failed: %s (%d)", strerror(-err), err);
258 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500259 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700260 outWindowInfo->windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500261
Yiwei Zhang68daf672019-06-26 22:02:41 -0700262 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500263}
264
265bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
266 ATRACE_CALL();
267
Alec Mouri45238012020-01-29 11:04:40 -0800268 int err = native_window_set_buffers_format(window, windowInfo.bufferFormat);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500269 if (err != 0) {
270 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
Alec Mouri45238012020-01-29 11:04:40 -0800271 windowInfo.bufferFormat, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500272 return false;
273 }
274
275 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
276 if (err != 0) {
277 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700278 "failed: %s (%d)",
279 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500280 return false;
281 }
282
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500283 // native_window_set_buffers_transform() expects the transform the app is requesting that
284 // the compositor perform during composition. With native windows, pre-transform works by
285 // rendering with the same transform the compositor is applying (as in Vulkan), but
286 // then requesting the inverse transform, so that when the compositor does
287 // it's job the two transforms cancel each other out and the compositor ends
288 // up applying an identity transform to the app's buffer.
289 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
290 if (err != 0) {
291 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700292 "failed: %s (%d)",
293 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500294 return false;
295 }
296
John Reckac513c22019-03-28 16:57:38 -0700297 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500298 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700299 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500300 windowInfo.bufferCount, strerror(-err), err);
301 return false;
302 }
303
304 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
305 if (err != 0) {
306 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
307 strerror(-err), err);
308 return false;
309 }
310
Yiwei Zhang68daf672019-06-26 22:02:41 -0700311 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500312}
313
314VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
Adlai Hollerd2345212020-10-07 14:16:40 -0400315 GrDirectContext* grContext)
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700316 : mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500317
318VulkanSurface::~VulkanSurface() {
319 releaseBuffers();
320
321 // release the native window to be available for use by other clients
322 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
323 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
324}
325
326void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700327 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500328 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
329
330 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
331 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
332 bufferInfo.dequeue_fence);
333 if (err != 0) {
334 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
335 }
336 bufferInfo.dequeued = false;
337
338 if (bufferInfo.dequeue_fence >= 0) {
339 close(bufferInfo.dequeue_fence);
340 bufferInfo.dequeue_fence = -1;
341 }
342 }
343
344 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
345 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
346
347 bufferInfo.skSurface.reset();
348 bufferInfo.buffer.clear();
349 bufferInfo.hasValidContents = false;
350 bufferInfo.lastPresentedCount = 0;
351 }
352}
353
354VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400355 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500356 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400357 mCurrentBufferInfo = nullptr;
358
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700359 // Query the transform hint synced from the initial Surface connect or last queueBuffer. The
360 // auto prerotation on the buffer is based on the same transform hint in use by the producer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500361 int transformHint = 0;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700362 int err =
363 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500364
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700365 // Since auto pre-rotation is enabled, dequeueBuffer to get the consumer driven buffer size
366 // from ANativeWindowBuffer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500367 ANativeWindowBuffer* buffer;
368 int fence_fd;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700369 err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500370 if (err != 0) {
371 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
372 return nullptr;
373 }
374
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700375 SkISize actualSize = SkISize::Make(buffer->width, buffer->height);
376 if (actualSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
377 if (actualSize != mWindowInfo.actualSize) {
378 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
379 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
380 mWindowInfo.actualSize = actualSize;
381 releaseBuffers();
382 }
383
384 if (transformHint != mWindowInfo.transform) {
385 err = native_window_set_buffers_transform(mNativeWindow.get(),
386 InvertTransform(transformHint));
387 if (err != 0) {
388 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", transformHint,
389 strerror(-err), err);
390 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
391 return nullptr;
392 }
393 mWindowInfo.transform = transformHint;
394 }
395
396 mWindowInfo.size = actualSize;
397 if (mWindowInfo.transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
398 mWindowInfo.size.set(actualSize.height(), actualSize.width());
399 }
400
401 mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
402 }
403
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500404 uint32_t idx;
405 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
406 if (mNativeBuffers[idx].buffer.get() == buffer) {
407 mNativeBuffers[idx].dequeued = true;
408 mNativeBuffers[idx].dequeue_fence = fence_fd;
409 break;
410 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
411 // increasing the number of buffers we have allocated
412 mNativeBuffers[idx].buffer = buffer;
413 mNativeBuffers[idx].dequeued = true;
414 mNativeBuffers[idx].dequeue_fence = fence_fd;
415 break;
416 }
417 }
418 if (idx == mWindowInfo.bufferCount) {
419 ALOGE("dequeueBuffer returned unrecognized buffer");
420 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
421 return nullptr;
422 }
423
424 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
425
426 if (bufferInfo->skSurface.get() == nullptr) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700427 bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
428 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400429 kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, nullptr);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500430 if (bufferInfo->skSurface.get() == nullptr) {
431 ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
432 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
433 return nullptr;
434 }
435 }
436
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400437 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500438 return bufferInfo;
439}
440
441bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
442 if (!dirtyRect.isEmpty()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500443
John Reck321d8e52019-04-12 13:06:11 -0700444 // native_window_set_surface_damage takes a rectangle in prerotated space
445 // with a bottom-left origin. That is, top > bottom.
446 // The dirtyRect is also in prerotated space, so we just need to switch it to
447 // a bottom-left origin space.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500448
John Reck321d8e52019-04-12 13:06:11 -0700449 SkIRect irect;
450 dirtyRect.roundOut(&irect);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500451 android_native_rect_t aRect;
John Reck321d8e52019-04-12 13:06:11 -0700452 aRect.left = irect.left();
453 aRect.top = logicalHeight() - irect.top();
454 aRect.right = irect.right();
455 aRect.bottom = logicalHeight() - irect.bottom();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500456
457 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
458 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
459 }
460
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400461 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
462 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500463 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
464 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
465
466 currentBuffer.dequeued = false;
467 // queueBuffer always closes fence, even on error
468 if (err != 0) {
469 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
470 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
471 currentBuffer.dequeue_fence);
472 } else {
473 currentBuffer.hasValidContents = true;
474 currentBuffer.lastPresentedCount = mPresentCount;
475 mPresentCount++;
476 }
477
478 if (currentBuffer.dequeue_fence >= 0) {
479 close(currentBuffer.dequeue_fence);
480 currentBuffer.dequeue_fence = -1;
481 }
482
483 return err == 0;
484}
485
486int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400487 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
488 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500489 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
490}
491
492} /* namespace renderthread */
493} /* namespace uirenderer */
494} /* namespace android */