blob: a6676608ec4428b488c3d41e97e504572528f231 [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>
John Reck0fa0cbc2019-04-05 16:57:46 -070020#include <algorithm>
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050021
22#include "VulkanManager.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050023#include "utils/Color.h"
John Reck0fa0cbc2019-04-05 16:57:46 -070024#include "utils/TraceUtils.h"
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050025
26namespace android {
27namespace uirenderer {
28namespace renderthread {
29
30static bool IsTransformSupported(int transform) {
31 // For now, only support pure rotations, not flip or flip-and-rotate, until we have
32 // more time to test them and build sample code. As far as I know we never actually
33 // use anything besides pure rotations anyway.
John Reck0fa0cbc2019-04-05 16:57:46 -070034 return transform == 0 || transform == NATIVE_WINDOW_TRANSFORM_ROT_90 ||
35 transform == NATIVE_WINDOW_TRANSFORM_ROT_180 ||
36 transform == NATIVE_WINDOW_TRANSFORM_ROT_270;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050037}
38
39static int InvertTransform(int transform) {
40 switch (transform) {
41 case NATIVE_WINDOW_TRANSFORM_ROT_90:
42 return NATIVE_WINDOW_TRANSFORM_ROT_270;
43 case NATIVE_WINDOW_TRANSFORM_ROT_180:
44 return NATIVE_WINDOW_TRANSFORM_ROT_180;
45 case NATIVE_WINDOW_TRANSFORM_ROT_270:
46 return NATIVE_WINDOW_TRANSFORM_ROT_90;
47 default:
48 return 0;
49 }
50}
51
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050052static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
53 const int width = windowSize.width();
54 const int height = windowSize.height();
55
56 switch (transform) {
57 case 0:
58 return SkMatrix::I();
59 case NATIVE_WINDOW_TRANSFORM_ROT_90:
60 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
61 case NATIVE_WINDOW_TRANSFORM_ROT_180:
62 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
63 case NATIVE_WINDOW_TRANSFORM_ROT_270:
64 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
65 default:
66 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
67 }
68 return SkMatrix::I();
69}
70
71void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize,
John Reck0fa0cbc2019-04-05 16:57:46 -070072 const SkISize& maxSize) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050073 SkISize& windowSize = windowInfo->size;
74
75 // clamp width & height to handle currentExtent of -1 and protect us from broken hints
John Reck0fa0cbc2019-04-05 16:57:46 -070076 if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width() ||
77 windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050078 int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width()));
79 int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height()));
John Reck0fa0cbc2019-04-05 16:57:46 -070080 ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]", windowSize.width(),
81 windowSize.height(), width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050082 windowSize.set(width, height);
83 }
84
85 windowInfo->actualSize = windowSize;
86 if (windowInfo->transform & HAL_TRANSFORM_ROT_90) {
87 windowInfo->actualSize.set(windowSize.height(), windowSize.width());
88 }
89
90 windowInfo->preTransform = GetPreTransformMatrix(windowInfo->size, windowInfo->transform);
91}
92
93static bool ResetNativeWindow(ANativeWindow* window) {
94 // -- Reset the native window --
95 // The native window might have been used previously, and had its properties
96 // changed from defaults. That will affect the answer we get for queries
97 // like MIN_UNDEQUEUED_BUFFERS. Reset to a known/default state before we
98 // attempt such queries.
99
100 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
101 if (err != 0) {
102 ALOGW("native_window_api_connect failed: %s (%d)", strerror(-err), err);
103 return false;
104 }
105
106 // this will match what we do on GL so pick that here.
107 err = window->setSwapInterval(window, 1);
108 if (err != 0) {
109 ALOGW("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
110 return false;
111 }
112
113 err = native_window_set_shared_buffer_mode(window, false);
114 if (err != 0) {
115 ALOGW("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
116 return false;
117 }
118
119 err = native_window_set_auto_refresh(window, false);
120 if (err != 0) {
121 ALOGW("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
122 return false;
123 }
124
125 return true;
126}
127
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500128VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700129 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
130 GrContext* grContext, const VulkanManager& vkManager,
131 uint32_t extraBuffers) {
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700132 // TODO(http://b/134182502)
133 const SkISize minSize = SkISize::Make(1, 1);
134 const SkISize maxSize = SkISize::Make(4096, 4096);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500135
136 /*
137 * Populate Window Info struct
138 */
139 WindowInfo windowInfo;
140
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700141 int err;
142 int width, height;
143 err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
144 if (err != 0 || width < 0) {
145 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, width);
146 return nullptr;
147 }
148 err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
149 if (err != 0 || height < 0) {
150 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, height);
151 return nullptr;
152 }
153 windowInfo.size = SkISize::Make(width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500154
John Reckac513c22019-03-28 16:57:38 -0700155 int query_value;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700156 err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &query_value);
John Reckac513c22019-03-28 16:57:38 -0700157 if (err != 0 || query_value < 0) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700158 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
John Reckac513c22019-03-28 16:57:38 -0700159 return nullptr;
160 }
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700161 windowInfo.transform = query_value;
John Reckac513c22019-03-28 16:57:38 -0700162
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700163 ComputeWindowSizeAndTransform(&windowInfo, minSize, maxSize);
164
165 err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
166 if (err != 0 || query_value < 0) {
167 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
168 return nullptr;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500169 }
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700170 windowInfo.bufferCount = static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500171
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700172 err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
173 if (err != 0 || query_value < 0) {
174 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
175 return nullptr;
176 }
177 if (windowInfo.bufferCount > static_cast<uint32_t>(query_value)) {
178 // Application must settle for fewer images than desired:
179 windowInfo.bufferCount = static_cast<uint32_t>(query_value);
180 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500181
182 windowInfo.dataspace = HAL_DATASPACE_V0_SRGB;
183 if (colorMode == ColorMode::WideColorGamut) {
184 skcms_Matrix3x3 surfaceGamut;
185 LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut),
186 "Could not get gamut matrix from color space");
187 if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
188 windowInfo.dataspace = HAL_DATASPACE_V0_SCRGB;
189 } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
190 windowInfo.dataspace = HAL_DATASPACE_DISPLAY_P3;
191 } else {
192 LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
193 }
194 }
195
196 windowInfo.pixelFormat = ColorTypeToPixelFormat(colorType);
197 VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
198 if (windowInfo.pixelFormat == PIXEL_FORMAT_RGBA_FP16) {
199 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
200 }
201
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400202 LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
203 "vkGetPhysicalDeviceImageFormatProperties2 is missing");
204 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
205 externalImageFormatInfo.sType =
206 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
207 externalImageFormatInfo.pNext = nullptr;
208 externalImageFormatInfo.handleType =
209 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400210
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400211 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
212 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
213 imageFormatInfo.pNext = &externalImageFormatInfo;
214 imageFormatInfo.format = vkPixelFormat;
215 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
216 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700217 // Currently Skia requires the images to be color attachments and support all transfer
218 // operations.
219 imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
220 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400221 imageFormatInfo.flags = 0;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400222
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400223 VkAndroidHardwareBufferUsageANDROID hwbUsage;
224 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
225 hwbUsage.pNext = nullptr;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400226
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400227 VkImageFormatProperties2 imgFormProps;
228 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
229 imgFormProps.pNext = &hwbUsage;
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400230
Yiwei Zhangbd363c92019-06-26 14:22:32 -0700231 VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
232 vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400233 if (VK_SUCCESS != res) {
234 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400235 return nullptr;
236 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500237
Derek Sollenberger4670126b2019-04-08 15:45:20 -0400238 uint64_t consumerUsage;
239 native_window_get_consumer_usage(window, &consumerUsage);
240 windowInfo.windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
241
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500242 /*
243 * Now we attempt to modify the window!
244 */
245 if (!UpdateWindow(window, windowInfo)) {
246 return nullptr;
247 }
248
249 return new VulkanSurface(window, windowInfo, minSize, maxSize, grContext);
250}
251
252bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
253 ATRACE_CALL();
254
255 if (!ResetNativeWindow(window)) {
256 return false;
257 }
258
259 // -- Configure the native window --
260 int err = native_window_set_buffers_format(window, windowInfo.pixelFormat);
261 if (err != 0) {
262 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
263 windowInfo.pixelFormat, strerror(-err), err);
264 return false;
265 }
266
267 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
268 if (err != 0) {
269 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700270 "failed: %s (%d)",
271 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500272 return false;
273 }
274
275 const SkISize& size = windowInfo.actualSize;
276 err = native_window_set_buffers_dimensions(window, size.width(), size.height());
277 if (err != 0) {
278 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700279 "failed: %s (%d)",
280 size.width(), size.height(), strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500281 return false;
282 }
283
284 // native_window_set_buffers_transform() expects the transform the app is requesting that
285 // the compositor perform during composition. With native windows, pre-transform works by
286 // rendering with the same transform the compositor is applying (as in Vulkan), but
287 // then requesting the inverse transform, so that when the compositor does
288 // it's job the two transforms cancel each other out and the compositor ends
289 // up applying an identity transform to the app's buffer.
290 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
291 if (err != 0) {
292 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700293 "failed: %s (%d)",
294 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500295 return false;
296 }
297
298 // Vulkan defaults to NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, but this is different than
299 // HWUI's expectation
300 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
301 if (err != 0) {
302 ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700303 "failed: %s (%d)",
304 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500305 return false;
306 }
307
John Reckac513c22019-03-28 16:57:38 -0700308 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500309 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700310 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500311 windowInfo.bufferCount, strerror(-err), err);
312 return false;
313 }
314
315 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
316 if (err != 0) {
317 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
318 strerror(-err), err);
319 return false;
320 }
321
322 return err == 0;
323}
324
325VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
John Reck0fa0cbc2019-04-05 16:57:46 -0700326 SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500327 : mNativeWindow(window)
328 , mWindowInfo(windowInfo)
329 , mGrContext(grContext)
330 , mMinWindowSize(minWindowSize)
John Reck0fa0cbc2019-04-05 16:57:46 -0700331 , mMaxWindowSize(maxWindowSize) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500332
333VulkanSurface::~VulkanSurface() {
334 releaseBuffers();
335
336 // release the native window to be available for use by other clients
337 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
338 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
339}
340
341void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700342 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500343 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
344
345 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
346 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
347 bufferInfo.dequeue_fence);
348 if (err != 0) {
349 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
350 }
351 bufferInfo.dequeued = false;
352
353 if (bufferInfo.dequeue_fence >= 0) {
354 close(bufferInfo.dequeue_fence);
355 bufferInfo.dequeue_fence = -1;
356 }
357 }
358
359 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
360 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
361
362 bufferInfo.skSurface.reset();
363 bufferInfo.buffer.clear();
364 bufferInfo.hasValidContents = false;
365 bufferInfo.lastPresentedCount = 0;
366 }
367}
368
369VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400370 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500371 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400372 mCurrentBufferInfo = nullptr;
373
John Reck0fa0cbc2019-04-05 16:57:46 -0700374 // check if the native window has been resized or rotated and update accordingly
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500375 SkISize newSize = SkISize::MakeEmpty();
376 int transformHint = 0;
377 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth);
378 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &newSize.fHeight);
379 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
380 if (newSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
381 WindowInfo newWindowInfo = mWindowInfo;
382 newWindowInfo.size = newSize;
383 newWindowInfo.transform = IsTransformSupported(transformHint) ? transformHint : 0;
384 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
385
386 int err = 0;
387 if (newWindowInfo.actualSize != mWindowInfo.actualSize) {
388 // reset the native buffers and update the window
389 err = native_window_set_buffers_dimensions(mNativeWindow.get(),
390 newWindowInfo.actualSize.width(),
391 newWindowInfo.actualSize.height());
392 if (err != 0) {
393 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
John Reck0fa0cbc2019-04-05 16:57:46 -0700394 newWindowInfo.actualSize.width(), newWindowInfo.actualSize.height(),
395 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500396 return nullptr;
397 }
398 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
399 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
400 releaseBuffers();
401 // TODO should we ask the nativewindow to allocate buffers?
402 }
403
404 if (newWindowInfo.transform != mWindowInfo.transform) {
405 err = native_window_set_buffers_transform(mNativeWindow.get(),
John Reck0fa0cbc2019-04-05 16:57:46 -0700406 InvertTransform(newWindowInfo.transform));
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500407 if (err != 0) {
408 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
409 newWindowInfo.transform, strerror(-err), err);
410 newWindowInfo.transform = mWindowInfo.transform;
411 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
412 }
413 }
414
415 mWindowInfo = newWindowInfo;
416 }
417
418 ANativeWindowBuffer* buffer;
419 int fence_fd;
420 int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
421 if (err != 0) {
422 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
423 return nullptr;
424 }
425
426 uint32_t idx;
427 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
428 if (mNativeBuffers[idx].buffer.get() == buffer) {
429 mNativeBuffers[idx].dequeued = true;
430 mNativeBuffers[idx].dequeue_fence = fence_fd;
431 break;
432 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
433 // increasing the number of buffers we have allocated
434 mNativeBuffers[idx].buffer = buffer;
435 mNativeBuffers[idx].dequeued = true;
436 mNativeBuffers[idx].dequeue_fence = fence_fd;
437 break;
438 }
439 }
440 if (idx == mWindowInfo.bufferCount) {
441 ALOGE("dequeueBuffer returned unrecognized buffer");
442 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
443 return nullptr;
444 }
445
446 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
447
448 if (bufferInfo->skSurface.get() == nullptr) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700449 bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
450 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
451 kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), nullptr);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500452 if (bufferInfo->skSurface.get() == nullptr) {
453 ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
454 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
455 return nullptr;
456 }
457 }
458
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400459 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500460 return bufferInfo;
461}
462
463bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
464 if (!dirtyRect.isEmpty()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500465
John Reck321d8e52019-04-12 13:06:11 -0700466 // native_window_set_surface_damage takes a rectangle in prerotated space
467 // with a bottom-left origin. That is, top > bottom.
468 // The dirtyRect is also in prerotated space, so we just need to switch it to
469 // a bottom-left origin space.
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500470
John Reck321d8e52019-04-12 13:06:11 -0700471 SkIRect irect;
472 dirtyRect.roundOut(&irect);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500473 android_native_rect_t aRect;
John Reck321d8e52019-04-12 13:06:11 -0700474 aRect.left = irect.left();
475 aRect.top = logicalHeight() - irect.top();
476 aRect.right = irect.right();
477 aRect.bottom = logicalHeight() - irect.bottom();
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500478
479 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
480 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
481 }
482
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400483 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
484 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500485 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
486 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
487
488 currentBuffer.dequeued = false;
489 // queueBuffer always closes fence, even on error
490 if (err != 0) {
491 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
492 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
493 currentBuffer.dequeue_fence);
494 } else {
495 currentBuffer.hasValidContents = true;
496 currentBuffer.lastPresentedCount = mPresentCount;
497 mPresentCount++;
498 }
499
500 if (currentBuffer.dequeue_fence >= 0) {
501 close(currentBuffer.dequeue_fence);
502 currentBuffer.dequeue_fence = -1;
503 }
504
505 return err == 0;
506}
507
508int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400509 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
510 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500511 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
512}
513
514} /* namespace renderthread */
515} /* namespace uirenderer */
516} /* namespace android */