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