1 /*
2  * Copyright 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 "AutoBackendTextureRelease.h"
18 
19 #include "renderthread/RenderThread.h"
20 #include "utils/Color.h"
21 #include "utils/PaintUtils.h"
22 
23 using namespace android::uirenderer::renderthread;
24 
25 namespace android {
26 namespace uirenderer {
27 
AutoBackendTextureRelease(GrDirectContext * context,AHardwareBuffer * buffer)28 AutoBackendTextureRelease::AutoBackendTextureRelease(GrDirectContext* context,
29                                                      AHardwareBuffer* buffer) {
30     AHardwareBuffer_Desc desc;
31     AHardwareBuffer_describe(buffer, &desc);
32     bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
33     GrBackendFormat backendFormat =
34             GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false);
35     LOG_ALWAYS_FATAL_IF(!backendFormat.isValid(),
36                         __FILE__ " Invalid GrBackendFormat. GrBackendApi==%" PRIu32
37                                  ", AHardwareBuffer_Format==%" PRIu32 ".",
38                         static_cast<int>(context->backend()), desc.format);
39     mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
40             context, buffer, desc.width, desc.height, &mDeleteProc, &mUpdateProc, &mImageCtx,
41             createProtectedImage, backendFormat, false);
42     LOG_ALWAYS_FATAL_IF(!mBackendTexture.isValid(),
43                         __FILE__ " Invalid GrBackendTexture. Width==%" PRIu32 ", height==%" PRIu32
44                                  ", protected==%d",
45                         desc.width, desc.height, createProtectedImage);
46 }
47 
unref(bool releaseImage)48 void AutoBackendTextureRelease::unref(bool releaseImage) {
49     if (!RenderThread::isCurrent()) {
50         // EGLImage needs to be destroyed on RenderThread to prevent memory leak.
51         // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not
52         // thread safe.
53         RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); });
54         return;
55     }
56 
57     if (releaseImage) {
58         mImage.reset();
59     }
60 
61     mUsageCount--;
62     if (mUsageCount <= 0) {
63         if (mBackendTexture.isValid()) {
64             mDeleteProc(mImageCtx);
65             mBackendTexture = {};
66         }
67         delete this;
68     }
69 }
70 
71 // releaseProc is invoked by SkImage, when texture is no longer in use.
72 // "releaseContext" contains an "AutoBackendTextureRelease*".
releaseProc(SkImage::ReleaseContext releaseContext)73 static void releaseProc(SkImage::ReleaseContext releaseContext) {
74     AutoBackendTextureRelease* textureRelease =
75             reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
76     textureRelease->unref(false);
77 }
78 
makeImage(AHardwareBuffer * buffer,android_dataspace dataspace,GrDirectContext * context)79 void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer,
80                                           android_dataspace dataspace,
81                                           GrDirectContext* context) {
82     AHardwareBuffer_Desc desc;
83     AHardwareBuffer_describe(buffer, &desc);
84     SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
85     // The following ref will be counteracted by Skia calling releaseProc, either during
86     // MakeFromTexture if there is a failure, or later when SkImage is discarded. It must
87     // be called before MakeFromTexture, otherwise Skia may remove HWUI's ref on failure.
88     ref();
89     mImage = SkImage::MakeFromTexture(
90             context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType,
91             uirenderer::DataSpaceToColorSpace(dataspace), releaseProc, this);
92 }
93 
newBufferContent(GrDirectContext * context)94 void AutoBackendTextureRelease::newBufferContent(GrDirectContext* context) {
95     if (mBackendTexture.isValid()) {
96         mUpdateProc(mImageCtx, context);
97     }
98 }
99 
releaseQueueOwnership(GrDirectContext * context)100 void AutoBackendTextureRelease::releaseQueueOwnership(GrDirectContext* context) {
101     if (!context) {
102         return;
103     }
104 
105     LOG_ALWAYS_FATAL_IF(Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan);
106     if (mBackendTexture.isValid()) {
107         // Passing in VK_IMAGE_LAYOUT_UNDEFINED means we keep the old layout.
108         GrBackendSurfaceMutableState newState(VK_IMAGE_LAYOUT_UNDEFINED,
109                                               VK_QUEUE_FAMILY_FOREIGN_EXT);
110 
111         // The unref for this ref happens in the releaseProc passed into setBackendTextureState. The
112         // releaseProc callback will be made when the work to set the new state has finished on the
113         // gpu.
114         ref();
115         // Note that we don't have an explicit call to set the backend texture back onto the
116         // graphics queue when we use the VkImage again. Internally, Skia will notice that the image
117         // is not on the graphics queue and will do the transition automatically.
118         context->setBackendTextureState(mBackendTexture, newState, nullptr, releaseProc, this);
119     }
120 }
121 
122 } /* namespace uirenderer */
123 } /* namespace android */
124