blob: a8e85475aff07dabcba3ecbaecaf3a29fee11040 [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
John Reck4bd8d8a2023-12-08 11:27:19 -050032static constexpr auto P3_XRB = static_cast<android_dataspace>(
33 ADATASPACE_STANDARD_DCI_P3 | ADATASPACE_TRANSFER_SRGB | ADATASPACE_RANGE_EXTENDED);
34
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050035static int InvertTransform(int transform) {
36 switch (transform) {
Alec Mouria5a0c962019-12-10 15:10:14 -080037 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
38 return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
39 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
40 return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
41 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
42 return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050043 default:
44 return 0;
45 }
46}
47
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050048static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
49 const int width = windowSize.width();
50 const int height = windowSize.height();
51
52 switch (transform) {
53 case 0:
54 return SkMatrix::I();
Alec Mouria5a0c962019-12-10 15:10:14 -080055 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050056 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080057 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050058 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080059 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050060 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
61 default:
62 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
63 }
64 return SkMatrix::I();
65}
66
John Reckee184272023-03-21 12:29:21 -040067static SkM44 GetPixelSnapMatrix(SkISize windowSize, int transform) {
68 // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
69 // desired fragment
70 static const SkScalar kOffset = 0.063f;
71 SkMatrix preRotation = GetPreTransformMatrix(windowSize, transform);
72 SkMatrix invert;
73 LOG_ALWAYS_FATAL_IF(!preRotation.invert(&invert));
74 return SkM44::Translate(kOffset, kOffset)
75 .postConcat(SkM44(preRotation))
76 .preConcat(SkM44(invert));
77}
78
Yiwei Zhang68daf672019-06-26 22:02:41 -070079static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
80 ATRACE_CALL();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050081
82 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
83 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070084 ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050085 return false;
86 }
87
88 // this will match what we do on GL so pick that here.
89 err = window->setSwapInterval(window, 1);
90 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070091 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050092 return false;
93 }
94
95 err = native_window_set_shared_buffer_mode(window, false);
96 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070097 ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050098 return false;
99 }
100
101 err = native_window_set_auto_refresh(window, false);
102 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700103 ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
104 return false;
105 }
106
107 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
108 if (err != 0) {
109 ALOGE("native_window_set_scaling_mode(NATIVE_WINDOW_SCALING_MODE_FREEZE) failed: %s (%d)",
110 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500111 return false;
112 }
113
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700114 // Let consumer drive the size of the buffers.
115 err = native_window_set_buffers_dimensions(window, 0, 0);
116 if (err != 0) {
117 ALOGE("native_window_set_buffers_dimensions(0,0) failed: %s (%d)", strerror(-err), err);
118 return false;
119 }
120
121 // Enable auto prerotation, so when buffer size is driven by the consumer
122 // and the transform hint specifies a 90 or 270 degree rotation, the width
123 // and height used for buffer pre-allocation and dequeueBuffer will be
124 // additionally swapped.
125 err = native_window_set_auto_prerotation(window, true);
126 if (err != 0) {
127 ALOGE("VulkanSurface::UpdateWindow() native_window_set_auto_prerotation failed: %s (%d)",
128 strerror(-err), err);
129 return false;
130 }
131
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500132 return true;
133}
134
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500135VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700136 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
Adlai Hollerd2345212020-10-07 14:16:40 -0400137 GrDirectContext* grContext, const VulkanManager& vkManager,
John Reck0fa0cbc2019-04-05 16:57:46 -0700138 uint32_t extraBuffers) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700139 // Connect and set native window to default configurations.
140 if (!ConnectAndSetWindowDefaults(window)) {
141 return nullptr;
142 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500143
Yiwei Zhang68daf672019-06-26 22:02:41 -0700144 // Initialize WindowInfo struct.
145 WindowInfo windowInfo;
146 if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700147 extraBuffers, &windowInfo)) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700148 return nullptr;
149 }
150
151 // Now we attempt to modify the window.
152 if (!UpdateWindow(window, windowInfo)) {
153 return nullptr;
154 }
155
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700156 return new VulkanSurface(window, windowInfo, grContext);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700157}
158
159bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
160 SkColorType colorType,
161 sk_sp<SkColorSpace> colorSpace,
162 const VulkanManager& vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700163 uint32_t extraBuffers, WindowInfo* outWindowInfo) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700164 ATRACE_CALL();
165
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700166 int width, height;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700167 int err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700168 if (err != 0 || width < 0) {
169 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, width);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700170 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700171 }
172 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
173 if (err != 0 || height < 0) {
174 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, height);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700175 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700176 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700177 outWindowInfo->size = SkISize::Make(width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500178
John Reckac513c22019-03-28 16:57:38 -0700179 int query_value;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700180 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &query_value);
John Reckac513c22019-03-28 16:57:38 -0700181 if (err != 0 || query_value < 0) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700182 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700183 return false;
John Reckac513c22019-03-28 16:57:38 -0700184 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700185 outWindowInfo->transform = query_value;
John Reckac513c22019-03-28 16:57:38 -0700186
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700187 outWindowInfo->actualSize = outWindowInfo->size;
Alec Mouria5a0c962019-12-10 15:10:14 -0800188 if (outWindowInfo->transform & ANATIVEWINDOW_TRANSFORM_ROTATE_90) {
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700189 outWindowInfo->actualSize.set(outWindowInfo->size.height(), outWindowInfo->size.width());
190 }
191
192 outWindowInfo->preTransform =
193 GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
John Reckee184272023-03-21 12:29:21 -0400194 outWindowInfo->pixelSnapMatrix =
195 GetPixelSnapMatrix(outWindowInfo->size, outWindowInfo->transform);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700196
197 err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
198 if (err != 0 || query_value < 0) {
199 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700200 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500201 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700202 outWindowInfo->bufferCount =
203 static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500204
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700205 err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
206 if (err != 0 || query_value < 0) {
207 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700208 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700209 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700210 if (outWindowInfo->bufferCount > static_cast<uint32_t>(query_value)) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700211 // Application must settle for fewer images than desired:
Yiwei Zhang68daf672019-06-26 22:02:41 -0700212 outWindowInfo->bufferCount = static_cast<uint32_t>(query_value);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700213 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500214
Alec Mouri45238012020-01-29 11:04:40 -0800215 outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400216 outWindowInfo->colorspace = colorSpace;
John Reck55887762023-01-25 16:51:18 -0500217 outWindowInfo->colorMode = colorMode;
218
John Reck0b3f3312023-01-31 16:21:28 -0500219 if (colorMode == ColorMode::Hdr || colorMode == ColorMode::Hdr10) {
John Reck4bd8d8a2023-12-08 11:27:19 -0500220 outWindowInfo->dataspace = P3_XRB;
John Reck55887762023-01-25 16:51:18 -0500221 } else {
222 outWindowInfo->dataspace = ColorSpaceToADataSpace(colorSpace.get(), colorType);
223 }
Leon Scroggins III7ccb8a42021-11-30 14:17:28 -0500224 LOG_ALWAYS_FATAL_IF(
225 outWindowInfo->dataspace == HAL_DATASPACE_UNKNOWN && colorType != kAlpha_8_SkColorType,
226 "Unsupported colorspace");
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400227
228 VkFormat vkPixelFormat;
229 switch (colorType) {
230 case kRGBA_8888_SkColorType:
231 vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
232 break;
233 case kRGBA_F16_SkColorType:
234 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
235 break;
236 case kRGBA_1010102_SkColorType:
237 vkPixelFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
238 break;
Leon Scroggins III7ccb8a42021-11-30 14:17:28 -0500239 case kAlpha_8_SkColorType:
240 vkPixelFormat = VK_FORMAT_R8_UNORM;
241 break;
Derek Sollenberger89f170c2021-04-01 16:05:54 -0400242 default:
243 LOG_ALWAYS_FATAL("Unsupported colorType: %d", (int)colorType);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500244 }
245
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400246 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
247 "vkGetPhysicalDeviceImageFormatProperties2 is missing");
248 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
249 externalImageFormatInfo.sType =
250 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
251 externalImageFormatInfo.pNext = nullptr;
252 externalImageFormatInfo.handleType =
253 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400254
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400255 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
256 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
257 imageFormatInfo.pNext = &externalImageFormatInfo;
258 imageFormatInfo.format = vkPixelFormat;
259 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
260 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700261 // Currently Skia requires the images to be color attachments and support all transfer
262 // operations.
263 imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
264 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400265 imageFormatInfo.flags = 0;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400266
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400267 VkAndroidHardwareBufferUsageANDROID hwbUsage;
268 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
269 hwbUsage.pNext = nullptr;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400270
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400271 VkImageFormatProperties2 imgFormProps;
272 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
273 imgFormProps.pNext = &hwbUsage;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400274
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700275 VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
276 vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400277 if (VK_SUCCESS != res) {
278 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
Yiwei Zhang68daf672019-06-26 22:02:41 -0700279 return false;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400280 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500281
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400282 uint64_t consumerUsage;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700283 err = native_window_get_consumer_usage(window, &consumerUsage);
284 if (err != 0) {
285 ALOGE("native_window_get_consumer_usage failed: %s (%d)", strerror(-err), err);
286 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500287 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700288 outWindowInfo->windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500289
Yiwei Zhang68daf672019-06-26 22:02:41 -0700290 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500291}
292
293bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
294 ATRACE_CALL();
295
Alec Mouri45238012020-01-29 11:04:40 -0800296 int err = native_window_set_buffers_format(window, windowInfo.bufferFormat);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500297 if (err != 0) {
298 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
Alec Mouri45238012020-01-29 11:04:40 -0800299 windowInfo.bufferFormat, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500300 return false;
301 }
302
303 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
304 if (err != 0) {
305 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700306 "failed: %s (%d)",
307 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500308 return false;
309 }
310
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500311 // native_window_set_buffers_transform() expects the transform the app is requesting that
312 // the compositor perform during composition. With native windows, pre-transform works by
313 // rendering with the same transform the compositor is applying (as in Vulkan), but
314 // then requesting the inverse transform, so that when the compositor does
315 // it's job the two transforms cancel each other out and the compositor ends
316 // up applying an identity transform to the app's buffer.
317 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
318 if (err != 0) {
319 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700320 "failed: %s (%d)",
321 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500322 return false;
323 }
324
John Reckac513c22019-03-28 16:57:38 -0700325 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500326 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700327 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500328 windowInfo.bufferCount, strerror(-err), err);
329 return false;
330 }
331
332 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
333 if (err != 0) {
334 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
335 strerror(-err), err);
336 return false;
337 }
338
Yiwei Zhang68daf672019-06-26 22:02:41 -0700339 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500340}
341
342VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
Adlai Hollerd2345212020-10-07 14:16:40 -0400343 GrDirectContext* grContext)
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700344 : mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500345
346VulkanSurface::~VulkanSurface() {
347 releaseBuffers();
348
349 // release the native window to be available for use by other clients
350 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
351 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
352}
353
354void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700355 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500356 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
357
358 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
359 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
John Reckf0baa242021-05-13 18:14:45 -0400360 bufferInfo.dequeue_fence.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500361 if (err != 0) {
362 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
363 }
364 bufferInfo.dequeued = false;
John Reckf0baa242021-05-13 18:14:45 -0400365 bufferInfo.dequeue_fence.reset();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500366 }
367
368 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
John Reckf0baa242021-05-13 18:14:45 -0400369 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence.ok());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500370
371 bufferInfo.skSurface.reset();
372 bufferInfo.buffer.clear();
373 bufferInfo.hasValidContents = false;
374 bufferInfo.lastPresentedCount = 0;
375 }
376}
377
John Reck61c64472023-05-04 11:29:45 -0400378void VulkanSurface::invalidateBuffers() {
379 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
380 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
381 bufferInfo.hasValidContents = false;
382 bufferInfo.lastPresentedCount = 0;
383 }
384}
385
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500386VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400387 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500388 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400389 mCurrentBufferInfo = nullptr;
390
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700391 // Query the transform hint synced from the initial Surface connect or last queueBuffer. The
392 // auto prerotation on the buffer is based on the same transform hint in use by the producer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500393 int transformHint = 0;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700394 int err =
395 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500396
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700397 // Since auto pre-rotation is enabled, dequeueBuffer to get the consumer driven buffer size
398 // from ANativeWindowBuffer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500399 ANativeWindowBuffer* buffer;
John Reckf0baa242021-05-13 18:14:45 -0400400 base::unique_fd fence_fd;
401 {
402 int rawFd = -1;
403 err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &rawFd);
404 fence_fd.reset(rawFd);
405 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500406 if (err != 0) {
407 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
408 return nullptr;
409 }
410
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700411 SkISize actualSize = SkISize::Make(buffer->width, buffer->height);
412 if (actualSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
413 if (actualSize != mWindowInfo.actualSize) {
414 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
415 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
416 mWindowInfo.actualSize = actualSize;
417 releaseBuffers();
John Reck61c64472023-05-04 11:29:45 -0400418 } else {
419 // A change in transform means we need to repaint the entire buffer area as the damage
420 // rects have just moved about.
421 invalidateBuffers();
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700422 }
423
424 if (transformHint != mWindowInfo.transform) {
425 err = native_window_set_buffers_transform(mNativeWindow.get(),
426 InvertTransform(transformHint));
427 if (err != 0) {
428 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", transformHint,
429 strerror(-err), err);
John Reckf0baa242021-05-13 18:14:45 -0400430 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700431 return nullptr;
432 }
433 mWindowInfo.transform = transformHint;
434 }
435
436 mWindowInfo.size = actualSize;
437 if (mWindowInfo.transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
438 mWindowInfo.size.set(actualSize.height(), actualSize.width());
439 }
440
441 mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
John Reckee184272023-03-21 12:29:21 -0400442 mWindowInfo.pixelSnapMatrix = GetPixelSnapMatrix(mWindowInfo.size, mWindowInfo.transform);
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700443 }
444
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500445 uint32_t idx;
446 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
447 if (mNativeBuffers[idx].buffer.get() == buffer) {
448 mNativeBuffers[idx].dequeued = true;
John Reckf0baa242021-05-13 18:14:45 -0400449 mNativeBuffers[idx].dequeue_fence = std::move(fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500450 break;
451 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
452 // increasing the number of buffers we have allocated
453 mNativeBuffers[idx].buffer = 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 }
458 }
459 if (idx == mWindowInfo.bufferCount) {
460 ALOGE("dequeueBuffer returned unrecognized buffer");
John Reckf0baa242021-05-13 18:14:45 -0400461 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500462 return nullptr;
463 }
464
465 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
466
467 if (bufferInfo->skSurface.get() == nullptr) {
John Reckb026f352023-04-05 13:19:15 -0400468 SkSurfaceProps surfaceProps;
469 if (mWindowInfo.colorMode != ColorMode::Default) {
470 surfaceProps = SkSurfaceProps(SkSurfaceProps::kAlwaysDither_Flag | surfaceProps.flags(),
471 surfaceProps.pixelGeometry());
472 }
Kevin Lubick6817fc42023-05-12 19:27:20 +0000473 bufferInfo->skSurface = SkSurfaces::WrapAndroidHardwareBuffer(
John Reck0fa0cbc2019-04-05 16:57:46 -0700474 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
John Reckb026f352023-04-05 13:19:15 -0400475 kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, &surfaceProps,
476 /*from_window=*/true);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500477 if (bufferInfo->skSurface.get() == nullptr) {
Kevin Lubick6817fc42023-05-12 19:27:20 +0000478 ALOGE("SkSurfaces::WrapAndroidHardwareBuffer failed");
Greg Danielffc50c62021-06-08 14:24:06 -0400479 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer,
480 mNativeBuffers[idx].dequeue_fence.release());
481 mNativeBuffers[idx].dequeued = false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500482 return nullptr;
483 }
484 }
485
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400486 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500487 return bufferInfo;
488}
489
490bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
491 if (!dirtyRect.isEmpty()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500492
John Reck321d8e52019-04-12 13:06:11 -0700493 // native_window_set_surface_damage takes a rectangle in prerotated space
494 // with a bottom-left origin. That is, top > bottom.
495 // The dirtyRect is also in prerotated space, so we just need to switch it to
496 // a bottom-left origin space.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500497
John Reck321d8e52019-04-12 13:06:11 -0700498 SkIRect irect;
499 dirtyRect.roundOut(&irect);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500500 android_native_rect_t aRect;
John Reck321d8e52019-04-12 13:06:11 -0700501 aRect.left = irect.left();
502 aRect.top = logicalHeight() - irect.top();
503 aRect.right = irect.right();
504 aRect.bottom = logicalHeight() - irect.bottom();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500505
506 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
507 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
508 }
509
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400510 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
511 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
John Reckf0baa242021-05-13 18:14:45 -0400512 // queueBuffer always closes fence, even on error
513 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence.release();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500514 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
515
516 currentBuffer.dequeued = false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500517 if (err != 0) {
518 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
John Reckf0baa242021-05-13 18:14:45 -0400519 // cancelBuffer takes ownership of the fence
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500520 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
John Reckf0baa242021-05-13 18:14:45 -0400521 currentBuffer.dequeue_fence.release());
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500522 } else {
523 currentBuffer.hasValidContents = true;
524 currentBuffer.lastPresentedCount = mPresentCount;
525 mPresentCount++;
526 }
527
John Reckf0baa242021-05-13 18:14:45 -0400528 currentBuffer.dequeue_fence.reset();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500529
530 return err == 0;
531}
532
533int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400534 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
535 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500536 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
537}
538
John Reck55887762023-01-25 16:51:18 -0500539void VulkanSurface::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
540 mWindowInfo.colorspace = std::move(colorSpace);
541 for (int i = 0; i < kNumBufferSlots; i++) {
542 mNativeBuffers[i].skSurface.reset();
543 }
544
John Reck0b3f3312023-01-31 16:21:28 -0500545 if (mWindowInfo.colorMode == ColorMode::Hdr || mWindowInfo.colorMode == ColorMode::Hdr10) {
John Reck4bd8d8a2023-12-08 11:27:19 -0500546 mWindowInfo.dataspace = P3_XRB;
John Reck55887762023-01-25 16:51:18 -0500547 } else {
548 mWindowInfo.dataspace = ColorSpaceToADataSpace(
549 mWindowInfo.colorspace.get(), BufferFormatToColorType(mWindowInfo.bufferFormat));
550 }
551 LOG_ALWAYS_FATAL_IF(mWindowInfo.dataspace == HAL_DATASPACE_UNKNOWN &&
552 mWindowInfo.bufferFormat != AHARDWAREBUFFER_FORMAT_R8_UNORM,
553 "Unsupported colorspace");
554
555 if (mNativeWindow) {
John Reck0b3f3312023-01-31 16:21:28 -0500556 int err = ANativeWindow_setBuffersDataSpace(mNativeWindow.get(), mWindowInfo.dataspace);
John Reck55887762023-01-25 16:51:18 -0500557 if (err != 0) {
558 ALOGE("VulkanSurface::setColorSpace() native_window_set_buffers_data_space(%d) "
559 "failed: %s (%d)",
560 mWindowInfo.dataspace, strerror(-err), err);
561 }
562 }
563}
564
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500565} /* namespace renderthread */
566} /* namespace uirenderer */
567} /* namespace android */