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