blob: 447512e5db39c81a37b99485a65b8cfd54ed2f84 [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
52static int ConvertVkTransformToNative(VkSurfaceTransformFlagsKHR transform) {
53 switch (transform) {
54 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
55 return NATIVE_WINDOW_TRANSFORM_ROT_270;
56 case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
57 return NATIVE_WINDOW_TRANSFORM_ROT_180;
58 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
59 return NATIVE_WINDOW_TRANSFORM_ROT_90;
60 case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
61 case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
62 default:
63 return 0;
64 }
65}
66
67static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
68 const int width = windowSize.width();
69 const int height = windowSize.height();
70
71 switch (transform) {
72 case 0:
73 return SkMatrix::I();
74 case NATIVE_WINDOW_TRANSFORM_ROT_90:
75 return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
76 case NATIVE_WINDOW_TRANSFORM_ROT_180:
77 return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
78 case NATIVE_WINDOW_TRANSFORM_ROT_270:
79 return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
80 default:
81 LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
82 }
83 return SkMatrix::I();
84}
85
86void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize,
John Reck0fa0cbc2019-04-05 16:57:46 -070087 const SkISize& maxSize) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050088 SkISize& windowSize = windowInfo->size;
89
90 // clamp width & height to handle currentExtent of -1 and protect us from broken hints
John Reck0fa0cbc2019-04-05 16:57:46 -070091 if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width() ||
92 windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050093 int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width()));
94 int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height()));
John Reck0fa0cbc2019-04-05 16:57:46 -070095 ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]", windowSize.width(),
96 windowSize.height(), width, height);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -050097 windowSize.set(width, height);
98 }
99
100 windowInfo->actualSize = windowSize;
101 if (windowInfo->transform & HAL_TRANSFORM_ROT_90) {
102 windowInfo->actualSize.set(windowSize.height(), windowSize.width());
103 }
104
105 windowInfo->preTransform = GetPreTransformMatrix(windowInfo->size, windowInfo->transform);
106}
107
108static bool ResetNativeWindow(ANativeWindow* window) {
109 // -- Reset the native window --
110 // The native window might have been used previously, and had its properties
111 // changed from defaults. That will affect the answer we get for queries
112 // like MIN_UNDEQUEUED_BUFFERS. Reset to a known/default state before we
113 // attempt such queries.
114
115 int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
116 if (err != 0) {
117 ALOGW("native_window_api_connect failed: %s (%d)", strerror(-err), err);
118 return false;
119 }
120
121 // this will match what we do on GL so pick that here.
122 err = window->setSwapInterval(window, 1);
123 if (err != 0) {
124 ALOGW("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
125 return false;
126 }
127
128 err = native_window_set_shared_buffer_mode(window, false);
129 if (err != 0) {
130 ALOGW("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
131 return false;
132 }
133
134 err = native_window_set_auto_refresh(window, false);
135 if (err != 0) {
136 ALOGW("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
137 return false;
138 }
139
140 return true;
141}
142
143class VkSurfaceAutoDeleter {
144public:
145 VkSurfaceAutoDeleter(VkInstance instance, VkSurfaceKHR surface,
146 PFN_vkDestroySurfaceKHR destroySurfaceKHR)
John Reck0fa0cbc2019-04-05 16:57:46 -0700147 : mInstance(instance), mSurface(surface), mDestroySurfaceKHR(destroySurfaceKHR) {}
148 ~VkSurfaceAutoDeleter() { destroy(); }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500149
150 void destroy() {
151 if (mSurface != VK_NULL_HANDLE) {
152 mDestroySurfaceKHR(mInstance, mSurface, nullptr);
153 mSurface = VK_NULL_HANDLE;
154 }
155 }
156
157private:
158 VkInstance mInstance;
159 VkSurfaceKHR mSurface;
160 PFN_vkDestroySurfaceKHR mDestroySurfaceKHR;
161};
162
163VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
John Reck0fa0cbc2019-04-05 16:57:46 -0700164 SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
165 GrContext* grContext, const VulkanManager& vkManager,
166 uint32_t extraBuffers) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500167 VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
168 memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
169 surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
170 surfaceCreateInfo.pNext = nullptr;
171 surfaceCreateInfo.flags = 0;
172 surfaceCreateInfo.window = window;
173
174 VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
175 VkResult res = vkManager.mCreateAndroidSurfaceKHR(vkManager.mInstance, &surfaceCreateInfo,
176 nullptr, &vkSurface);
177 if (VK_SUCCESS != res) {
178 ALOGE("VulkanSurface::Create() vkCreateAndroidSurfaceKHR failed (%d)", res);
179 return nullptr;
180 }
181
182 VkSurfaceAutoDeleter vkSurfaceDeleter(vkManager.mInstance, vkSurface,
183 vkManager.mDestroySurfaceKHR);
184
185 SkDEBUGCODE(VkBool32 supported; res = vkManager.mGetPhysicalDeviceSurfaceSupportKHR(
John Reck0fa0cbc2019-04-05 16:57:46 -0700186 vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex,
187 vkSurface, &supported);
188 // All physical devices and queue families on Android must be capable of
189 // presentation with any native window.
190 SkASSERT(VK_SUCCESS == res && supported););
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500191
192 // check for capabilities
193 VkSurfaceCapabilitiesKHR caps;
194 res = vkManager.mGetPhysicalDeviceSurfaceCapabilitiesKHR(vkManager.mPhysicalDevice, vkSurface,
195 &caps);
196 if (VK_SUCCESS != res) {
197 ALOGE("VulkanSurface::Create() vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed (%d)", res);
198 return nullptr;
199 }
200
201 LOG_ALWAYS_FATAL_IF(0 == (caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR));
202
203 /*
204 * We must destroy the VK Surface before attempting to update the window as doing so after
205 * will cause the native window to be modified in unexpected ways.
206 */
207 vkSurfaceDeleter.destroy();
208
209 /*
210 * Populate Window Info struct
211 */
212 WindowInfo windowInfo;
213
214 windowInfo.transform = ConvertVkTransformToNative(caps.supportedTransforms);
215 windowInfo.size = SkISize::Make(caps.currentExtent.width, caps.currentExtent.height);
216
217 const SkISize minSize = SkISize::Make(caps.minImageExtent.width, caps.minImageExtent.height);
218 const SkISize maxSize = SkISize::Make(caps.maxImageExtent.width, caps.maxImageExtent.height);
219 ComputeWindowSizeAndTransform(&windowInfo, minSize, maxSize);
220
John Reckac513c22019-03-28 16:57:38 -0700221 int query_value;
222 int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
223 if (err != 0 || query_value < 0) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700224 ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
John Reckac513c22019-03-28 16:57:38 -0700225 return nullptr;
226 }
227 auto min_undequeued_buffers = static_cast<uint32_t>(query_value);
228
John Reck0fa0cbc2019-04-05 16:57:46 -0700229 windowInfo.bufferCount = min_undequeued_buffers +
230 std::max(sTargetBufferCount + extraBuffers, caps.minImageCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500231 if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) {
232 // Application must settle for fewer images than desired:
233 windowInfo.bufferCount = caps.maxImageCount;
234 }
235
236 // Currently Skia requires the images to be color attachments and support all transfer
237 // operations.
238 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
John Reck0fa0cbc2019-04-05 16:57:46 -0700239 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500240 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
241 LOG_ALWAYS_FATAL_IF((caps.supportedUsageFlags & usageFlags) != usageFlags);
242
243 windowInfo.dataspace = HAL_DATASPACE_V0_SRGB;
244 if (colorMode == ColorMode::WideColorGamut) {
245 skcms_Matrix3x3 surfaceGamut;
246 LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut),
247 "Could not get gamut matrix from color space");
248 if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
249 windowInfo.dataspace = HAL_DATASPACE_V0_SCRGB;
250 } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
251 windowInfo.dataspace = HAL_DATASPACE_DISPLAY_P3;
252 } else {
253 LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
254 }
255 }
256
257 windowInfo.pixelFormat = ColorTypeToPixelFormat(colorType);
258 VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
259 if (windowInfo.pixelFormat == PIXEL_FORMAT_RGBA_FP16) {
260 vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
261 }
262
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400263 if (nullptr != vkManager.mGetPhysicalDeviceImageFormatProperties2) {
264 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
265 externalImageFormatInfo.sType =
266 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
267 externalImageFormatInfo.pNext = nullptr;
268 externalImageFormatInfo.handleType =
269 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
270
271 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
272 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
273 imageFormatInfo.pNext = &externalImageFormatInfo;
274 imageFormatInfo.format = vkPixelFormat;
275 imageFormatInfo.type = VK_IMAGE_TYPE_2D;
276 imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
277 imageFormatInfo.usage = usageFlags;
278 imageFormatInfo.flags = 0;
279
280 VkAndroidHardwareBufferUsageANDROID hwbUsage;
281 hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
282 hwbUsage.pNext = nullptr;
283
284 VkImageFormatProperties2 imgFormProps;
285 imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
286 imgFormProps.pNext = &hwbUsage;
287
288 res = vkManager.mGetPhysicalDeviceImageFormatProperties2(vkManager.mPhysicalDevice,
289 &imageFormatInfo, &imgFormProps);
290 if (VK_SUCCESS != res) {
291 ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
292 return nullptr;
293 }
294
295 windowInfo.windowUsageFlags = hwbUsage.androidHardwareBufferUsage;
Greg Daniel2173f182019-04-01 09:29:44 -0400296 if (vkManager.isQualcomm()) {
297 windowInfo.windowUsageFlags =
298 windowInfo.windowUsageFlags | AHARDWAREBUFFER_USAGE_VENDOR_0;
299 }
Derek Sollenberger31c1b822019-03-19 13:55:10 -0400300
301 } else {
302 ALOGE("VulkanSurface::Create() vkmGetPhysicalDeviceImageFormatProperties2 is missing");
303 return nullptr;
304 }
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500305
306 /*
307 * Now we attempt to modify the window!
308 */
309 if (!UpdateWindow(window, windowInfo)) {
310 return nullptr;
311 }
312
313 return new VulkanSurface(window, windowInfo, minSize, maxSize, grContext);
314}
315
316bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
317 ATRACE_CALL();
318
319 if (!ResetNativeWindow(window)) {
320 return false;
321 }
322
323 // -- Configure the native window --
324 int err = native_window_set_buffers_format(window, windowInfo.pixelFormat);
325 if (err != 0) {
326 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
327 windowInfo.pixelFormat, strerror(-err), err);
328 return false;
329 }
330
331 err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
332 if (err != 0) {
333 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700334 "failed: %s (%d)",
335 windowInfo.dataspace, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500336 return false;
337 }
338
339 const SkISize& size = windowInfo.actualSize;
340 err = native_window_set_buffers_dimensions(window, size.width(), size.height());
341 if (err != 0) {
342 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700343 "failed: %s (%d)",
344 size.width(), size.height(), strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500345 return false;
346 }
347
348 // native_window_set_buffers_transform() expects the transform the app is requesting that
349 // the compositor perform during composition. With native windows, pre-transform works by
350 // rendering with the same transform the compositor is applying (as in Vulkan), but
351 // then requesting the inverse transform, so that when the compositor does
352 // it's job the two transforms cancel each other out and the compositor ends
353 // up applying an identity transform to the app's buffer.
354 err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
355 if (err != 0) {
356 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700357 "failed: %s (%d)",
358 windowInfo.transform, strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500359 return false;
360 }
361
362 // Vulkan defaults to NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, but this is different than
363 // HWUI's expectation
364 err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
365 if (err != 0) {
366 ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) "
John Reck0fa0cbc2019-04-05 16:57:46 -0700367 "failed: %s (%d)",
368 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500369 return false;
370 }
371
John Reckac513c22019-03-28 16:57:38 -0700372 err = native_window_set_buffer_count(window, windowInfo.bufferCount);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500373 if (err != 0) {
John Reckac513c22019-03-28 16:57:38 -0700374 ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500375 windowInfo.bufferCount, strerror(-err), err);
376 return false;
377 }
378
379 err = native_window_set_usage(window, windowInfo.windowUsageFlags);
380 if (err != 0) {
381 ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
382 strerror(-err), err);
383 return false;
384 }
385
386 return err == 0;
387}
388
389VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
John Reck0fa0cbc2019-04-05 16:57:46 -0700390 SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500391 : mNativeWindow(window)
392 , mWindowInfo(windowInfo)
393 , mGrContext(grContext)
394 , mMinWindowSize(minWindowSize)
John Reck0fa0cbc2019-04-05 16:57:46 -0700395 , mMaxWindowSize(maxWindowSize) {}
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500396
397VulkanSurface::~VulkanSurface() {
398 releaseBuffers();
399
400 // release the native window to be available for use by other clients
401 int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
402 ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
403}
404
405void VulkanSurface::releaseBuffers() {
John Reckac513c22019-03-28 16:57:38 -0700406 for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500407 VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
408
409 if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
410 int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
411 bufferInfo.dequeue_fence);
412 if (err != 0) {
413 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
414 }
415 bufferInfo.dequeued = false;
416
417 if (bufferInfo.dequeue_fence >= 0) {
418 close(bufferInfo.dequeue_fence);
419 bufferInfo.dequeue_fence = -1;
420 }
421 }
422
423 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
424 LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
425
426 bufferInfo.skSurface.reset();
427 bufferInfo.buffer.clear();
428 bufferInfo.hasValidContents = false;
429 bufferInfo.lastPresentedCount = 0;
430 }
431}
432
433VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400434 // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500435 // value at the end of the function if everything dequeued correctly.
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400436 mCurrentBufferInfo = nullptr;
437
John Reck0fa0cbc2019-04-05 16:57:46 -0700438 // check if the native window has been resized or rotated and update accordingly
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500439 SkISize newSize = SkISize::MakeEmpty();
440 int transformHint = 0;
441 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth);
442 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &newSize.fHeight);
443 mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
444 if (newSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
445 WindowInfo newWindowInfo = mWindowInfo;
446 newWindowInfo.size = newSize;
447 newWindowInfo.transform = IsTransformSupported(transformHint) ? transformHint : 0;
448 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
449
450 int err = 0;
451 if (newWindowInfo.actualSize != mWindowInfo.actualSize) {
452 // reset the native buffers and update the window
453 err = native_window_set_buffers_dimensions(mNativeWindow.get(),
454 newWindowInfo.actualSize.width(),
455 newWindowInfo.actualSize.height());
456 if (err != 0) {
457 ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
John Reck0fa0cbc2019-04-05 16:57:46 -0700458 newWindowInfo.actualSize.width(), newWindowInfo.actualSize.height(),
459 strerror(-err), err);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500460 return nullptr;
461 }
462 // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
463 // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
464 releaseBuffers();
465 // TODO should we ask the nativewindow to allocate buffers?
466 }
467
468 if (newWindowInfo.transform != mWindowInfo.transform) {
469 err = native_window_set_buffers_transform(mNativeWindow.get(),
John Reck0fa0cbc2019-04-05 16:57:46 -0700470 InvertTransform(newWindowInfo.transform));
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500471 if (err != 0) {
472 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
473 newWindowInfo.transform, strerror(-err), err);
474 newWindowInfo.transform = mWindowInfo.transform;
475 ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
476 }
477 }
478
479 mWindowInfo = newWindowInfo;
480 }
481
482 ANativeWindowBuffer* buffer;
483 int fence_fd;
484 int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
485 if (err != 0) {
486 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
487 return nullptr;
488 }
489
490 uint32_t idx;
491 for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
492 if (mNativeBuffers[idx].buffer.get() == buffer) {
493 mNativeBuffers[idx].dequeued = true;
494 mNativeBuffers[idx].dequeue_fence = fence_fd;
495 break;
496 } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
497 // increasing the number of buffers we have allocated
498 mNativeBuffers[idx].buffer = buffer;
499 mNativeBuffers[idx].dequeued = true;
500 mNativeBuffers[idx].dequeue_fence = fence_fd;
501 break;
502 }
503 }
504 if (idx == mWindowInfo.bufferCount) {
505 ALOGE("dequeueBuffer returned unrecognized buffer");
506 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
507 return nullptr;
508 }
509
510 VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
511
512 if (bufferInfo->skSurface.get() == nullptr) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700513 bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
514 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
515 kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), nullptr);
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500516 if (bufferInfo->skSurface.get() == nullptr) {
517 ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
518 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
519 return nullptr;
520 }
521 }
522
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400523 mCurrentBufferInfo = bufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500524 return bufferInfo;
525}
526
527bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
528 if (!dirtyRect.isEmpty()) {
529 SkRect transformedRect;
530 mWindowInfo.preTransform.mapRect(&transformedRect, dirtyRect);
531
532 SkIRect transformedIRect;
533 transformedRect.roundOut(&transformedIRect);
534 transformedIRect.intersect(0, 0, mWindowInfo.size.fWidth, mWindowInfo.size.fHeight);
535
536 // map to bottom-left coordinate system
537 android_native_rect_t aRect;
538 aRect.left = transformedIRect.x();
539 aRect.top = mWindowInfo.size.fHeight - (transformedIRect.y() + transformedIRect.height());
540 aRect.right = aRect.left + transformedIRect.width();
541 aRect.bottom = aRect.top - transformedIRect.height();
542
543 int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
544 ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
545 }
546
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400547 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
548 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500549 int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
550 int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
551
552 currentBuffer.dequeued = false;
553 // queueBuffer always closes fence, even on error
554 if (err != 0) {
555 ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
556 mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
557 currentBuffer.dequeue_fence);
558 } else {
559 currentBuffer.hasValidContents = true;
560 currentBuffer.lastPresentedCount = mPresentCount;
561 mPresentCount++;
562 }
563
564 if (currentBuffer.dequeue_fence >= 0) {
565 close(currentBuffer.dequeue_fence);
566 currentBuffer.dequeue_fence = -1;
567 }
568
569 return err == 0;
570}
571
572int VulkanSurface::getCurrentBuffersAge() {
Stan Ilievbc5f06b2019-03-26 15:14:34 -0400573 LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
574 VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
Derek Sollenbergera19b71a2019-02-15 16:36:30 -0500575 return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
576}
577
578} /* namespace renderthread */
579} /* namespace uirenderer */
580} /* namespace android */