blob: 20c2b1acaf02abe5a1919316054ba22d47cce365 [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>
Nolan Scobie572d8012024-08-30 13:43:34 -040020#include <gui/TraceUtils.h>
21#include <include/android/SkSurfaceAndroid.h>
22#include <include/gpu/ganesh/GrDirectContext.h>
23
John Reck0fa0cbc2019-04-05 16:57:46 -070024#include <algorithm>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050025
26#include "VulkanManager.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050027#include "utils/Color.h"
28
29namespace android {
30namespace uirenderer {
31namespace renderthread {
32
John Reck4bd8d8a2023-12-08 11:27:19 -050033static constexpr auto P3_XRB = static_cast<android_dataspace>(
34 ADATASPACE_STANDARD_DCI_P3 | ADATASPACE_TRANSFER_SRGB | ADATASPACE_RANGE_EXTENDED);
35
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050036static int InvertTransform(int transform) {
37 switch (transform) {
Alec Mouria5a0c962019-12-10 15:10:14 -080038 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
39 return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
40 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
41 return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
42 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
43 return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050044 default:
45 return 0;
46 }
47}
48
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050049static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
50 const int width = windowSize.width();
51 const int height = windowSize.height();
52
53 switch (transform) {
54 case 0:
55 return SkMatrix::I();
Alec Mouria5a0c962019-12-10 15:10:14 -080056 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050057 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080058 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050059 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080060 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050061 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
62 default:
63 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
64 }
65 return SkMatrix::I();
66}
67
John Reckee184272023-03-21 12:29:21 -040068static SkM44 GetPixelSnapMatrix(SkISize windowSize, int transform) {
69 // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
70 // desired fragment
71 static const SkScalar kOffset = 0.063f;
72 SkMatrix preRotation = GetPreTransformMatrix(windowSize, transform);
73 SkMatrix invert;
74 LOG_ALWAYS_FATAL_IF(!preRotation.invert(&invert));
75 return SkM44::Translate(kOffset, kOffset)
76 .postConcat(SkM44(preRotation))
77 .preConcat(SkM44(invert));
78}
79
Yiwei Zhang68daf672019-06-26 22:02:41 -070080static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
81 ATRACE_CALL();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050082
83 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
84 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070085 ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050086 return false;
87 }
88
89 // this will match what we do on GL so pick that here.
90 err = window->setSwapInterval(window, 1);
91 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070092 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050093 return false;
94 }
95
96 err = native_window_set_shared_buffer_mode(window, false);
97 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070098 ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050099 return false;
100 }
101
102 err = native_window_set_auto_refresh(window, false);
103 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700104 ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
105 return false;
106 }
107
108 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
109 if (err != 0) {
110 ALOGE("native_window_set_scaling_mode(NATIVE_WINDOW_SCALING_MODE_FREEZE) failed: %s (%d)",
111 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500112 return false;
113 }
114
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700115 // Let consumer drive the size of the buffers.
116 err = native_window_set_buffers_dimensions(window, 0, 0);
117 if (err != 0) {
118 ALOGE("native_window_set_buffers_dimensions(0,0) failed: %s (%d)", strerror(-err), err);
119 return false;
120 }
121
122 // Enable auto prerotation, so when buffer size is driven by the consumer
123 // and the transform hint specifies a 90 or 270 degree rotation, the width
124 // and height used for buffer pre-allocation and dequeueBuffer will be
125 // additionally swapped.
126 err = native_window_set_auto_prerotation(window, true);
127 if (err != 0) {
128 ALOGE("VulkanSurface::UpdateWindow() native_window_set_auto_prerotation failed: %s (%d)",
129 strerror(-err), err);
130 return false;
131 }
132
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500133 return true;
134}
135
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500136VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700137 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
Adlai Hollerd2345212020-10-07 14:16:40 -0400138 GrDirectContext* grContext, const VulkanManager& vkManager,
John Reck0fa0cbc2019-04-05 16:57:46 -0700139 uint32_t extraBuffers) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700140 // Connect and set native window to default configurations.
141 if (!ConnectAndSetWindowDefaults(window)) {
142 return nullptr;
143 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500144
Yiwei Zhang68daf672019-06-26 22:02:41 -0700145 // Initialize WindowInfo struct.
146 WindowInfo windowInfo;
147 if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700148 extraBuffers, &windowInfo)) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700149 return nullptr;
150 }
151
152 // Now we attempt to modify the window.
153 if (!UpdateWindow(window, windowInfo)) {
154 return nullptr;
155 }
156
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700157 return new VulkanSurface(window, windowInfo, grContext);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700158}
159
160bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
161 SkColorType colorType,
162 sk_sp<SkColorSpace> colorSpace,
163 const VulkanManager& vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700164 uint32_t extraBuffers, WindowInfo* outWindowInfo) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700165 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 Zhangdab6ecd2019-06-27 12:22:33 -0700188 outWindowInfo->actualSize = outWindowInfo->size;
Alec Mouria5a0c962019-12-10 15:10:14 -0800189 if (outWindowInfo->transform & ANATIVEWINDOW_TRANSFORM_ROTATE_90) {
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700190 outWindowInfo->actualSize.set(outWindowInfo->size.height(), outWindowInfo->size.width());
191 }
192
193 outWindowInfo->preTransform =
194 GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
John Reckee184272023-03-21 12:29:21 -0400195 outWindowInfo->pixelSnapMatrix =
196 GetPixelSnapMatrix(outWindowInfo->size, outWindowInfo->transform);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700197
198 err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &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;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500202 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700203 outWindowInfo->bufferCount =
204 static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500205
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700206 err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
207 if (err != 0 || query_value < 0) {
208 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700209 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700210 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700211 if (outWindowInfo->bufferCount > static_cast<uint32_t>(query_value)) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700212 // Application must settle for fewer images than desired:
Yiwei Zhang68daf672019-06-26 22:02:41 -0700213 outWindowInfo->bufferCount = static_cast<uint32_t>(query_value);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700214 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500215
Alec Mouri45238012020-01-29 11:04:40 -0800216 outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400217 outWindowInfo->colorspace = colorSpace;
John Reck55887762023-01-25 16:51:18 -0500218 outWindowInfo->colorMode = colorMode;
219
John Reck0b3f3312023-01-31 16:21:28 -0500220 if (colorMode == ColorMode::Hdr || colorMode == ColorMode::Hdr10) {
John Reck4bd8d8a2023-12-08 11:27:19 -0500221 outWindowInfo->dataspace = P3_XRB;
John Reck55887762023-01-25 16:51:18 -0500222 } else {
223 outWindowInfo->dataspace = ColorSpaceToADataSpace(colorSpace.get(), colorType);
224 }
Leon Scroggins III7ccb8a42021-11-30 14:17:28 -0500225 LOG_ALWAYS_FATAL_IF(
226 outWindowInfo->dataspace == HAL_DATASPACE_UNKNOWN && colorType != kAlpha_8_SkColorType,
227 "Unsupported colorspace");
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400228
229 VkFormat vkPixelFormat;
230 switch (colorType) {
231 case kRGBA_8888_SkColorType:
232 vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
233 break;
234 case kRGBA_F16_SkColorType:
235 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
236 break;
237 case kRGBA_1010102_SkColorType:
238 vkPixelFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
239 break;
Leon Scroggins III7ccb8a42021-11-30 14:17:28 -0500240 case kAlpha_8_SkColorType:
241 vkPixelFormat = VK_FORMAT_R8_UNORM;
242 break;
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400243 default:
244 LOG_ALWAYS_FATAL("Unsupported colorType: %d", (int)colorType);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500245 }
246
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400247 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
248 "vkGetPhysicalDeviceImageFormatProperties2 is missing");
249 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
250 externalImageFormatInfo.sType =
251 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
252 externalImageFormatInfo.pNext = nullptr;
253 externalImageFormatInfo.handleType =
254 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400255
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400256 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
257 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
258 imageFormatInfo.pNext = &externalImageFormatInfo;
259 imageFormatInfo.format = vkPixelFormat;
260 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
261 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700262 // Currently Skia requires the images to be color attachments and support all transfer
263 // operations.
264 imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
265 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400266 imageFormatInfo.flags = 0;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400267
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400268 VkAndroidHardwareBufferUsageANDROID hwbUsage;
269 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
270 hwbUsage.pNext = nullptr;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400271
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400272 VkImageFormatProperties2 imgFormProps;
273 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
274 imgFormProps.pNext = &hwbUsage;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400275
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700276 VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
277 vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400278 if (VK_SUCCESS != res) {
279 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
Yiwei Zhang68daf672019-06-26 22:02:41 -0700280 return false;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400281 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500282
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400283 uint64_t consumerUsage;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700284 err = native_window_get_consumer_usage(window, &consumerUsage);
285 if (err != 0) {
286 ALOGE("native_window_get_consumer_usage failed: %s (%d)", strerror(-err), err);
287 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500288 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700289 outWindowInfo->windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500290
Yiwei Zhang68daf672019-06-26 22:02:41 -0700291 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500292}
293
294bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
295 ATRACE_CALL();
296
Alec Mouri45238012020-01-29 11:04:40 -0800297 int err = native_window_set_buffers_format(window, windowInfo.bufferFormat);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500298 if (err != 0) {
299 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
Alec Mouri45238012020-01-29 11:04:40 -0800300 windowInfo.bufferFormat, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500301 return false;
302 }
303
304 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
305 if (err != 0) {
306 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700307 "failed: %s (%d)",
308 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500309 return false;
310 }
311
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500312 // native_window_set_buffers_transform() expects the transform the app is requesting that
313 // the compositor perform during composition. With native windows, pre-transform works by
314 // rendering with the same transform the compositor is applying (as in Vulkan), but
315 // then requesting the inverse transform, so that when the compositor does
316 // it's job the two transforms cancel each other out and the compositor ends
317 // up applying an identity transform to the app's buffer.
318 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
319 if (err != 0) {
320 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700321 "failed: %s (%d)",
322 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500323 return false;
324 }
325
John Reck1391d8e2024-04-26 15:31:37 -0400326 // If bufferCount == 1 then we're in shared buffer mode and we cannot actually call
327 // set_buffer_count, it'll just fail.
328 if (windowInfo.bufferCount > 1) {
329 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
330 if (err != 0) {
331 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s "
332 "(%d)",
333 windowInfo.bufferCount, strerror(-err), err);
334 return false;
335 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500336 }
337
338 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
339 if (err != 0) {
340 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
341 strerror(-err), err);
342 return false;
343 }
344
Yiwei Zhang68daf672019-06-26 22:02:41 -0700345 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500346}
347
348VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
Adlai Hollerd2345212020-10-07 14:16:40 -0400349 GrDirectContext* grContext)
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700350 : mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500351
352VulkanSurface::~VulkanSurface() {
353 releaseBuffers();
354
355 // release the native window to be available for use by other clients
356 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
357 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
358}
359
360void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700361 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500362 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
363
364 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
365 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
John Reckf0baa242021-05-13 18:14:45 -0400366 bufferInfo.dequeue_fence.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500367 if (err != 0) {
368 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
369 }
370 bufferInfo.dequeued = false;
John Reckf0baa242021-05-13 18:14:45 -0400371 bufferInfo.dequeue_fence.reset();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500372 }
373
374 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
John Reckf0baa242021-05-13 18:14:45 -0400375 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence.ok());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500376
377 bufferInfo.skSurface.reset();
378 bufferInfo.buffer.clear();
379 bufferInfo.hasValidContents = false;
380 bufferInfo.lastPresentedCount = 0;
381 }
382}
383
John Reck61c64472023-05-04 11:29:45 -0400384void VulkanSurface::invalidateBuffers() {
385 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
386 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
387 bufferInfo.hasValidContents = false;
388 bufferInfo.lastPresentedCount = 0;
389 }
390}
391
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500392VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400393 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500394 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400395 mCurrentBufferInfo = nullptr;
396
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700397 // Query the transform hint synced from the initial Surface connect or last queueBuffer. The
398 // auto prerotation on the buffer is based on the same transform hint in use by the producer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500399 int transformHint = 0;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700400 int err =
401 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500402
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700403 // Since auto pre-rotation is enabled, dequeueBuffer to get the consumer driven buffer size
404 // from ANativeWindowBuffer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500405 ANativeWindowBuffer* buffer;
John Reckf0baa242021-05-13 18:14:45 -0400406 base::unique_fd fence_fd;
407 {
408 int rawFd = -1;
409 err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &rawFd);
410 fence_fd.reset(rawFd);
411 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500412 if (err != 0) {
413 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
414 return nullptr;
415 }
416
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700417 SkISize actualSize = SkISize::Make(buffer->width, buffer->height);
418 if (actualSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
419 if (actualSize != mWindowInfo.actualSize) {
420 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
421 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
422 mWindowInfo.actualSize = actualSize;
423 releaseBuffers();
John Reck61c64472023-05-04 11:29:45 -0400424 } else {
425 // A change in transform means we need to repaint the entire buffer area as the damage
426 // rects have just moved about.
427 invalidateBuffers();
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700428 }
429
430 if (transformHint != mWindowInfo.transform) {
431 err = native_window_set_buffers_transform(mNativeWindow.get(),
432 InvertTransform(transformHint));
433 if (err != 0) {
434 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", transformHint,
435 strerror(-err), err);
John Reckf0baa242021-05-13 18:14:45 -0400436 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700437 return nullptr;
438 }
439 mWindowInfo.transform = transformHint;
440 }
441
442 mWindowInfo.size = actualSize;
443 if (mWindowInfo.transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
444 mWindowInfo.size.set(actualSize.height(), actualSize.width());
445 }
446
447 mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
John Reckee184272023-03-21 12:29:21 -0400448 mWindowInfo.pixelSnapMatrix = GetPixelSnapMatrix(mWindowInfo.size, mWindowInfo.transform);
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700449 }
450
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500451 uint32_t idx;
452 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
453 if (mNativeBuffers[idx].buffer.get() == buffer) {
454 mNativeBuffers[idx].dequeued = true;
John Reckf0baa242021-05-13 18:14:45 -0400455 mNativeBuffers[idx].dequeue_fence = std::move(fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500456 break;
457 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
458 // increasing the number of buffers we have allocated
459 mNativeBuffers[idx].buffer = buffer;
460 mNativeBuffers[idx].dequeued = true;
John Reckf0baa242021-05-13 18:14:45 -0400461 mNativeBuffers[idx].dequeue_fence = std::move(fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500462 break;
463 }
464 }
465 if (idx == mWindowInfo.bufferCount) {
466 ALOGE("dequeueBuffer returned unrecognized buffer");
John Reckf0baa242021-05-13 18:14:45 -0400467 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500468 return nullptr;
469 }
470
471 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
472
473 if (bufferInfo->skSurface.get() == nullptr) {
John Reckb026f352023-04-05 13:19:15 -0400474 SkSurfaceProps surfaceProps;
475 if (mWindowInfo.colorMode != ColorMode::Default) {
476 surfaceProps = SkSurfaceProps(SkSurfaceProps::kAlwaysDither_Flag | surfaceProps.flags(),
477 surfaceProps.pixelGeometry());
478 }
Kevin Lubick6817fc42023-05-12 19:27:20 +0000479 bufferInfo->skSurface = SkSurfaces::WrapAndroidHardwareBuffer(
John Reck0fa0cbc2019-04-05 16:57:46 -0700480 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
John Reckb026f352023-04-05 13:19:15 -0400481 kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, &surfaceProps,
482 /*from_window=*/true);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500483 if (bufferInfo->skSurface.get() == nullptr) {
Kevin Lubick6817fc42023-05-12 19:27:20 +0000484 ALOGE("SkSurfaces::WrapAndroidHardwareBuffer failed");
Greg Danielffc50c62021-06-08 14:24:06 -0400485 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer,
486 mNativeBuffers[idx].dequeue_fence.release());
487 mNativeBuffers[idx].dequeued = false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500488 return nullptr;
489 }
490 }
491
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400492 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500493 return bufferInfo;
494}
495
496bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
497 if (!dirtyRect.isEmpty()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500498
John Reck321d8e52019-04-12 13:06:11 -0700499 // native_window_set_surface_damage takes a rectangle in prerotated space
500 // with a bottom-left origin. That is, top > bottom.
501 // The dirtyRect is also in prerotated space, so we just need to switch it to
502 // a bottom-left origin space.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500503
John Reck321d8e52019-04-12 13:06:11 -0700504 SkIRect irect;
505 dirtyRect.roundOut(&irect);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500506 android_native_rect_t aRect;
John Reck321d8e52019-04-12 13:06:11 -0700507 aRect.left = irect.left();
508 aRect.top = logicalHeight() - irect.top();
509 aRect.right = irect.right();
510 aRect.bottom = logicalHeight() - irect.bottom();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500511
512 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
513 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
514 }
515
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400516 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
517 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
John Reckf0baa242021-05-13 18:14:45 -0400518 // queueBuffer always closes fence, even on error
519 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence.release();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500520 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
521
522 currentBuffer.dequeued = false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500523 if (err != 0) {
524 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
John Reckf0baa242021-05-13 18:14:45 -0400525 // cancelBuffer takes ownership of the fence
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500526 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
John Reckf0baa242021-05-13 18:14:45 -0400527 currentBuffer.dequeue_fence.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500528 } else {
529 currentBuffer.hasValidContents = true;
530 currentBuffer.lastPresentedCount = mPresentCount;
531 mPresentCount++;
532 }
533
John Reckf0baa242021-05-13 18:14:45 -0400534 currentBuffer.dequeue_fence.reset();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500535
536 return err == 0;
537}
538
539int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400540 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
541 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500542 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
543}
544
John Reck55887762023-01-25 16:51:18 -0500545void VulkanSurface::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
546 mWindowInfo.colorspace = std::move(colorSpace);
547 for (int i = 0; i < kNumBufferSlots; i++) {
548 mNativeBuffers[i].skSurface.reset();
549 }
550
John Reck0b3f3312023-01-31 16:21:28 -0500551 if (mWindowInfo.colorMode == ColorMode::Hdr || mWindowInfo.colorMode == ColorMode::Hdr10) {
John Reck4bd8d8a2023-12-08 11:27:19 -0500552 mWindowInfo.dataspace = P3_XRB;
John Reck55887762023-01-25 16:51:18 -0500553 } else {
554 mWindowInfo.dataspace = ColorSpaceToADataSpace(
555 mWindowInfo.colorspace.get(), BufferFormatToColorType(mWindowInfo.bufferFormat));
556 }
557 LOG_ALWAYS_FATAL_IF(mWindowInfo.dataspace == HAL_DATASPACE_UNKNOWN &&
558 mWindowInfo.bufferFormat != AHARDWAREBUFFER_FORMAT_R8_UNORM,
559 "Unsupported colorspace");
560
561 if (mNativeWindow) {
John Reck0b3f3312023-01-31 16:21:28 -0500562 int err = ANativeWindow_setBuffersDataSpace(mNativeWindow.get(), mWindowInfo.dataspace);
John Reck55887762023-01-25 16:51:18 -0500563 if (err != 0) {
564 ALOGE("VulkanSurface::setColorSpace() native_window_set_buffers_data_space(%d) "
565 "failed: %s (%d)",
566 mWindowInfo.dataspace, strerror(-err), err);
567 }
568 }
569}
570
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500571} /* namespace renderthread */
572} /* namespace uirenderer */
573} /* namespace android */