blob: 21b6c44e997e98a5e3d033d4aad8909658e8f36a [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
rnleece9762b2021-05-21 15:40:53 -070023#include <gui/TraceUtils.h>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050024#include "VulkanManager.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050025#include "utils/Color.h"
26
Leon Scroggins III7ccb8a42021-11-30 14:17:28 -050027#undef LOG_TAG
28#define LOG_TAG "VulkanSurface"
29
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050030namespace android {
31namespace uirenderer {
32namespace renderthread {
33
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050034static int InvertTransform(int transform) {
35 switch (transform) {
Alec Mouria5a0c962019-12-10 15:10:14 -080036 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
37 return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
38 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
39 return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
40 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
41 return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050042 default:
43 return 0;
44 }
45}
46
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050047static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
48 const int width = windowSize.width();
49 const int height = windowSize.height();
50
51 switch (transform) {
52 case 0:
53 return SkMatrix::I();
Alec Mouria5a0c962019-12-10 15:10:14 -080054 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050055 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080056 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050057 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080058 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050059 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
60 default:
61 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
62 }
63 return SkMatrix::I();
64}
65
Yiwei Zhang68daf672019-06-26 22:02:41 -070066static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
67 ATRACE_CALL();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050068
69 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
70 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070071 ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050072 return false;
73 }
74
75 // this will match what we do on GL so pick that here.
76 err = window->setSwapInterval(window, 1);
77 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070078 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050079 return false;
80 }
81
82 err = native_window_set_shared_buffer_mode(window, false);
83 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070084 ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050085 return false;
86 }
87
88 err = native_window_set_auto_refresh(window, false);
89 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070090 ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
91 return false;
92 }
93
94 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
95 if (err != 0) {
96 ALOGE("native_window_set_scaling_mode(NATIVE_WINDOW_SCALING_MODE_FREEZE) failed: %s (%d)",
97 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050098 return false;
99 }
100
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700101 // Let consumer drive the size of the buffers.
102 err = native_window_set_buffers_dimensions(window, 0, 0);
103 if (err != 0) {
104 ALOGE("native_window_set_buffers_dimensions(0,0) failed: %s (%d)", strerror(-err), err);
105 return false;
106 }
107
108 // Enable auto prerotation, so when buffer size is driven by the consumer
109 // and the transform hint specifies a 90 or 270 degree rotation, the width
110 // and height used for buffer pre-allocation and dequeueBuffer will be
111 // additionally swapped.
112 err = native_window_set_auto_prerotation(window, true);
113 if (err != 0) {
114 ALOGE("VulkanSurface::UpdateWindow() native_window_set_auto_prerotation failed: %s (%d)",
115 strerror(-err), err);
116 return false;
117 }
118
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500119 return true;
120}
121
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500122VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700123 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
Adlai Hollerd2345212020-10-07 14:16:40 -0400124 GrDirectContext* grContext, const VulkanManager& vkManager,
John Reck0fa0cbc2019-04-05 16:57:46 -0700125 uint32_t extraBuffers) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700126 // Connect and set native window to default configurations.
127 if (!ConnectAndSetWindowDefaults(window)) {
128 return nullptr;
129 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500130
Yiwei Zhang68daf672019-06-26 22:02:41 -0700131 // Initialize WindowInfo struct.
132 WindowInfo windowInfo;
133 if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700134 extraBuffers, &windowInfo)) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700135 return nullptr;
136 }
137
138 // Now we attempt to modify the window.
139 if (!UpdateWindow(window, windowInfo)) {
140 return nullptr;
141 }
142
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700143 return new VulkanSurface(window, windowInfo, grContext);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700144}
145
146bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
147 SkColorType colorType,
148 sk_sp<SkColorSpace> colorSpace,
149 const VulkanManager& vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700150 uint32_t extraBuffers, WindowInfo* outWindowInfo) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700151 ATRACE_CALL();
152
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700153 int width, height;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700154 int err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700155 if (err != 0 || width < 0) {
156 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, width);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700157 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700158 }
159 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
160 if (err != 0 || height < 0) {
161 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, height);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700162 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700163 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700164 outWindowInfo->size = SkISize::Make(width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500165
John Reckac513c22019-03-28 16:57:38 -0700166 int query_value;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700167 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &query_value);
John Reckac513c22019-03-28 16:57:38 -0700168 if (err != 0 || query_value < 0) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700169 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700170 return false;
John Reckac513c22019-03-28 16:57:38 -0700171 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700172 outWindowInfo->transform = query_value;
John Reckac513c22019-03-28 16:57:38 -0700173
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700174 outWindowInfo->actualSize = outWindowInfo->size;
Alec Mouria5a0c962019-12-10 15:10:14 -0800175 if (outWindowInfo->transform & ANATIVEWINDOW_TRANSFORM_ROTATE_90) {
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700176 outWindowInfo->actualSize.set(outWindowInfo->size.height(), outWindowInfo->size.width());
177 }
178
179 outWindowInfo->preTransform =
180 GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700181
182 err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
183 if (err != 0 || query_value < 0) {
184 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700185 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500186 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700187 outWindowInfo->bufferCount =
188 static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500189
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700190 err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &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;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700194 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700195 if (outWindowInfo->bufferCount > static_cast<uint32_t>(query_value)) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700196 // Application must settle for fewer images than desired:
Yiwei Zhang68daf672019-06-26 22:02:41 -0700197 outWindowInfo->bufferCount = static_cast<uint32_t>(query_value);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700198 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500199
Alec Mouri45238012020-01-29 11:04:40 -0800200 outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400201 outWindowInfo->colorspace = colorSpace;
John Reck55887762023-01-25 16:51:18 -0500202 outWindowInfo->colorMode = colorMode;
203
John Reck0b3f3312023-01-31 16:21:28 -0500204 if (colorMode == ColorMode::Hdr || colorMode == ColorMode::Hdr10) {
John Reck55887762023-01-25 16:51:18 -0500205 outWindowInfo->dataspace =
206 static_cast<android_dataspace>(STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_EXTENDED);
207 } else {
208 outWindowInfo->dataspace = ColorSpaceToADataSpace(colorSpace.get(), colorType);
209 }
Leon Scroggins III7ccb8a42021-11-30 14:17:28 -0500210 LOG_ALWAYS_FATAL_IF(
211 outWindowInfo->dataspace == HAL_DATASPACE_UNKNOWN && colorType != kAlpha_8_SkColorType,
212 "Unsupported colorspace");
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400213
214 VkFormat vkPixelFormat;
215 switch (colorType) {
216 case kRGBA_8888_SkColorType:
217 vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
218 break;
219 case kRGBA_F16_SkColorType:
220 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
221 break;
222 case kRGBA_1010102_SkColorType:
223 vkPixelFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
224 break;
Leon Scroggins III7ccb8a42021-11-30 14:17:28 -0500225 case kAlpha_8_SkColorType:
226 vkPixelFormat = VK_FORMAT_R8_UNORM;
227 break;
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400228 default:
229 LOG_ALWAYS_FATAL("Unsupported colorType: %d", (int)colorType);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500230 }
231
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400232 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
233 "vkGetPhysicalDeviceImageFormatProperties2 is missing");
234 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
235 externalImageFormatInfo.sType =
236 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
237 externalImageFormatInfo.pNext = nullptr;
238 externalImageFormatInfo.handleType =
239 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400240
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400241 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
242 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
243 imageFormatInfo.pNext = &externalImageFormatInfo;
244 imageFormatInfo.format = vkPixelFormat;
245 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
246 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700247 // Currently Skia requires the images to be color attachments and support all transfer
248 // operations.
249 imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
250 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400251 imageFormatInfo.flags = 0;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400252
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400253 VkAndroidHardwareBufferUsageANDROID hwbUsage;
254 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
255 hwbUsage.pNext = nullptr;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400256
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400257 VkImageFormatProperties2 imgFormProps;
258 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
259 imgFormProps.pNext = &hwbUsage;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400260
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700261 VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
262 vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400263 if (VK_SUCCESS != res) {
264 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
Yiwei Zhang68daf672019-06-26 22:02:41 -0700265 return false;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400266 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500267
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400268 uint64_t consumerUsage;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700269 err = native_window_get_consumer_usage(window, &consumerUsage);
270 if (err != 0) {
271 ALOGE("native_window_get_consumer_usage failed: %s (%d)", strerror(-err), err);
272 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500273 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700274 outWindowInfo->windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500275
Yiwei Zhang68daf672019-06-26 22:02:41 -0700276 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500277}
278
279bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
280 ATRACE_CALL();
281
Alec Mouri45238012020-01-29 11:04:40 -0800282 int err = native_window_set_buffers_format(window, windowInfo.bufferFormat);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500283 if (err != 0) {
284 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
Alec Mouri45238012020-01-29 11:04:40 -0800285 windowInfo.bufferFormat, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500286 return false;
287 }
288
289 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
290 if (err != 0) {
291 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700292 "failed: %s (%d)",
293 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500294 return false;
295 }
296
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500297 // native_window_set_buffers_transform() expects the transform the app is requesting that
298 // the compositor perform during composition. With native windows, pre-transform works by
299 // rendering with the same transform the compositor is applying (as in Vulkan), but
300 // then requesting the inverse transform, so that when the compositor does
301 // it's job the two transforms cancel each other out and the compositor ends
302 // up applying an identity transform to the app's buffer.
303 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
304 if (err != 0) {
305 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700306 "failed: %s (%d)",
307 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500308 return false;
309 }
310
John Reckac513c22019-03-28 16:57:38 -0700311 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500312 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700313 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500314 windowInfo.bufferCount, strerror(-err), err);
315 return false;
316 }
317
318 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
319 if (err != 0) {
320 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
321 strerror(-err), err);
322 return false;
323 }
324
Yiwei Zhang68daf672019-06-26 22:02:41 -0700325 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500326}
327
328VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
Adlai Hollerd2345212020-10-07 14:16:40 -0400329 GrDirectContext* grContext)
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700330 : mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500331
332VulkanSurface::~VulkanSurface() {
333 releaseBuffers();
334
335 // release the native window to be available for use by other clients
336 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
337 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
338}
339
340void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700341 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500342 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
343
344 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
345 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
John Reckf0baa242021-05-13 18:14:45 -0400346 bufferInfo.dequeue_fence.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500347 if (err != 0) {
348 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
349 }
350 bufferInfo.dequeued = false;
John Reckf0baa242021-05-13 18:14:45 -0400351 bufferInfo.dequeue_fence.reset();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500352 }
353
354 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
John Reckf0baa242021-05-13 18:14:45 -0400355 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence.ok());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500356
357 bufferInfo.skSurface.reset();
358 bufferInfo.buffer.clear();
359 bufferInfo.hasValidContents = false;
360 bufferInfo.lastPresentedCount = 0;
361 }
362}
363
364VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400365 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500366 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400367 mCurrentBufferInfo = nullptr;
368
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700369 // Query the transform hint synced from the initial Surface connect or last queueBuffer. The
370 // auto prerotation on the buffer is based on the same transform hint in use by the producer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500371 int transformHint = 0;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700372 int err =
373 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500374
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700375 // Since auto pre-rotation is enabled, dequeueBuffer to get the consumer driven buffer size
376 // from ANativeWindowBuffer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500377 ANativeWindowBuffer* buffer;
John Reckf0baa242021-05-13 18:14:45 -0400378 base::unique_fd fence_fd;
379 {
380 int rawFd = -1;
381 err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &rawFd);
382 fence_fd.reset(rawFd);
383 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500384 if (err != 0) {
385 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
386 return nullptr;
387 }
388
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700389 SkISize actualSize = SkISize::Make(buffer->width, buffer->height);
390 if (actualSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
391 if (actualSize != mWindowInfo.actualSize) {
392 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
393 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
394 mWindowInfo.actualSize = actualSize;
395 releaseBuffers();
396 }
397
398 if (transformHint != mWindowInfo.transform) {
399 err = native_window_set_buffers_transform(mNativeWindow.get(),
400 InvertTransform(transformHint));
401 if (err != 0) {
402 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", transformHint,
403 strerror(-err), err);
John Reckf0baa242021-05-13 18:14:45 -0400404 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700405 return nullptr;
406 }
407 mWindowInfo.transform = transformHint;
408 }
409
410 mWindowInfo.size = actualSize;
411 if (mWindowInfo.transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
412 mWindowInfo.size.set(actualSize.height(), actualSize.width());
413 }
414
415 mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
416 }
417
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500418 uint32_t idx;
419 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
420 if (mNativeBuffers[idx].buffer.get() == buffer) {
421 mNativeBuffers[idx].dequeued = true;
John Reckf0baa242021-05-13 18:14:45 -0400422 mNativeBuffers[idx].dequeue_fence = std::move(fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500423 break;
424 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
425 // increasing the number of buffers we have allocated
426 mNativeBuffers[idx].buffer = buffer;
427 mNativeBuffers[idx].dequeued = true;
John Reckf0baa242021-05-13 18:14:45 -0400428 mNativeBuffers[idx].dequeue_fence = std::move(fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500429 break;
430 }
431 }
432 if (idx == mWindowInfo.bufferCount) {
433 ALOGE("dequeueBuffer returned unrecognized buffer");
John Reckf0baa242021-05-13 18:14:45 -0400434 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500435 return nullptr;
436 }
437
438 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
439
440 if (bufferInfo->skSurface.get() == nullptr) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700441 bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
442 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
Vasiliy Telezhnikov372a21b2021-11-17 13:50:56 -0500443 kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, nullptr, /*from_window=*/true);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500444 if (bufferInfo->skSurface.get() == nullptr) {
445 ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
Greg Danielffc50c62021-06-08 14:24:06 -0400446 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer,
447 mNativeBuffers[idx].dequeue_fence.release());
448 mNativeBuffers[idx].dequeued = false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500449 return nullptr;
450 }
451 }
452
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400453 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500454 return bufferInfo;
455}
456
457bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
458 if (!dirtyRect.isEmpty()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500459
John Reck321d8e52019-04-12 13:06:11 -0700460 // native_window_set_surface_damage takes a rectangle in prerotated space
461 // with a bottom-left origin. That is, top > bottom.
462 // The dirtyRect is also in prerotated space, so we just need to switch it to
463 // a bottom-left origin space.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500464
John Reck321d8e52019-04-12 13:06:11 -0700465 SkIRect irect;
466 dirtyRect.roundOut(&irect);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500467 android_native_rect_t aRect;
John Reck321d8e52019-04-12 13:06:11 -0700468 aRect.left = irect.left();
469 aRect.top = logicalHeight() - irect.top();
470 aRect.right = irect.right();
471 aRect.bottom = logicalHeight() - irect.bottom();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500472
473 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
474 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
475 }
476
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400477 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
478 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
John Reckf0baa242021-05-13 18:14:45 -0400479 // queueBuffer always closes fence, even on error
480 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence.release();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500481 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
482
483 currentBuffer.dequeued = false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500484 if (err != 0) {
485 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
John Reckf0baa242021-05-13 18:14:45 -0400486 // cancelBuffer takes ownership of the fence
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500487 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
John Reckf0baa242021-05-13 18:14:45 -0400488 currentBuffer.dequeue_fence.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500489 } else {
490 currentBuffer.hasValidContents = true;
491 currentBuffer.lastPresentedCount = mPresentCount;
492 mPresentCount++;
493 }
494
John Reckf0baa242021-05-13 18:14:45 -0400495 currentBuffer.dequeue_fence.reset();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500496
497 return err == 0;
498}
499
500int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400501 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
502 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500503 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
504}
505
John Reck55887762023-01-25 16:51:18 -0500506void VulkanSurface::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
507 mWindowInfo.colorspace = std::move(colorSpace);
508 for (int i = 0; i < kNumBufferSlots; i++) {
509 mNativeBuffers[i].skSurface.reset();
510 }
511
John Reck0b3f3312023-01-31 16:21:28 -0500512 if (mWindowInfo.colorMode == ColorMode::Hdr || mWindowInfo.colorMode == ColorMode::Hdr10) {
John Reck55887762023-01-25 16:51:18 -0500513 mWindowInfo.dataspace =
514 static_cast<android_dataspace>(STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_EXTENDED);
515 } else {
516 mWindowInfo.dataspace = ColorSpaceToADataSpace(
517 mWindowInfo.colorspace.get(), BufferFormatToColorType(mWindowInfo.bufferFormat));
518 }
519 LOG_ALWAYS_FATAL_IF(mWindowInfo.dataspace == HAL_DATASPACE_UNKNOWN &&
520 mWindowInfo.bufferFormat != AHARDWAREBUFFER_FORMAT_R8_UNORM,
521 "Unsupported colorspace");
522
523 if (mNativeWindow) {
John Reck0b3f3312023-01-31 16:21:28 -0500524 int err = ANativeWindow_setBuffersDataSpace(mNativeWindow.get(), mWindowInfo.dataspace);
John Reck55887762023-01-25 16:51:18 -0500525 if (err != 0) {
526 ALOGE("VulkanSurface::setColorSpace() native_window_set_buffers_data_space(%d) "
527 "failed: %s (%d)",
528 mWindowInfo.dataspace, strerror(-err), err);
529 }
530 }
531}
532
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500533} /* namespace renderthread */
534} /* namespace uirenderer */
535} /* namespace android */