blob: 20b743bab2c2bf137ef4064fa1e16a0c909663bf [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
Kevin Lubick6817fc42023-05-12 19:27:20 +000019#include <include/android/SkSurfaceAndroid.h>
Adlai Hollerd2345212020-10-07 14:16:40 -040020#include <GrDirectContext.h>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050021#include <SkSurface.h>
John Reck0fa0cbc2019-04-05 16:57:46 -070022#include <algorithm>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050023
rnleece9762b2021-05-21 15:40:53 -070024#include <gui/TraceUtils.h>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050025#include "VulkanManager.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050026#include "utils/Color.h"
27
28namespace android {
29namespace uirenderer {
30namespace renderthread {
31
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050032static int InvertTransform(int transform) {
33 switch (transform) {
Alec Mouria5a0c962019-12-10 15:10:14 -080034 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
35 return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
36 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
37 return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
38 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
39 return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050040 default:
41 return 0;
42 }
43}
44
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050045static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
46 const int width = windowSize.width();
47 const int height = windowSize.height();
48
49 switch (transform) {
50 case 0:
51 return SkMatrix::I();
Alec Mouria5a0c962019-12-10 15:10:14 -080052 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050053 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080054 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050055 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080056 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050057 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
58 default:
59 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
60 }
61 return SkMatrix::I();
62}
63
John Reckee184272023-03-21 12:29:21 -040064static SkM44 GetPixelSnapMatrix(SkISize windowSize, int transform) {
65 // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
66 // desired fragment
67 static const SkScalar kOffset = 0.063f;
68 SkMatrix preRotation = GetPreTransformMatrix(windowSize, transform);
69 SkMatrix invert;
70 LOG_ALWAYS_FATAL_IF(!preRotation.invert(&invert));
71 return SkM44::Translate(kOffset, kOffset)
72 .postConcat(SkM44(preRotation))
73 .preConcat(SkM44(invert));
74}
75
Yiwei Zhang68daf672019-06-26 22:02:41 -070076static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
77 ATRACE_CALL();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050078
79 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
80 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070081 ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050082 return false;
83 }
84
85 // this will match what we do on GL so pick that here.
86 err = window->setSwapInterval(window, 1);
87 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070088 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050089 return false;
90 }
91
92 err = native_window_set_shared_buffer_mode(window, false);
93 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070094 ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050095 return false;
96 }
97
98 err = native_window_set_auto_refresh(window, false);
99 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700100 ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
101 return false;
102 }
103
104 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
105 if (err != 0) {
106 ALOGE("native_window_set_scaling_mode(NATIVE_WINDOW_SCALING_MODE_FREEZE) failed: %s (%d)",
107 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500108 return false;
109 }
110
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700111 // Let consumer drive the size of the buffers.
112 err = native_window_set_buffers_dimensions(window, 0, 0);
113 if (err != 0) {
114 ALOGE("native_window_set_buffers_dimensions(0,0) failed: %s (%d)", strerror(-err), err);
115 return false;
116 }
117
118 // Enable auto prerotation, so when buffer size is driven by the consumer
119 // and the transform hint specifies a 90 or 270 degree rotation, the width
120 // and height used for buffer pre-allocation and dequeueBuffer will be
121 // additionally swapped.
122 err = native_window_set_auto_prerotation(window, true);
123 if (err != 0) {
124 ALOGE("VulkanSurface::UpdateWindow() native_window_set_auto_prerotation failed: %s (%d)",
125 strerror(-err), err);
126 return false;
127 }
128
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500129 return true;
130}
131
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500132VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700133 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
Adlai Hollerd2345212020-10-07 14:16:40 -0400134 GrDirectContext* grContext, const VulkanManager& vkManager,
John Reck0fa0cbc2019-04-05 16:57:46 -0700135 uint32_t extraBuffers) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700136 // Connect and set native window to default configurations.
137 if (!ConnectAndSetWindowDefaults(window)) {
138 return nullptr;
139 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500140
Yiwei Zhang68daf672019-06-26 22:02:41 -0700141 // Initialize WindowInfo struct.
142 WindowInfo windowInfo;
143 if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700144 extraBuffers, &windowInfo)) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700145 return nullptr;
146 }
147
148 // Now we attempt to modify the window.
149 if (!UpdateWindow(window, windowInfo)) {
150 return nullptr;
151 }
152
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700153 return new VulkanSurface(window, windowInfo, grContext);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700154}
155
156bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
157 SkColorType colorType,
158 sk_sp<SkColorSpace> colorSpace,
159 const VulkanManager& vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700160 uint32_t extraBuffers, WindowInfo* outWindowInfo) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700161 ATRACE_CALL();
162
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700163 int width, height;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700164 int err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700165 if (err != 0 || width < 0) {
166 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, width);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700167 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700168 }
169 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
170 if (err != 0 || height < 0) {
171 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, height);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700172 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700173 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700174 outWindowInfo->size = SkISize::Make(width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500175
John Reckac513c22019-03-28 16:57:38 -0700176 int query_value;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700177 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &query_value);
John Reckac513c22019-03-28 16:57:38 -0700178 if (err != 0 || query_value < 0) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700179 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700180 return false;
John Reckac513c22019-03-28 16:57:38 -0700181 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700182 outWindowInfo->transform = query_value;
John Reckac513c22019-03-28 16:57:38 -0700183
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700184 outWindowInfo->actualSize = outWindowInfo->size;
Alec Mouria5a0c962019-12-10 15:10:14 -0800185 if (outWindowInfo->transform & ANATIVEWINDOW_TRANSFORM_ROTATE_90) {
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700186 outWindowInfo->actualSize.set(outWindowInfo->size.height(), outWindowInfo->size.width());
187 }
188
189 outWindowInfo->preTransform =
190 GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
John Reckee184272023-03-21 12:29:21 -0400191 outWindowInfo->pixelSnapMatrix =
192 GetPixelSnapMatrix(outWindowInfo->size, outWindowInfo->transform);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700193
194 err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
195 if (err != 0 || query_value < 0) {
196 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700197 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500198 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700199 outWindowInfo->bufferCount =
200 static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500201
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700202 err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
203 if (err != 0 || query_value < 0) {
204 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700205 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700206 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700207 if (outWindowInfo->bufferCount > static_cast<uint32_t>(query_value)) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700208 // Application must settle for fewer images than desired:
Yiwei Zhang68daf672019-06-26 22:02:41 -0700209 outWindowInfo->bufferCount = static_cast<uint32_t>(query_value);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700210 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500211
Alec Mouri45238012020-01-29 11:04:40 -0800212 outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400213 outWindowInfo->colorspace = colorSpace;
John Reck55887762023-01-25 16:51:18 -0500214 outWindowInfo->colorMode = colorMode;
215
John Reck0b3f3312023-01-31 16:21:28 -0500216 if (colorMode == ColorMode::Hdr || colorMode == ColorMode::Hdr10) {
John Reck55887762023-01-25 16:51:18 -0500217 outWindowInfo->dataspace =
218 static_cast<android_dataspace>(STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_EXTENDED);
219 } else {
220 outWindowInfo->dataspace = ColorSpaceToADataSpace(colorSpace.get(), colorType);
221 }
Leon Scroggins III7ccb8a42021-11-30 14:17:28 -0500222 LOG_ALWAYS_FATAL_IF(
223 outWindowInfo->dataspace == HAL_DATASPACE_UNKNOWN && colorType != kAlpha_8_SkColorType,
224 "Unsupported colorspace");
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400225
226 VkFormat vkPixelFormat;
227 switch (colorType) {
228 case kRGBA_8888_SkColorType:
229 vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
230 break;
231 case kRGBA_F16_SkColorType:
232 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
233 break;
234 case kRGBA_1010102_SkColorType:
235 vkPixelFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
236 break;
Leon Scroggins III7ccb8a42021-11-30 14:17:28 -0500237 case kAlpha_8_SkColorType:
238 vkPixelFormat = VK_FORMAT_R8_UNORM;
239 break;
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400240 default:
241 LOG_ALWAYS_FATAL("Unsupported colorType: %d", (int)colorType);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500242 }
243
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400244 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
245 "vkGetPhysicalDeviceImageFormatProperties2 is missing");
246 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
247 externalImageFormatInfo.sType =
248 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
249 externalImageFormatInfo.pNext = nullptr;
250 externalImageFormatInfo.handleType =
251 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400252
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400253 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
254 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
255 imageFormatInfo.pNext = &externalImageFormatInfo;
256 imageFormatInfo.format = vkPixelFormat;
257 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
258 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700259 // Currently Skia requires the images to be color attachments and support all transfer
260 // operations.
261 imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
262 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400263 imageFormatInfo.flags = 0;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400264
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400265 VkAndroidHardwareBufferUsageANDROID hwbUsage;
266 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
267 hwbUsage.pNext = nullptr;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400268
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400269 VkImageFormatProperties2 imgFormProps;
270 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
271 imgFormProps.pNext = &hwbUsage;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400272
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700273 VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
274 vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400275 if (VK_SUCCESS != res) {
276 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
Yiwei Zhang68daf672019-06-26 22:02:41 -0700277 return false;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400278 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500279
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400280 uint64_t consumerUsage;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700281 err = native_window_get_consumer_usage(window, &consumerUsage);
282 if (err != 0) {
283 ALOGE("native_window_get_consumer_usage failed: %s (%d)", strerror(-err), err);
284 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500285 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700286 outWindowInfo->windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500287
Yiwei Zhang68daf672019-06-26 22:02:41 -0700288 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500289}
290
291bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
292 ATRACE_CALL();
293
Alec Mouri45238012020-01-29 11:04:40 -0800294 int err = native_window_set_buffers_format(window, windowInfo.bufferFormat);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500295 if (err != 0) {
296 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
Alec Mouri45238012020-01-29 11:04:40 -0800297 windowInfo.bufferFormat, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500298 return false;
299 }
300
301 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
302 if (err != 0) {
303 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700304 "failed: %s (%d)",
305 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500306 return false;
307 }
308
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500309 // native_window_set_buffers_transform() expects the transform the app is requesting that
310 // the compositor perform during composition. With native windows, pre-transform works by
311 // rendering with the same transform the compositor is applying (as in Vulkan), but
312 // then requesting the inverse transform, so that when the compositor does
313 // it's job the two transforms cancel each other out and the compositor ends
314 // up applying an identity transform to the app's buffer.
315 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
316 if (err != 0) {
317 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700318 "failed: %s (%d)",
319 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500320 return false;
321 }
322
John Reckac513c22019-03-28 16:57:38 -0700323 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500324 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700325 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500326 windowInfo.bufferCount, strerror(-err), err);
327 return false;
328 }
329
330 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
331 if (err != 0) {
332 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
333 strerror(-err), err);
334 return false;
335 }
336
Yiwei Zhang68daf672019-06-26 22:02:41 -0700337 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500338}
339
340VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
Adlai Hollerd2345212020-10-07 14:16:40 -0400341 GrDirectContext* grContext)
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700342 : mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500343
344VulkanSurface::~VulkanSurface() {
345 releaseBuffers();
346
347 // release the native window to be available for use by other clients
348 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
349 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
350}
351
352void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700353 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500354 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
355
356 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
357 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
John Reckf0baa242021-05-13 18:14:45 -0400358 bufferInfo.dequeue_fence.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500359 if (err != 0) {
360 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
361 }
362 bufferInfo.dequeued = false;
John Reckf0baa242021-05-13 18:14:45 -0400363 bufferInfo.dequeue_fence.reset();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500364 }
365
366 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
John Reckf0baa242021-05-13 18:14:45 -0400367 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence.ok());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500368
369 bufferInfo.skSurface.reset();
370 bufferInfo.buffer.clear();
371 bufferInfo.hasValidContents = false;
372 bufferInfo.lastPresentedCount = 0;
373 }
374}
375
John Reck61c64472023-05-04 11:29:45 -0400376void VulkanSurface::invalidateBuffers() {
377 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
378 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
379 bufferInfo.hasValidContents = false;
380 bufferInfo.lastPresentedCount = 0;
381 }
382}
383
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500384VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400385 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500386 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400387 mCurrentBufferInfo = nullptr;
388
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700389 // Query the transform hint synced from the initial Surface connect or last queueBuffer. The
390 // auto prerotation on the buffer is based on the same transform hint in use by the producer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500391 int transformHint = 0;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700392 int err =
393 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500394
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700395 // Since auto pre-rotation is enabled, dequeueBuffer to get the consumer driven buffer size
396 // from ANativeWindowBuffer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500397 ANativeWindowBuffer* buffer;
John Reckf0baa242021-05-13 18:14:45 -0400398 base::unique_fd fence_fd;
399 {
400 int rawFd = -1;
401 err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &rawFd);
402 fence_fd.reset(rawFd);
403 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500404 if (err != 0) {
405 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
406 return nullptr;
407 }
408
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700409 SkISize actualSize = SkISize::Make(buffer->width, buffer->height);
410 if (actualSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
411 if (actualSize != mWindowInfo.actualSize) {
412 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
413 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
414 mWindowInfo.actualSize = actualSize;
415 releaseBuffers();
John Reck61c64472023-05-04 11:29:45 -0400416 } else {
417 // A change in transform means we need to repaint the entire buffer area as the damage
418 // rects have just moved about.
419 invalidateBuffers();
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700420 }
421
422 if (transformHint != mWindowInfo.transform) {
423 err = native_window_set_buffers_transform(mNativeWindow.get(),
424 InvertTransform(transformHint));
425 if (err != 0) {
426 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", transformHint,
427 strerror(-err), err);
John Reckf0baa242021-05-13 18:14:45 -0400428 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700429 return nullptr;
430 }
431 mWindowInfo.transform = transformHint;
432 }
433
434 mWindowInfo.size = actualSize;
435 if (mWindowInfo.transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
436 mWindowInfo.size.set(actualSize.height(), actualSize.width());
437 }
438
439 mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
John Reckee184272023-03-21 12:29:21 -0400440 mWindowInfo.pixelSnapMatrix = GetPixelSnapMatrix(mWindowInfo.size, mWindowInfo.transform);
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700441 }
442
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500443 uint32_t idx;
444 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
445 if (mNativeBuffers[idx].buffer.get() == buffer) {
446 mNativeBuffers[idx].dequeued = true;
John Reckf0baa242021-05-13 18:14:45 -0400447 mNativeBuffers[idx].dequeue_fence = std::move(fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500448 break;
449 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
450 // increasing the number of buffers we have allocated
451 mNativeBuffers[idx].buffer = buffer;
452 mNativeBuffers[idx].dequeued = true;
John Reckf0baa242021-05-13 18:14:45 -0400453 mNativeBuffers[idx].dequeue_fence = std::move(fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500454 break;
455 }
456 }
457 if (idx == mWindowInfo.bufferCount) {
458 ALOGE("dequeueBuffer returned unrecognized buffer");
John Reckf0baa242021-05-13 18:14:45 -0400459 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500460 return nullptr;
461 }
462
463 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
464
465 if (bufferInfo->skSurface.get() == nullptr) {
John Reckb026f352023-04-05 13:19:15 -0400466 SkSurfaceProps surfaceProps;
467 if (mWindowInfo.colorMode != ColorMode::Default) {
468 surfaceProps = SkSurfaceProps(SkSurfaceProps::kAlwaysDither_Flag | surfaceProps.flags(),
469 surfaceProps.pixelGeometry());
470 }
Kevin Lubick6817fc42023-05-12 19:27:20 +0000471 bufferInfo->skSurface = SkSurfaces::WrapAndroidHardwareBuffer(
John Reck0fa0cbc2019-04-05 16:57:46 -0700472 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
John Reckb026f352023-04-05 13:19:15 -0400473 kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, &surfaceProps,
474 /*from_window=*/true);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500475 if (bufferInfo->skSurface.get() == nullptr) {
Kevin Lubick6817fc42023-05-12 19:27:20 +0000476 ALOGE("SkSurfaces::WrapAndroidHardwareBuffer failed");
Greg Danielffc50c62021-06-08 14:24:06 -0400477 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer,
478 mNativeBuffers[idx].dequeue_fence.release());
479 mNativeBuffers[idx].dequeued = false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500480 return nullptr;
481 }
482 }
483
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400484 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500485 return bufferInfo;
486}
487
488bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
489 if (!dirtyRect.isEmpty()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500490
John Reck321d8e52019-04-12 13:06:11 -0700491 // native_window_set_surface_damage takes a rectangle in prerotated space
492 // with a bottom-left origin. That is, top > bottom.
493 // The dirtyRect is also in prerotated space, so we just need to switch it to
494 // a bottom-left origin space.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500495
John Reck321d8e52019-04-12 13:06:11 -0700496 SkIRect irect;
497 dirtyRect.roundOut(&irect);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500498 android_native_rect_t aRect;
John Reck321d8e52019-04-12 13:06:11 -0700499 aRect.left = irect.left();
500 aRect.top = logicalHeight() - irect.top();
501 aRect.right = irect.right();
502 aRect.bottom = logicalHeight() - irect.bottom();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500503
504 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
505 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
506 }
507
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400508 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
509 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
John Reckf0baa242021-05-13 18:14:45 -0400510 // queueBuffer always closes fence, even on error
511 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence.release();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500512 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
513
514 currentBuffer.dequeued = false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500515 if (err != 0) {
516 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
John Reckf0baa242021-05-13 18:14:45 -0400517 // cancelBuffer takes ownership of the fence
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500518 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
John Reckf0baa242021-05-13 18:14:45 -0400519 currentBuffer.dequeue_fence.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500520 } else {
521 currentBuffer.hasValidContents = true;
522 currentBuffer.lastPresentedCount = mPresentCount;
523 mPresentCount++;
524 }
525
John Reckf0baa242021-05-13 18:14:45 -0400526 currentBuffer.dequeue_fence.reset();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500527
528 return err == 0;
529}
530
531int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400532 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
533 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500534 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
535}
536
John Reck55887762023-01-25 16:51:18 -0500537void VulkanSurface::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
538 mWindowInfo.colorspace = std::move(colorSpace);
539 for (int i = 0; i < kNumBufferSlots; i++) {
540 mNativeBuffers[i].skSurface.reset();
541 }
542
John Reck0b3f3312023-01-31 16:21:28 -0500543 if (mWindowInfo.colorMode == ColorMode::Hdr || mWindowInfo.colorMode == ColorMode::Hdr10) {
John Reck55887762023-01-25 16:51:18 -0500544 mWindowInfo.dataspace =
545 static_cast<android_dataspace>(STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_EXTENDED);
546 } else {
547 mWindowInfo.dataspace = ColorSpaceToADataSpace(
548 mWindowInfo.colorspace.get(), BufferFormatToColorType(mWindowInfo.bufferFormat));
549 }
550 LOG_ALWAYS_FATAL_IF(mWindowInfo.dataspace == HAL_DATASPACE_UNKNOWN &&
551 mWindowInfo.bufferFormat != AHARDWAREBUFFER_FORMAT_R8_UNORM,
552 "Unsupported colorspace");
553
554 if (mNativeWindow) {
John Reck0b3f3312023-01-31 16:21:28 -0500555 int err = ANativeWindow_setBuffersDataSpace(mNativeWindow.get(), mWindowInfo.dataspace);
John Reck55887762023-01-25 16:51:18 -0500556 if (err != 0) {
557 ALOGE("VulkanSurface::setColorSpace() native_window_set_buffers_data_space(%d) "
558 "failed: %s (%d)",
559 mWindowInfo.dataspace, strerror(-err), err);
560 }
561 }
562}
563
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500564} /* namespace renderthread */
565} /* namespace uirenderer */
566} /* namespace android */