blob: acf4931d614499d6fa1f5a651914c795625d3e5f [file] [log] [blame]
Derek Sollenbergera19b71a2019-02-15 16:36:30 -05001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "VulkanSurface.h"
18
Adlai Hollerd2345212020-10-07 14:16:40 -040019#include <GrDirectContext.h>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050020#include <SkSurface.h>
John Reck0fa0cbc2019-04-05 16:57:46 -070021#include <algorithm>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050022
23#include "VulkanManager.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050024#include "utils/Color.h"
John Reck0fa0cbc2019-04-05 16:57:46 -070025#include "utils/TraceUtils.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050026
27namespace android {
28namespace uirenderer {
29namespace renderthread {
30
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050031static int InvertTransform(int transform) {
32 switch (transform) {
Alec Mouria5a0c962019-12-10 15:10:14 -080033 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
34 return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
35 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
36 return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
37 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
38 return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050039 default:
40 return 0;
41 }
42}
43
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050044static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
45 const int width = windowSize.width();
46 const int height = windowSize.height();
47
48 switch (transform) {
49 case 0:
50 return SkMatrix::I();
Alec Mouria5a0c962019-12-10 15:10:14 -080051 case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050052 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080053 case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050054 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
Alec Mouria5a0c962019-12-10 15:10:14 -080055 case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050056 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
57 default:
58 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
59 }
60 return SkMatrix::I();
61}
62
Yiwei Zhang68daf672019-06-26 22:02:41 -070063static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
64 ATRACE_CALL();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050065
66 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
67 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070068 ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050069 return false;
70 }
71
72 // this will match what we do on GL so pick that here.
73 err = window->setSwapInterval(window, 1);
74 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070075 ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050076 return false;
77 }
78
79 err = native_window_set_shared_buffer_mode(window, false);
80 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070081 ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050082 return false;
83 }
84
85 err = native_window_set_auto_refresh(window, false);
86 if (err != 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -070087 ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
88 return false;
89 }
90
91 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
92 if (err != 0) {
93 ALOGE("native_window_set_scaling_mode(NATIVE_WINDOW_SCALING_MODE_FREEZE) failed: %s (%d)",
94 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050095 return false;
96 }
97
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -070098 // Let consumer drive the size of the buffers.
99 err = native_window_set_buffers_dimensions(window, 0, 0);
100 if (err != 0) {
101 ALOGE("native_window_set_buffers_dimensions(0,0) failed: %s (%d)", strerror(-err), err);
102 return false;
103 }
104
105 // Enable auto prerotation, so when buffer size is driven by the consumer
106 // and the transform hint specifies a 90 or 270 degree rotation, the width
107 // and height used for buffer pre-allocation and dequeueBuffer will be
108 // additionally swapped.
109 err = native_window_set_auto_prerotation(window, true);
110 if (err != 0) {
111 ALOGE("VulkanSurface::UpdateWindow() native_window_set_auto_prerotation failed: %s (%d)",
112 strerror(-err), err);
113 return false;
114 }
115
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500116 return true;
117}
118
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500119VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700120 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
Adlai Hollerd2345212020-10-07 14:16:40 -0400121 GrDirectContext* grContext, const VulkanManager& vkManager,
John Reck0fa0cbc2019-04-05 16:57:46 -0700122 uint32_t extraBuffers) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700123 // Connect and set native window to default configurations.
124 if (!ConnectAndSetWindowDefaults(window)) {
125 return nullptr;
126 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500127
Yiwei Zhang68daf672019-06-26 22:02:41 -0700128 // Initialize WindowInfo struct.
129 WindowInfo windowInfo;
130 if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700131 extraBuffers, &windowInfo)) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700132 return nullptr;
133 }
134
135 // Now we attempt to modify the window.
136 if (!UpdateWindow(window, windowInfo)) {
137 return nullptr;
138 }
139
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700140 return new VulkanSurface(window, windowInfo, grContext);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700141}
142
143bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
144 SkColorType colorType,
145 sk_sp<SkColorSpace> colorSpace,
146 const VulkanManager& vkManager,
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700147 uint32_t extraBuffers, WindowInfo* outWindowInfo) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700148 ATRACE_CALL();
149
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700150 int width, height;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700151 int err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700152 if (err != 0 || width < 0) {
153 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, width);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700154 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700155 }
156 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
157 if (err != 0 || height < 0) {
158 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, height);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700159 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700160 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700161 outWindowInfo->size = SkISize::Make(width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500162
John Reckac513c22019-03-28 16:57:38 -0700163 int query_value;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700164 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &query_value);
John Reckac513c22019-03-28 16:57:38 -0700165 if (err != 0 || query_value < 0) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700166 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700167 return false;
John Reckac513c22019-03-28 16:57:38 -0700168 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700169 outWindowInfo->transform = query_value;
John Reckac513c22019-03-28 16:57:38 -0700170
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700171 outWindowInfo->actualSize = outWindowInfo->size;
Alec Mouria5a0c962019-12-10 15:10:14 -0800172 if (outWindowInfo->transform & ANATIVEWINDOW_TRANSFORM_ROTATE_90) {
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700173 outWindowInfo->actualSize.set(outWindowInfo->size.height(), outWindowInfo->size.width());
174 }
175
176 outWindowInfo->preTransform =
177 GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700178
179 err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
180 if (err != 0 || query_value < 0) {
181 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700182 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500183 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700184 outWindowInfo->bufferCount =
185 static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500186
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700187 err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
188 if (err != 0 || query_value < 0) {
189 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
Yiwei Zhang68daf672019-06-26 22:02:41 -0700190 return false;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700191 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700192 if (outWindowInfo->bufferCount > static_cast<uint32_t>(query_value)) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700193 // Application must settle for fewer images than desired:
Yiwei Zhang68daf672019-06-26 22:02:41 -0700194 outWindowInfo->bufferCount = static_cast<uint32_t>(query_value);
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700195 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500196
Yiwei Zhang68daf672019-06-26 22:02:41 -0700197 outWindowInfo->dataspace = HAL_DATASPACE_V0_SRGB;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500198 if (colorMode == ColorMode::WideColorGamut) {
199 skcms_Matrix3x3 surfaceGamut;
200 LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut),
201 "Could not get gamut matrix from color space");
202 if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700203 outWindowInfo->dataspace = HAL_DATASPACE_V0_SCRGB;
Mike Reed7ac1af32020-05-26 10:50:21 -0400204 } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDisplayP3, sizeof(surfaceGamut)) == 0) {
Yiwei Zhang68daf672019-06-26 22:02:41 -0700205 outWindowInfo->dataspace = HAL_DATASPACE_DISPLAY_P3;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500206 } else {
207 LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
208 }
209 }
210
Alec Mouri45238012020-01-29 11:04:40 -0800211 outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500212 VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
Alec Mouri45238012020-01-29 11:04:40 -0800213 if (outWindowInfo->bufferFormat == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500214 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
215 }
216
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400217 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
218 "vkGetPhysicalDeviceImageFormatProperties2 is missing");
219 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
220 externalImageFormatInfo.sType =
221 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
222 externalImageFormatInfo.pNext = nullptr;
223 externalImageFormatInfo.handleType =
224 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400225
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400226 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
227 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
228 imageFormatInfo.pNext = &externalImageFormatInfo;
229 imageFormatInfo.format = vkPixelFormat;
230 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
231 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700232 // Currently Skia requires the images to be color attachments and support all transfer
233 // operations.
234 imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
235 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400236 imageFormatInfo.flags = 0;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400237
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400238 VkAndroidHardwareBufferUsageANDROID hwbUsage;
239 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
240 hwbUsage.pNext = nullptr;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400241
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400242 VkImageFormatProperties2 imgFormProps;
243 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
244 imgFormProps.pNext = &hwbUsage;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400245
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700246 VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
247 vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400248 if (VK_SUCCESS != res) {
249 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
Yiwei Zhang68daf672019-06-26 22:02:41 -0700250 return false;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400251 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500252
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400253 uint64_t consumerUsage;
Yiwei Zhang68daf672019-06-26 22:02:41 -0700254 err = native_window_get_consumer_usage(window, &consumerUsage);
255 if (err != 0) {
256 ALOGE("native_window_get_consumer_usage failed: %s (%d)", strerror(-err), err);
257 return false;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500258 }
Yiwei Zhang68daf672019-06-26 22:02:41 -0700259 outWindowInfo->windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500260
Yiwei Zhang68daf672019-06-26 22:02:41 -0700261 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500262}
263
264bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
265 ATRACE_CALL();
266
Alec Mouri45238012020-01-29 11:04:40 -0800267 int err = native_window_set_buffers_format(window, windowInfo.bufferFormat);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500268 if (err != 0) {
269 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
Alec Mouri45238012020-01-29 11:04:40 -0800270 windowInfo.bufferFormat, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500271 return false;
272 }
273
274 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
275 if (err != 0) {
276 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700277 "failed: %s (%d)",
278 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500279 return false;
280 }
281
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500282 // native_window_set_buffers_transform() expects the transform the app is requesting that
283 // the compositor perform during composition. With native windows, pre-transform works by
284 // rendering with the same transform the compositor is applying (as in Vulkan), but
285 // then requesting the inverse transform, so that when the compositor does
286 // it's job the two transforms cancel each other out and the compositor ends
287 // up applying an identity transform to the app's buffer.
288 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
289 if (err != 0) {
290 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700291 "failed: %s (%d)",
292 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500293 return false;
294 }
295
John Reckac513c22019-03-28 16:57:38 -0700296 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500297 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700298 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500299 windowInfo.bufferCount, strerror(-err), err);
300 return false;
301 }
302
303 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
304 if (err != 0) {
305 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
306 strerror(-err), err);
307 return false;
308 }
309
Yiwei Zhang68daf672019-06-26 22:02:41 -0700310 return true;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500311}
312
313VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
Adlai Hollerd2345212020-10-07 14:16:40 -0400314 GrDirectContext* grContext)
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700315 : mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500316
317VulkanSurface::~VulkanSurface() {
318 releaseBuffers();
319
320 // release the native window to be available for use by other clients
321 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
322 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
323}
324
325void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700326 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500327 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
328
329 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
330 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
331 bufferInfo.dequeue_fence);
332 if (err != 0) {
333 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
334 }
335 bufferInfo.dequeued = false;
336
337 if (bufferInfo.dequeue_fence >= 0) {
338 close(bufferInfo.dequeue_fence);
339 bufferInfo.dequeue_fence = -1;
340 }
341 }
342
343 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
344 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
345
346 bufferInfo.skSurface.reset();
347 bufferInfo.buffer.clear();
348 bufferInfo.hasValidContents = false;
349 bufferInfo.lastPresentedCount = 0;
350 }
351}
352
353VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400354 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500355 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400356 mCurrentBufferInfo = nullptr;
357
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700358 // Query the transform hint synced from the initial Surface connect or last queueBuffer. The
359 // auto prerotation on the buffer is based on the same transform hint in use by the producer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500360 int transformHint = 0;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700361 int err =
362 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500363
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700364 // Since auto pre-rotation is enabled, dequeueBuffer to get the consumer driven buffer size
365 // from ANativeWindowBuffer.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500366 ANativeWindowBuffer* buffer;
367 int fence_fd;
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700368 err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500369 if (err != 0) {
370 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
371 return nullptr;
372 }
373
Yiwei Zhangdab6ecd2019-06-27 12:22:33 -0700374 SkISize actualSize = SkISize::Make(buffer->width, buffer->height);
375 if (actualSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
376 if (actualSize != mWindowInfo.actualSize) {
377 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
378 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
379 mWindowInfo.actualSize = actualSize;
380 releaseBuffers();
381 }
382
383 if (transformHint != mWindowInfo.transform) {
384 err = native_window_set_buffers_transform(mNativeWindow.get(),
385 InvertTransform(transformHint));
386 if (err != 0) {
387 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", transformHint,
388 strerror(-err), err);
389 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
390 return nullptr;
391 }
392 mWindowInfo.transform = transformHint;
393 }
394
395 mWindowInfo.size = actualSize;
396 if (mWindowInfo.transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
397 mWindowInfo.size.set(actualSize.height(), actualSize.width());
398 }
399
400 mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
401 }
402
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500403 uint32_t idx;
404 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
405 if (mNativeBuffers[idx].buffer.get() == buffer) {
406 mNativeBuffers[idx].dequeued = true;
407 mNativeBuffers[idx].dequeue_fence = fence_fd;
408 break;
409 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
410 // increasing the number of buffers we have allocated
411 mNativeBuffers[idx].buffer = buffer;
412 mNativeBuffers[idx].dequeued = true;
413 mNativeBuffers[idx].dequeue_fence = fence_fd;
414 break;
415 }
416 }
417 if (idx == mWindowInfo.bufferCount) {
418 ALOGE("dequeueBuffer returned unrecognized buffer");
419 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
420 return nullptr;
421 }
422
423 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
424
425 if (bufferInfo->skSurface.get() == nullptr) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700426 bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
427 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
428 kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), nullptr);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500429 if (bufferInfo->skSurface.get() == nullptr) {
430 ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
431 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
432 return nullptr;
433 }
434 }
435
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400436 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500437 return bufferInfo;
438}
439
440bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
441 if (!dirtyRect.isEmpty()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500442
John Reck321d8e52019-04-12 13:06:11 -0700443 // native_window_set_surface_damage takes a rectangle in prerotated space
444 // with a bottom-left origin. That is, top > bottom.
445 // The dirtyRect is also in prerotated space, so we just need to switch it to
446 // a bottom-left origin space.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500447
John Reck321d8e52019-04-12 13:06:11 -0700448 SkIRect irect;
449 dirtyRect.roundOut(&irect);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500450 android_native_rect_t aRect;
John Reck321d8e52019-04-12 13:06:11 -0700451 aRect.left = irect.left();
452 aRect.top = logicalHeight() - irect.top();
453 aRect.right = irect.right();
454 aRect.bottom = logicalHeight() - irect.bottom();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500455
456 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
457 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
458 }
459
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400460 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
461 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500462 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
463 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
464
465 currentBuffer.dequeued = false;
466 // queueBuffer always closes fence, even on error
467 if (err != 0) {
468 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
469 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
470 currentBuffer.dequeue_fence);
471 } else {
472 currentBuffer.hasValidContents = true;
473 currentBuffer.lastPresentedCount = mPresentCount;
474 mPresentCount++;
475 }
476
477 if (currentBuffer.dequeue_fence >= 0) {
478 close(currentBuffer.dequeue_fence);
479 currentBuffer.dequeue_fence = -1;
480 }
481
482 return err == 0;
483}
484
485int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400486 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
487 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500488 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
489}
490
491} /* namespace renderthread */
492} /* namespace uirenderer */
493} /* namespace android */