1 /*
2  * Copyright 2020 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 "AutoBackendTexture.h"
18 
19 #undef LOG_TAG
20 #define LOG_TAG "RenderEngine"
21 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
22 
23 #include "ColorSpaces.h"
24 #include "log/log_main.h"
25 #include "utils/Trace.h"
26 
27 namespace android {
28 namespace renderengine {
29 namespace skia {
30 
AutoBackendTexture(GrDirectContext * context,AHardwareBuffer * buffer,bool isOutputBuffer,CleanupManager & cleanupMgr)31 AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer,
32                                        bool isOutputBuffer, CleanupManager& cleanupMgr)
33       : mCleanupMgr(cleanupMgr), mIsOutputBuffer(isOutputBuffer) {
34     ATRACE_CALL();
35     AHardwareBuffer_Desc desc;
36     AHardwareBuffer_describe(buffer, &desc);
37     bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
38     GrBackendFormat backendFormat =
39             GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false);
40     mBackendTexture =
41             GrAHardwareBufferUtils::MakeBackendTexture(context, buffer, desc.width, desc.height,
42                                                        &mDeleteProc, &mUpdateProc, &mImageCtx,
43                                                        createProtectedImage, backendFormat,
44                                                        isOutputBuffer);
45     mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
46     ALOGE_IF(!mBackendTexture.isValid(),
47              "Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d isWriteable:%d "
48              "format:%d",
49              this, desc.width, desc.height, createProtectedImage, isOutputBuffer, desc.format);
50 }
51 
~AutoBackendTexture()52 AutoBackendTexture::~AutoBackendTexture() {
53     if (mBackendTexture.isValid()) {
54         mDeleteProc(mImageCtx);
55         mBackendTexture = {};
56     }
57 }
58 
unref(bool releaseLocalResources)59 void AutoBackendTexture::unref(bool releaseLocalResources) {
60     if (releaseLocalResources) {
61         mSurface = nullptr;
62         mImage = nullptr;
63     }
64 
65     mUsageCount--;
66     if (mUsageCount <= 0) {
67         mCleanupMgr.add(this);
68     }
69 }
70 
71 // releaseSurfaceProc is invoked by SkSurface, when the texture is no longer in use.
72 // "releaseContext" contains an "AutoBackendTexture*".
releaseSurfaceProc(SkSurface::ReleaseContext releaseContext)73 void AutoBackendTexture::releaseSurfaceProc(SkSurface::ReleaseContext releaseContext) {
74     AutoBackendTexture* textureRelease = reinterpret_cast<AutoBackendTexture*>(releaseContext);
75     textureRelease->unref(false);
76 }
77 
78 // releaseImageProc is invoked by SkImage, when the texture is no longer in use.
79 // "releaseContext" contains an "AutoBackendTexture*".
releaseImageProc(SkImage::ReleaseContext releaseContext)80 void AutoBackendTexture::releaseImageProc(SkImage::ReleaseContext releaseContext) {
81     AutoBackendTexture* textureRelease = reinterpret_cast<AutoBackendTexture*>(releaseContext);
82     textureRelease->unref(false);
83 }
84 
makeImage(ui::Dataspace dataspace,SkAlphaType alphaType,GrDirectContext * context)85 sk_sp<SkImage> AutoBackendTexture::makeImage(ui::Dataspace dataspace, SkAlphaType alphaType,
86                                              GrDirectContext* context) {
87     ATRACE_CALL();
88 
89     if (mBackendTexture.isValid()) {
90         mUpdateProc(mImageCtx, context);
91     }
92 
93     auto colorType = mColorType;
94     if (alphaType == kOpaque_SkAlphaType) {
95         if (colorType == kRGBA_8888_SkColorType) {
96             colorType = kRGB_888x_SkColorType;
97         }
98     }
99 
100     sk_sp<SkImage> image =
101             SkImage::MakeFromTexture(context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType,
102                                      alphaType, toSkColorSpace(dataspace), releaseImageProc, this);
103     if (image.get()) {
104         // The following ref will be counteracted by releaseProc, when SkImage is discarded.
105         ref();
106     }
107 
108     mImage = image;
109     mDataspace = dataspace;
110     LOG_ALWAYS_FATAL_IF(mImage == nullptr,
111                         "Unable to generate SkImage. isTextureValid:%d dataspace:%d",
112                         mBackendTexture.isValid(), dataspace);
113     return mImage;
114 }
115 
getOrCreateSurface(ui::Dataspace dataspace,GrDirectContext * context)116 sk_sp<SkSurface> AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace,
117                                                         GrDirectContext* context) {
118     ATRACE_CALL();
119     LOG_ALWAYS_FATAL_IF(!mIsOutputBuffer, "You can't generate a SkSurface for a read-only texture");
120     if (!mSurface.get() || mDataspace != dataspace) {
121         sk_sp<SkSurface> surface =
122                 SkSurface::MakeFromBackendTexture(context, mBackendTexture,
123                                                   kTopLeft_GrSurfaceOrigin, 0, mColorType,
124                                                   toSkColorSpace(dataspace), nullptr,
125                                                   releaseSurfaceProc, this);
126         if (surface.get()) {
127             // The following ref will be counteracted by releaseProc, when SkSurface is discarded.
128             ref();
129         }
130         mSurface = surface;
131     }
132 
133     mDataspace = dataspace;
134     LOG_ALWAYS_FATAL_IF(mSurface == nullptr,
135                         "Unable to generate SkSurface. isTextureValid:%d dataspace:%d",
136                         mBackendTexture.isValid(), dataspace);
137     return mSurface;
138 }
139 
140 } // namespace skia
141 } // namespace renderengine
142 } // namespace android
143