xref: /aosp_15_r20/frameworks/base/libs/hwui/renderthread/VulkanSurface.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "VulkanSurface.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <SkSurface.h>
20*d57664e9SAndroid Build Coastguard Worker #include <gui/TraceUtils.h>
21*d57664e9SAndroid Build Coastguard Worker #include <include/android/SkSurfaceAndroid.h>
22*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/GrDirectContext.h>
23*d57664e9SAndroid Build Coastguard Worker 
24*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
25*d57664e9SAndroid Build Coastguard Worker 
26*d57664e9SAndroid Build Coastguard Worker #include "VulkanManager.h"
27*d57664e9SAndroid Build Coastguard Worker #include "utils/Color.h"
28*d57664e9SAndroid Build Coastguard Worker 
29*d57664e9SAndroid Build Coastguard Worker namespace android {
30*d57664e9SAndroid Build Coastguard Worker namespace uirenderer {
31*d57664e9SAndroid Build Coastguard Worker namespace renderthread {
32*d57664e9SAndroid Build Coastguard Worker 
33*d57664e9SAndroid Build Coastguard Worker static constexpr auto P3_XRB = static_cast<android_dataspace>(
34*d57664e9SAndroid Build Coastguard Worker         ADATASPACE_STANDARD_DCI_P3 | ADATASPACE_TRANSFER_SRGB | ADATASPACE_RANGE_EXTENDED);
35*d57664e9SAndroid Build Coastguard Worker 
InvertTransform(int transform)36*d57664e9SAndroid Build Coastguard Worker static int InvertTransform(int transform) {
37*d57664e9SAndroid Build Coastguard Worker     switch (transform) {
38*d57664e9SAndroid Build Coastguard Worker         case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
39*d57664e9SAndroid Build Coastguard Worker             return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
40*d57664e9SAndroid Build Coastguard Worker         case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
41*d57664e9SAndroid Build Coastguard Worker             return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
42*d57664e9SAndroid Build Coastguard Worker         case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
43*d57664e9SAndroid Build Coastguard Worker             return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
44*d57664e9SAndroid Build Coastguard Worker         default:
45*d57664e9SAndroid Build Coastguard Worker             return 0;
46*d57664e9SAndroid Build Coastguard Worker     }
47*d57664e9SAndroid Build Coastguard Worker }
48*d57664e9SAndroid Build Coastguard Worker 
GetPreTransformMatrix(SkISize windowSize,int transform)49*d57664e9SAndroid Build Coastguard Worker static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
50*d57664e9SAndroid Build Coastguard Worker     const int width = windowSize.width();
51*d57664e9SAndroid Build Coastguard Worker     const int height = windowSize.height();
52*d57664e9SAndroid Build Coastguard Worker 
53*d57664e9SAndroid Build Coastguard Worker     switch (transform) {
54*d57664e9SAndroid Build Coastguard Worker         case 0:
55*d57664e9SAndroid Build Coastguard Worker             return SkMatrix::I();
56*d57664e9SAndroid Build Coastguard Worker         case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
57*d57664e9SAndroid Build Coastguard Worker             return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
58*d57664e9SAndroid Build Coastguard Worker         case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
59*d57664e9SAndroid Build Coastguard Worker             return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
60*d57664e9SAndroid Build Coastguard Worker         case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
61*d57664e9SAndroid Build Coastguard Worker             return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
62*d57664e9SAndroid Build Coastguard Worker         default:
63*d57664e9SAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
64*d57664e9SAndroid Build Coastguard Worker     }
65*d57664e9SAndroid Build Coastguard Worker     return SkMatrix::I();
66*d57664e9SAndroid Build Coastguard Worker }
67*d57664e9SAndroid Build Coastguard Worker 
GetPixelSnapMatrix(SkISize windowSize,int transform)68*d57664e9SAndroid Build Coastguard Worker static SkM44 GetPixelSnapMatrix(SkISize windowSize, int transform) {
69*d57664e9SAndroid Build Coastguard Worker     // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
70*d57664e9SAndroid Build Coastguard Worker     // desired fragment
71*d57664e9SAndroid Build Coastguard Worker     static const SkScalar kOffset = 0.063f;
72*d57664e9SAndroid Build Coastguard Worker     SkMatrix preRotation = GetPreTransformMatrix(windowSize, transform);
73*d57664e9SAndroid Build Coastguard Worker     SkMatrix invert;
74*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(!preRotation.invert(&invert));
75*d57664e9SAndroid Build Coastguard Worker     return SkM44::Translate(kOffset, kOffset)
76*d57664e9SAndroid Build Coastguard Worker             .postConcat(SkM44(preRotation))
77*d57664e9SAndroid Build Coastguard Worker             .preConcat(SkM44(invert));
78*d57664e9SAndroid Build Coastguard Worker }
79*d57664e9SAndroid Build Coastguard Worker 
ConnectAndSetWindowDefaults(ANativeWindow * window)80*d57664e9SAndroid Build Coastguard Worker static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
81*d57664e9SAndroid Build Coastguard Worker     ATRACE_CALL();
82*d57664e9SAndroid Build Coastguard Worker 
83*d57664e9SAndroid Build Coastguard Worker     int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
84*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
85*d57664e9SAndroid Build Coastguard Worker         ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), err);
86*d57664e9SAndroid Build Coastguard Worker         return false;
87*d57664e9SAndroid Build Coastguard Worker     }
88*d57664e9SAndroid Build Coastguard Worker 
89*d57664e9SAndroid Build Coastguard Worker     // this will match what we do on GL so pick that here.
90*d57664e9SAndroid Build Coastguard Worker     err = window->setSwapInterval(window, 1);
91*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
92*d57664e9SAndroid Build Coastguard Worker         ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
93*d57664e9SAndroid Build Coastguard Worker         return false;
94*d57664e9SAndroid Build Coastguard Worker     }
95*d57664e9SAndroid Build Coastguard Worker 
96*d57664e9SAndroid Build Coastguard Worker     err = native_window_set_shared_buffer_mode(window, false);
97*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
98*d57664e9SAndroid Build Coastguard Worker         ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
99*d57664e9SAndroid Build Coastguard Worker         return false;
100*d57664e9SAndroid Build Coastguard Worker     }
101*d57664e9SAndroid Build Coastguard Worker 
102*d57664e9SAndroid Build Coastguard Worker     err = native_window_set_auto_refresh(window, false);
103*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
104*d57664e9SAndroid Build Coastguard Worker         ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
105*d57664e9SAndroid Build Coastguard Worker         return false;
106*d57664e9SAndroid Build Coastguard Worker     }
107*d57664e9SAndroid Build Coastguard Worker 
108*d57664e9SAndroid Build Coastguard Worker     err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
109*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
110*d57664e9SAndroid Build Coastguard Worker         ALOGE("native_window_set_scaling_mode(NATIVE_WINDOW_SCALING_MODE_FREEZE) failed: %s (%d)",
111*d57664e9SAndroid Build Coastguard Worker               strerror(-err), err);
112*d57664e9SAndroid Build Coastguard Worker         return false;
113*d57664e9SAndroid Build Coastguard Worker     }
114*d57664e9SAndroid Build Coastguard Worker 
115*d57664e9SAndroid Build Coastguard Worker     // Let consumer drive the size of the buffers.
116*d57664e9SAndroid Build Coastguard Worker     err = native_window_set_buffers_dimensions(window, 0, 0);
117*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
118*d57664e9SAndroid Build Coastguard Worker         ALOGE("native_window_set_buffers_dimensions(0,0) failed: %s (%d)", strerror(-err), err);
119*d57664e9SAndroid Build Coastguard Worker         return false;
120*d57664e9SAndroid Build Coastguard Worker     }
121*d57664e9SAndroid Build Coastguard Worker 
122*d57664e9SAndroid Build Coastguard Worker     // Enable auto prerotation, so when buffer size is driven by the consumer
123*d57664e9SAndroid Build Coastguard Worker     // and the transform hint specifies a 90 or 270 degree rotation, the width
124*d57664e9SAndroid Build Coastguard Worker     // and height used for buffer pre-allocation and dequeueBuffer will be
125*d57664e9SAndroid Build Coastguard Worker     // additionally swapped.
126*d57664e9SAndroid Build Coastguard Worker     err = native_window_set_auto_prerotation(window, true);
127*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
128*d57664e9SAndroid Build Coastguard Worker         ALOGE("VulkanSurface::UpdateWindow() native_window_set_auto_prerotation failed: %s (%d)",
129*d57664e9SAndroid Build Coastguard Worker               strerror(-err), err);
130*d57664e9SAndroid Build Coastguard Worker         return false;
131*d57664e9SAndroid Build Coastguard Worker     }
132*d57664e9SAndroid Build Coastguard Worker 
133*d57664e9SAndroid Build Coastguard Worker     return true;
134*d57664e9SAndroid Build Coastguard Worker }
135*d57664e9SAndroid Build Coastguard Worker 
Create(ANativeWindow * window,ColorMode colorMode,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,GrDirectContext * grContext,const VulkanManager & vkManager,uint32_t extraBuffers)136*d57664e9SAndroid Build Coastguard Worker VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
137*d57664e9SAndroid Build Coastguard Worker                                      SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
138*d57664e9SAndroid Build Coastguard Worker                                      GrDirectContext* grContext, const VulkanManager& vkManager,
139*d57664e9SAndroid Build Coastguard Worker                                      uint32_t extraBuffers) {
140*d57664e9SAndroid Build Coastguard Worker     // Connect and set native window to default configurations.
141*d57664e9SAndroid Build Coastguard Worker     if (!ConnectAndSetWindowDefaults(window)) {
142*d57664e9SAndroid Build Coastguard Worker         return nullptr;
143*d57664e9SAndroid Build Coastguard Worker     }
144*d57664e9SAndroid Build Coastguard Worker 
145*d57664e9SAndroid Build Coastguard Worker     // Initialize WindowInfo struct.
146*d57664e9SAndroid Build Coastguard Worker     WindowInfo windowInfo;
147*d57664e9SAndroid Build Coastguard Worker     if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
148*d57664e9SAndroid Build Coastguard Worker                                     extraBuffers, &windowInfo)) {
149*d57664e9SAndroid Build Coastguard Worker         return nullptr;
150*d57664e9SAndroid Build Coastguard Worker     }
151*d57664e9SAndroid Build Coastguard Worker 
152*d57664e9SAndroid Build Coastguard Worker     // Now we attempt to modify the window.
153*d57664e9SAndroid Build Coastguard Worker     if (!UpdateWindow(window, windowInfo)) {
154*d57664e9SAndroid Build Coastguard Worker         return nullptr;
155*d57664e9SAndroid Build Coastguard Worker     }
156*d57664e9SAndroid Build Coastguard Worker 
157*d57664e9SAndroid Build Coastguard Worker     return new VulkanSurface(window, windowInfo, grContext);
158*d57664e9SAndroid Build Coastguard Worker }
159*d57664e9SAndroid Build Coastguard Worker 
InitializeWindowInfoStruct(ANativeWindow * window,ColorMode colorMode,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const VulkanManager & vkManager,uint32_t extraBuffers,WindowInfo * outWindowInfo)160*d57664e9SAndroid Build Coastguard Worker bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
161*d57664e9SAndroid Build Coastguard Worker                                                SkColorType colorType,
162*d57664e9SAndroid Build Coastguard Worker                                                sk_sp<SkColorSpace> colorSpace,
163*d57664e9SAndroid Build Coastguard Worker                                                const VulkanManager& vkManager,
164*d57664e9SAndroid Build Coastguard Worker                                                uint32_t extraBuffers, WindowInfo* outWindowInfo) {
165*d57664e9SAndroid Build Coastguard Worker     ATRACE_CALL();
166*d57664e9SAndroid Build Coastguard Worker 
167*d57664e9SAndroid Build Coastguard Worker     int width, height;
168*d57664e9SAndroid Build Coastguard Worker     int err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
169*d57664e9SAndroid Build Coastguard Worker     if (err != 0 || width < 0) {
170*d57664e9SAndroid Build Coastguard Worker         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, width);
171*d57664e9SAndroid Build Coastguard Worker         return false;
172*d57664e9SAndroid Build Coastguard Worker     }
173*d57664e9SAndroid Build Coastguard Worker     err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
174*d57664e9SAndroid Build Coastguard Worker     if (err != 0 || height < 0) {
175*d57664e9SAndroid Build Coastguard Worker         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, height);
176*d57664e9SAndroid Build Coastguard Worker         return false;
177*d57664e9SAndroid Build Coastguard Worker     }
178*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->size = SkISize::Make(width, height);
179*d57664e9SAndroid Build Coastguard Worker 
180*d57664e9SAndroid Build Coastguard Worker     int query_value;
181*d57664e9SAndroid Build Coastguard Worker     err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &query_value);
182*d57664e9SAndroid Build Coastguard Worker     if (err != 0 || query_value < 0) {
183*d57664e9SAndroid Build Coastguard Worker         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
184*d57664e9SAndroid Build Coastguard Worker         return false;
185*d57664e9SAndroid Build Coastguard Worker     }
186*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->transform = query_value;
187*d57664e9SAndroid Build Coastguard Worker 
188*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->actualSize = outWindowInfo->size;
189*d57664e9SAndroid Build Coastguard Worker     if (outWindowInfo->transform & ANATIVEWINDOW_TRANSFORM_ROTATE_90) {
190*d57664e9SAndroid Build Coastguard Worker         outWindowInfo->actualSize.set(outWindowInfo->size.height(), outWindowInfo->size.width());
191*d57664e9SAndroid Build Coastguard Worker     }
192*d57664e9SAndroid Build Coastguard Worker 
193*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->preTransform =
194*d57664e9SAndroid Build Coastguard Worker             GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
195*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->pixelSnapMatrix =
196*d57664e9SAndroid Build Coastguard Worker             GetPixelSnapMatrix(outWindowInfo->size, outWindowInfo->transform);
197*d57664e9SAndroid Build Coastguard Worker 
198*d57664e9SAndroid Build Coastguard Worker     err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
199*d57664e9SAndroid Build Coastguard Worker     if (err != 0 || query_value < 0) {
200*d57664e9SAndroid Build Coastguard Worker         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
201*d57664e9SAndroid Build Coastguard Worker         return false;
202*d57664e9SAndroid Build Coastguard Worker     }
203*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->bufferCount =
204*d57664e9SAndroid Build Coastguard Worker             static_cast<uint32_t>(query_value) + sTargetBufferCount + extraBuffers;
205*d57664e9SAndroid Build Coastguard Worker 
206*d57664e9SAndroid Build Coastguard Worker     err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
207*d57664e9SAndroid Build Coastguard Worker     if (err != 0 || query_value < 0) {
208*d57664e9SAndroid Build Coastguard Worker         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value);
209*d57664e9SAndroid Build Coastguard Worker         return false;
210*d57664e9SAndroid Build Coastguard Worker     }
211*d57664e9SAndroid Build Coastguard Worker     if (outWindowInfo->bufferCount > static_cast<uint32_t>(query_value)) {
212*d57664e9SAndroid Build Coastguard Worker         // Application must settle for fewer images than desired:
213*d57664e9SAndroid Build Coastguard Worker         outWindowInfo->bufferCount = static_cast<uint32_t>(query_value);
214*d57664e9SAndroid Build Coastguard Worker     }
215*d57664e9SAndroid Build Coastguard Worker 
216*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
217*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->colorspace = colorSpace;
218*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->colorMode = colorMode;
219*d57664e9SAndroid Build Coastguard Worker 
220*d57664e9SAndroid Build Coastguard Worker     if (colorMode == ColorMode::Hdr || colorMode == ColorMode::Hdr10) {
221*d57664e9SAndroid Build Coastguard Worker         outWindowInfo->dataspace = P3_XRB;
222*d57664e9SAndroid Build Coastguard Worker     } else {
223*d57664e9SAndroid Build Coastguard Worker         outWindowInfo->dataspace = ColorSpaceToADataSpace(colorSpace.get(), colorType);
224*d57664e9SAndroid Build Coastguard Worker     }
225*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(
226*d57664e9SAndroid Build Coastguard Worker             outWindowInfo->dataspace == HAL_DATASPACE_UNKNOWN && colorType != kAlpha_8_SkColorType,
227*d57664e9SAndroid Build Coastguard Worker             "Unsupported colorspace");
228*d57664e9SAndroid Build Coastguard Worker 
229*d57664e9SAndroid Build Coastguard Worker     VkFormat vkPixelFormat;
230*d57664e9SAndroid Build Coastguard Worker     switch (colorType) {
231*d57664e9SAndroid Build Coastguard Worker         case kRGBA_8888_SkColorType:
232*d57664e9SAndroid Build Coastguard Worker             vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
233*d57664e9SAndroid Build Coastguard Worker             break;
234*d57664e9SAndroid Build Coastguard Worker         case kRGBA_F16_SkColorType:
235*d57664e9SAndroid Build Coastguard Worker             vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
236*d57664e9SAndroid Build Coastguard Worker             break;
237*d57664e9SAndroid Build Coastguard Worker         case kRGBA_1010102_SkColorType:
238*d57664e9SAndroid Build Coastguard Worker             vkPixelFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
239*d57664e9SAndroid Build Coastguard Worker             break;
240*d57664e9SAndroid Build Coastguard Worker         case kAlpha_8_SkColorType:
241*d57664e9SAndroid Build Coastguard Worker             vkPixelFormat = VK_FORMAT_R8_UNORM;
242*d57664e9SAndroid Build Coastguard Worker             break;
243*d57664e9SAndroid Build Coastguard Worker         default:
244*d57664e9SAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL("Unsupported colorType: %d", (int)colorType);
245*d57664e9SAndroid Build Coastguard Worker     }
246*d57664e9SAndroid Build Coastguard Worker 
247*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
248*d57664e9SAndroid Build Coastguard Worker                         "vkGetPhysicalDeviceImageFormatProperties2 is missing");
249*d57664e9SAndroid Build Coastguard Worker     VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
250*d57664e9SAndroid Build Coastguard Worker     externalImageFormatInfo.sType =
251*d57664e9SAndroid Build Coastguard Worker             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
252*d57664e9SAndroid Build Coastguard Worker     externalImageFormatInfo.pNext = nullptr;
253*d57664e9SAndroid Build Coastguard Worker     externalImageFormatInfo.handleType =
254*d57664e9SAndroid Build Coastguard Worker             VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
255*d57664e9SAndroid Build Coastguard Worker 
256*d57664e9SAndroid Build Coastguard Worker     VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
257*d57664e9SAndroid Build Coastguard Worker     imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
258*d57664e9SAndroid Build Coastguard Worker     imageFormatInfo.pNext = &externalImageFormatInfo;
259*d57664e9SAndroid Build Coastguard Worker     imageFormatInfo.format = vkPixelFormat;
260*d57664e9SAndroid Build Coastguard Worker     imageFormatInfo.type = VK_IMAGE_TYPE_2D;
261*d57664e9SAndroid Build Coastguard Worker     imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
262*d57664e9SAndroid Build Coastguard Worker     // Currently Skia requires the images to be color attachments and support all transfer
263*d57664e9SAndroid Build Coastguard Worker     // operations.
264*d57664e9SAndroid Build Coastguard Worker     imageFormatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
265*d57664e9SAndroid Build Coastguard Worker                             VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
266*d57664e9SAndroid Build Coastguard Worker     imageFormatInfo.flags = 0;
267*d57664e9SAndroid Build Coastguard Worker 
268*d57664e9SAndroid Build Coastguard Worker     VkAndroidHardwareBufferUsageANDROID hwbUsage;
269*d57664e9SAndroid Build Coastguard Worker     hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
270*d57664e9SAndroid Build Coastguard Worker     hwbUsage.pNext = nullptr;
271*d57664e9SAndroid Build Coastguard Worker 
272*d57664e9SAndroid Build Coastguard Worker     VkImageFormatProperties2 imgFormProps;
273*d57664e9SAndroid Build Coastguard Worker     imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
274*d57664e9SAndroid Build Coastguard Worker     imgFormProps.pNext = &hwbUsage;
275*d57664e9SAndroid Build Coastguard Worker 
276*d57664e9SAndroid Build Coastguard Worker     VkResult res = vkManager.mGetPhysicalDeviceImageFormatProperties2(
277*d57664e9SAndroid Build Coastguard Worker             vkManager.mPhysicalDevice, &imageFormatInfo, &imgFormProps);
278*d57664e9SAndroid Build Coastguard Worker     if (VK_SUCCESS != res) {
279*d57664e9SAndroid Build Coastguard Worker         ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
280*d57664e9SAndroid Build Coastguard Worker         return false;
281*d57664e9SAndroid Build Coastguard Worker     }
282*d57664e9SAndroid Build Coastguard Worker 
283*d57664e9SAndroid Build Coastguard Worker     uint64_t consumerUsage;
284*d57664e9SAndroid Build Coastguard Worker     err = native_window_get_consumer_usage(window, &consumerUsage);
285*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
286*d57664e9SAndroid Build Coastguard Worker         ALOGE("native_window_get_consumer_usage failed: %s (%d)", strerror(-err), err);
287*d57664e9SAndroid Build Coastguard Worker         return false;
288*d57664e9SAndroid Build Coastguard Worker     }
289*d57664e9SAndroid Build Coastguard Worker     outWindowInfo->windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
290*d57664e9SAndroid Build Coastguard Worker 
291*d57664e9SAndroid Build Coastguard Worker     return true;
292*d57664e9SAndroid Build Coastguard Worker }
293*d57664e9SAndroid Build Coastguard Worker 
UpdateWindow(ANativeWindow * window,const WindowInfo & windowInfo)294*d57664e9SAndroid Build Coastguard Worker bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
295*d57664e9SAndroid Build Coastguard Worker     ATRACE_CALL();
296*d57664e9SAndroid Build Coastguard Worker 
297*d57664e9SAndroid Build Coastguard Worker     int err = native_window_set_buffers_format(window, windowInfo.bufferFormat);
298*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
299*d57664e9SAndroid Build Coastguard Worker         ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
300*d57664e9SAndroid Build Coastguard Worker               windowInfo.bufferFormat, strerror(-err), err);
301*d57664e9SAndroid Build Coastguard Worker         return false;
302*d57664e9SAndroid Build Coastguard Worker     }
303*d57664e9SAndroid Build Coastguard Worker 
304*d57664e9SAndroid Build Coastguard Worker     err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
305*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
306*d57664e9SAndroid Build Coastguard Worker         ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
307*d57664e9SAndroid Build Coastguard Worker               "failed: %s (%d)",
308*d57664e9SAndroid Build Coastguard Worker               windowInfo.dataspace, strerror(-err), err);
309*d57664e9SAndroid Build Coastguard Worker         return false;
310*d57664e9SAndroid Build Coastguard Worker     }
311*d57664e9SAndroid Build Coastguard Worker 
312*d57664e9SAndroid Build Coastguard Worker     // native_window_set_buffers_transform() expects the transform the app is requesting that
313*d57664e9SAndroid Build Coastguard Worker     // the compositor perform during composition. With native windows, pre-transform works by
314*d57664e9SAndroid Build Coastguard Worker     // rendering with the same transform the compositor is applying (as in Vulkan), but
315*d57664e9SAndroid Build Coastguard Worker     // then requesting the inverse transform, so that when the compositor does
316*d57664e9SAndroid Build Coastguard Worker     // it's job the two transforms cancel each other out and the compositor ends
317*d57664e9SAndroid Build Coastguard Worker     // up applying an identity transform to the app's buffer.
318*d57664e9SAndroid Build Coastguard Worker     err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
319*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
320*d57664e9SAndroid Build Coastguard Worker         ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
321*d57664e9SAndroid Build Coastguard Worker               "failed: %s (%d)",
322*d57664e9SAndroid Build Coastguard Worker               windowInfo.transform, strerror(-err), err);
323*d57664e9SAndroid Build Coastguard Worker         return false;
324*d57664e9SAndroid Build Coastguard Worker     }
325*d57664e9SAndroid Build Coastguard Worker 
326*d57664e9SAndroid Build Coastguard Worker     // If bufferCount == 1 then we're in shared buffer mode and we cannot actually call
327*d57664e9SAndroid Build Coastguard Worker     // set_buffer_count, it'll just fail.
328*d57664e9SAndroid Build Coastguard Worker     if (windowInfo.bufferCount > 1) {
329*d57664e9SAndroid Build Coastguard Worker         err = native_window_set_buffer_count(window, windowInfo.bufferCount);
330*d57664e9SAndroid Build Coastguard Worker         if (err != 0) {
331*d57664e9SAndroid Build Coastguard Worker             ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s "
332*d57664e9SAndroid Build Coastguard Worker                   "(%d)",
333*d57664e9SAndroid Build Coastguard Worker                   windowInfo.bufferCount, strerror(-err), err);
334*d57664e9SAndroid Build Coastguard Worker             return false;
335*d57664e9SAndroid Build Coastguard Worker         }
336*d57664e9SAndroid Build Coastguard Worker     }
337*d57664e9SAndroid Build Coastguard Worker 
338*d57664e9SAndroid Build Coastguard Worker     err = native_window_set_usage(window, windowInfo.windowUsageFlags);
339*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
340*d57664e9SAndroid Build Coastguard Worker         ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
341*d57664e9SAndroid Build Coastguard Worker               strerror(-err), err);
342*d57664e9SAndroid Build Coastguard Worker         return false;
343*d57664e9SAndroid Build Coastguard Worker     }
344*d57664e9SAndroid Build Coastguard Worker 
345*d57664e9SAndroid Build Coastguard Worker     return true;
346*d57664e9SAndroid Build Coastguard Worker }
347*d57664e9SAndroid Build Coastguard Worker 
VulkanSurface(ANativeWindow * window,const WindowInfo & windowInfo,GrDirectContext * grContext)348*d57664e9SAndroid Build Coastguard Worker VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
349*d57664e9SAndroid Build Coastguard Worker                              GrDirectContext* grContext)
350*d57664e9SAndroid Build Coastguard Worker         : mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
351*d57664e9SAndroid Build Coastguard Worker 
~VulkanSurface()352*d57664e9SAndroid Build Coastguard Worker VulkanSurface::~VulkanSurface() {
353*d57664e9SAndroid Build Coastguard Worker     releaseBuffers();
354*d57664e9SAndroid Build Coastguard Worker 
355*d57664e9SAndroid Build Coastguard Worker     // release the native window to be available for use by other clients
356*d57664e9SAndroid Build Coastguard Worker     int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
357*d57664e9SAndroid Build Coastguard Worker     ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
358*d57664e9SAndroid Build Coastguard Worker }
359*d57664e9SAndroid Build Coastguard Worker 
releaseBuffers()360*d57664e9SAndroid Build Coastguard Worker void VulkanSurface::releaseBuffers() {
361*d57664e9SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
362*d57664e9SAndroid Build Coastguard Worker         VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
363*d57664e9SAndroid Build Coastguard Worker 
364*d57664e9SAndroid Build Coastguard Worker         if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
365*d57664e9SAndroid Build Coastguard Worker             int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
366*d57664e9SAndroid Build Coastguard Worker                                                   bufferInfo.dequeue_fence.release());
367*d57664e9SAndroid Build Coastguard Worker             if (err != 0) {
368*d57664e9SAndroid Build Coastguard Worker                 ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
369*d57664e9SAndroid Build Coastguard Worker             }
370*d57664e9SAndroid Build Coastguard Worker             bufferInfo.dequeued = false;
371*d57664e9SAndroid Build Coastguard Worker             bufferInfo.dequeue_fence.reset();
372*d57664e9SAndroid Build Coastguard Worker         }
373*d57664e9SAndroid Build Coastguard Worker 
374*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
375*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence.ok());
376*d57664e9SAndroid Build Coastguard Worker 
377*d57664e9SAndroid Build Coastguard Worker         bufferInfo.skSurface.reset();
378*d57664e9SAndroid Build Coastguard Worker         bufferInfo.buffer.clear();
379*d57664e9SAndroid Build Coastguard Worker         bufferInfo.hasValidContents = false;
380*d57664e9SAndroid Build Coastguard Worker         bufferInfo.lastPresentedCount = 0;
381*d57664e9SAndroid Build Coastguard Worker     }
382*d57664e9SAndroid Build Coastguard Worker }
383*d57664e9SAndroid Build Coastguard Worker 
invalidateBuffers()384*d57664e9SAndroid Build Coastguard Worker void VulkanSurface::invalidateBuffers() {
385*d57664e9SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
386*d57664e9SAndroid Build Coastguard Worker         VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
387*d57664e9SAndroid Build Coastguard Worker         bufferInfo.hasValidContents = false;
388*d57664e9SAndroid Build Coastguard Worker         bufferInfo.lastPresentedCount = 0;
389*d57664e9SAndroid Build Coastguard Worker     }
390*d57664e9SAndroid Build Coastguard Worker }
391*d57664e9SAndroid Build Coastguard Worker 
dequeueNativeBuffer()392*d57664e9SAndroid Build Coastguard Worker VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
393*d57664e9SAndroid Build Coastguard Worker     // Set the mCurrentBufferInfo to invalid in case of error and only reset it to the correct
394*d57664e9SAndroid Build Coastguard Worker     // value at the end of the function if everything dequeued correctly.
395*d57664e9SAndroid Build Coastguard Worker     mCurrentBufferInfo = nullptr;
396*d57664e9SAndroid Build Coastguard Worker 
397*d57664e9SAndroid Build Coastguard Worker     // Query the transform hint synced from the initial Surface connect or last queueBuffer. The
398*d57664e9SAndroid Build Coastguard Worker     // auto prerotation on the buffer is based on the same transform hint in use by the producer.
399*d57664e9SAndroid Build Coastguard Worker     int transformHint = 0;
400*d57664e9SAndroid Build Coastguard Worker     int err =
401*d57664e9SAndroid Build Coastguard Worker             mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
402*d57664e9SAndroid Build Coastguard Worker 
403*d57664e9SAndroid Build Coastguard Worker     // Since auto pre-rotation is enabled, dequeueBuffer to get the consumer driven buffer size
404*d57664e9SAndroid Build Coastguard Worker     // from ANativeWindowBuffer.
405*d57664e9SAndroid Build Coastguard Worker     ANativeWindowBuffer* buffer;
406*d57664e9SAndroid Build Coastguard Worker     base::unique_fd fence_fd;
407*d57664e9SAndroid Build Coastguard Worker     {
408*d57664e9SAndroid Build Coastguard Worker         int rawFd = -1;
409*d57664e9SAndroid Build Coastguard Worker         err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &rawFd);
410*d57664e9SAndroid Build Coastguard Worker         fence_fd.reset(rawFd);
411*d57664e9SAndroid Build Coastguard Worker     }
412*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
413*d57664e9SAndroid Build Coastguard Worker         ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
414*d57664e9SAndroid Build Coastguard Worker         return nullptr;
415*d57664e9SAndroid Build Coastguard Worker     }
416*d57664e9SAndroid Build Coastguard Worker 
417*d57664e9SAndroid Build Coastguard Worker     SkISize actualSize = SkISize::Make(buffer->width, buffer->height);
418*d57664e9SAndroid Build Coastguard Worker     if (actualSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
419*d57664e9SAndroid Build Coastguard Worker         if (actualSize != mWindowInfo.actualSize) {
420*d57664e9SAndroid Build Coastguard Worker             // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
421*d57664e9SAndroid Build Coastguard Worker             // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
422*d57664e9SAndroid Build Coastguard Worker             mWindowInfo.actualSize = actualSize;
423*d57664e9SAndroid Build Coastguard Worker             releaseBuffers();
424*d57664e9SAndroid Build Coastguard Worker         } else {
425*d57664e9SAndroid Build Coastguard Worker             // A change in transform means we need to repaint the entire buffer area as the damage
426*d57664e9SAndroid Build Coastguard Worker             // rects have just moved about.
427*d57664e9SAndroid Build Coastguard Worker             invalidateBuffers();
428*d57664e9SAndroid Build Coastguard Worker         }
429*d57664e9SAndroid Build Coastguard Worker 
430*d57664e9SAndroid Build Coastguard Worker         if (transformHint != mWindowInfo.transform) {
431*d57664e9SAndroid Build Coastguard Worker             err = native_window_set_buffers_transform(mNativeWindow.get(),
432*d57664e9SAndroid Build Coastguard Worker                                                       InvertTransform(transformHint));
433*d57664e9SAndroid Build Coastguard Worker             if (err != 0) {
434*d57664e9SAndroid Build Coastguard Worker                 ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", transformHint,
435*d57664e9SAndroid Build Coastguard Worker                       strerror(-err), err);
436*d57664e9SAndroid Build Coastguard Worker                 mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
437*d57664e9SAndroid Build Coastguard Worker                 return nullptr;
438*d57664e9SAndroid Build Coastguard Worker             }
439*d57664e9SAndroid Build Coastguard Worker             mWindowInfo.transform = transformHint;
440*d57664e9SAndroid Build Coastguard Worker         }
441*d57664e9SAndroid Build Coastguard Worker 
442*d57664e9SAndroid Build Coastguard Worker         mWindowInfo.size = actualSize;
443*d57664e9SAndroid Build Coastguard Worker         if (mWindowInfo.transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
444*d57664e9SAndroid Build Coastguard Worker             mWindowInfo.size.set(actualSize.height(), actualSize.width());
445*d57664e9SAndroid Build Coastguard Worker         }
446*d57664e9SAndroid Build Coastguard Worker 
447*d57664e9SAndroid Build Coastguard Worker         mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
448*d57664e9SAndroid Build Coastguard Worker         mWindowInfo.pixelSnapMatrix = GetPixelSnapMatrix(mWindowInfo.size, mWindowInfo.transform);
449*d57664e9SAndroid Build Coastguard Worker     }
450*d57664e9SAndroid Build Coastguard Worker 
451*d57664e9SAndroid Build Coastguard Worker     uint32_t idx;
452*d57664e9SAndroid Build Coastguard Worker     for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
453*d57664e9SAndroid Build Coastguard Worker         if (mNativeBuffers[idx].buffer.get() == buffer) {
454*d57664e9SAndroid Build Coastguard Worker             mNativeBuffers[idx].dequeued = true;
455*d57664e9SAndroid Build Coastguard Worker             mNativeBuffers[idx].dequeue_fence = std::move(fence_fd);
456*d57664e9SAndroid Build Coastguard Worker             break;
457*d57664e9SAndroid Build Coastguard Worker         } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
458*d57664e9SAndroid Build Coastguard Worker             // increasing the number of buffers we have allocated
459*d57664e9SAndroid Build Coastguard Worker             mNativeBuffers[idx].buffer = buffer;
460*d57664e9SAndroid Build Coastguard Worker             mNativeBuffers[idx].dequeued = true;
461*d57664e9SAndroid Build Coastguard Worker             mNativeBuffers[idx].dequeue_fence = std::move(fence_fd);
462*d57664e9SAndroid Build Coastguard Worker             break;
463*d57664e9SAndroid Build Coastguard Worker         }
464*d57664e9SAndroid Build Coastguard Worker     }
465*d57664e9SAndroid Build Coastguard Worker     if (idx == mWindowInfo.bufferCount) {
466*d57664e9SAndroid Build Coastguard Worker         ALOGE("dequeueBuffer returned unrecognized buffer");
467*d57664e9SAndroid Build Coastguard Worker         mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
468*d57664e9SAndroid Build Coastguard Worker         return nullptr;
469*d57664e9SAndroid Build Coastguard Worker     }
470*d57664e9SAndroid Build Coastguard Worker 
471*d57664e9SAndroid Build Coastguard Worker     VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
472*d57664e9SAndroid Build Coastguard Worker 
473*d57664e9SAndroid Build Coastguard Worker     if (bufferInfo->skSurface.get() == nullptr) {
474*d57664e9SAndroid Build Coastguard Worker         SkSurfaceProps surfaceProps;
475*d57664e9SAndroid Build Coastguard Worker         if (mWindowInfo.colorMode != ColorMode::Default) {
476*d57664e9SAndroid Build Coastguard Worker             surfaceProps = SkSurfaceProps(SkSurfaceProps::kAlwaysDither_Flag | surfaceProps.flags(),
477*d57664e9SAndroid Build Coastguard Worker                                           surfaceProps.pixelGeometry());
478*d57664e9SAndroid Build Coastguard Worker         }
479*d57664e9SAndroid Build Coastguard Worker         bufferInfo->skSurface = SkSurfaces::WrapAndroidHardwareBuffer(
480*d57664e9SAndroid Build Coastguard Worker                 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
481*d57664e9SAndroid Build Coastguard Worker                 kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, &surfaceProps,
482*d57664e9SAndroid Build Coastguard Worker                 /*from_window=*/true);
483*d57664e9SAndroid Build Coastguard Worker         if (bufferInfo->skSurface.get() == nullptr) {
484*d57664e9SAndroid Build Coastguard Worker             ALOGE("SkSurfaces::WrapAndroidHardwareBuffer failed");
485*d57664e9SAndroid Build Coastguard Worker             mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer,
486*d57664e9SAndroid Build Coastguard Worker                                         mNativeBuffers[idx].dequeue_fence.release());
487*d57664e9SAndroid Build Coastguard Worker             mNativeBuffers[idx].dequeued = false;
488*d57664e9SAndroid Build Coastguard Worker             return nullptr;
489*d57664e9SAndroid Build Coastguard Worker         }
490*d57664e9SAndroid Build Coastguard Worker     }
491*d57664e9SAndroid Build Coastguard Worker 
492*d57664e9SAndroid Build Coastguard Worker     mCurrentBufferInfo = bufferInfo;
493*d57664e9SAndroid Build Coastguard Worker     return bufferInfo;
494*d57664e9SAndroid Build Coastguard Worker }
495*d57664e9SAndroid Build Coastguard Worker 
presentCurrentBuffer(const SkRect & dirtyRect,int semaphoreFd)496*d57664e9SAndroid Build Coastguard Worker bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
497*d57664e9SAndroid Build Coastguard Worker     if (!dirtyRect.isEmpty()) {
498*d57664e9SAndroid Build Coastguard Worker 
499*d57664e9SAndroid Build Coastguard Worker         // native_window_set_surface_damage takes a rectangle in prerotated space
500*d57664e9SAndroid Build Coastguard Worker         // with a bottom-left origin. That is, top > bottom.
501*d57664e9SAndroid Build Coastguard Worker         // The dirtyRect is also in prerotated space, so we just need to switch it to
502*d57664e9SAndroid Build Coastguard Worker         // a bottom-left origin space.
503*d57664e9SAndroid Build Coastguard Worker 
504*d57664e9SAndroid Build Coastguard Worker         SkIRect irect;
505*d57664e9SAndroid Build Coastguard Worker         dirtyRect.roundOut(&irect);
506*d57664e9SAndroid Build Coastguard Worker         android_native_rect_t aRect;
507*d57664e9SAndroid Build Coastguard Worker         aRect.left = irect.left();
508*d57664e9SAndroid Build Coastguard Worker         aRect.top = logicalHeight() - irect.top();
509*d57664e9SAndroid Build Coastguard Worker         aRect.right = irect.right();
510*d57664e9SAndroid Build Coastguard Worker         aRect.bottom = logicalHeight() - irect.bottom();
511*d57664e9SAndroid Build Coastguard Worker 
512*d57664e9SAndroid Build Coastguard Worker         int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
513*d57664e9SAndroid Build Coastguard Worker         ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
514*d57664e9SAndroid Build Coastguard Worker     }
515*d57664e9SAndroid Build Coastguard Worker 
516*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
517*d57664e9SAndroid Build Coastguard Worker     VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
518*d57664e9SAndroid Build Coastguard Worker     // queueBuffer always closes fence, even on error
519*d57664e9SAndroid Build Coastguard Worker     int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence.release();
520*d57664e9SAndroid Build Coastguard Worker     int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
521*d57664e9SAndroid Build Coastguard Worker 
522*d57664e9SAndroid Build Coastguard Worker     currentBuffer.dequeued = false;
523*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
524*d57664e9SAndroid Build Coastguard Worker         ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
525*d57664e9SAndroid Build Coastguard Worker         // cancelBuffer takes ownership of the fence
526*d57664e9SAndroid Build Coastguard Worker         mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
527*d57664e9SAndroid Build Coastguard Worker                                     currentBuffer.dequeue_fence.release());
528*d57664e9SAndroid Build Coastguard Worker     } else {
529*d57664e9SAndroid Build Coastguard Worker         currentBuffer.hasValidContents = true;
530*d57664e9SAndroid Build Coastguard Worker         currentBuffer.lastPresentedCount = mPresentCount;
531*d57664e9SAndroid Build Coastguard Worker         mPresentCount++;
532*d57664e9SAndroid Build Coastguard Worker     }
533*d57664e9SAndroid Build Coastguard Worker 
534*d57664e9SAndroid Build Coastguard Worker     currentBuffer.dequeue_fence.reset();
535*d57664e9SAndroid Build Coastguard Worker 
536*d57664e9SAndroid Build Coastguard Worker     return err == 0;
537*d57664e9SAndroid Build Coastguard Worker }
538*d57664e9SAndroid Build Coastguard Worker 
getCurrentBuffersAge()539*d57664e9SAndroid Build Coastguard Worker int VulkanSurface::getCurrentBuffersAge() {
540*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(!mCurrentBufferInfo);
541*d57664e9SAndroid Build Coastguard Worker     VulkanSurface::NativeBufferInfo& currentBuffer = *mCurrentBufferInfo;
542*d57664e9SAndroid Build Coastguard Worker     return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
543*d57664e9SAndroid Build Coastguard Worker }
544*d57664e9SAndroid Build Coastguard Worker 
setColorSpace(sk_sp<SkColorSpace> colorSpace)545*d57664e9SAndroid Build Coastguard Worker void VulkanSurface::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
546*d57664e9SAndroid Build Coastguard Worker     mWindowInfo.colorspace = std::move(colorSpace);
547*d57664e9SAndroid Build Coastguard Worker     for (int i = 0; i < kNumBufferSlots; i++) {
548*d57664e9SAndroid Build Coastguard Worker         mNativeBuffers[i].skSurface.reset();
549*d57664e9SAndroid Build Coastguard Worker     }
550*d57664e9SAndroid Build Coastguard Worker 
551*d57664e9SAndroid Build Coastguard Worker     if (mWindowInfo.colorMode == ColorMode::Hdr || mWindowInfo.colorMode == ColorMode::Hdr10) {
552*d57664e9SAndroid Build Coastguard Worker         mWindowInfo.dataspace = P3_XRB;
553*d57664e9SAndroid Build Coastguard Worker     } else {
554*d57664e9SAndroid Build Coastguard Worker         mWindowInfo.dataspace = ColorSpaceToADataSpace(
555*d57664e9SAndroid Build Coastguard Worker                 mWindowInfo.colorspace.get(), BufferFormatToColorType(mWindowInfo.bufferFormat));
556*d57664e9SAndroid Build Coastguard Worker     }
557*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(mWindowInfo.dataspace == HAL_DATASPACE_UNKNOWN &&
558*d57664e9SAndroid Build Coastguard Worker                                 mWindowInfo.bufferFormat != AHARDWAREBUFFER_FORMAT_R8_UNORM,
559*d57664e9SAndroid Build Coastguard Worker                         "Unsupported colorspace");
560*d57664e9SAndroid Build Coastguard Worker 
561*d57664e9SAndroid Build Coastguard Worker     if (mNativeWindow) {
562*d57664e9SAndroid Build Coastguard Worker         int err = ANativeWindow_setBuffersDataSpace(mNativeWindow.get(), mWindowInfo.dataspace);
563*d57664e9SAndroid Build Coastguard Worker         if (err != 0) {
564*d57664e9SAndroid Build Coastguard Worker             ALOGE("VulkanSurface::setColorSpace() native_window_set_buffers_data_space(%d) "
565*d57664e9SAndroid Build Coastguard Worker                   "failed: %s (%d)",
566*d57664e9SAndroid Build Coastguard Worker                   mWindowInfo.dataspace, strerror(-err), err);
567*d57664e9SAndroid Build Coastguard Worker         }
568*d57664e9SAndroid Build Coastguard Worker     }
569*d57664e9SAndroid Build Coastguard Worker }
570*d57664e9SAndroid Build Coastguard Worker 
571*d57664e9SAndroid Build Coastguard Worker } /* namespace renderthread */
572*d57664e9SAndroid Build Coastguard Worker } /* namespace uirenderer */
573*d57664e9SAndroid Build Coastguard Worker } /* namespace android */
574