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     if (!mBackendTexture.isValid() || !desc.width || !desc.height) {
47         LOG_ALWAYS_FATAL("Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d "
48                          "isWriteable:%d format:%d",
49                          this, desc.width, desc.height, createProtectedImage, isOutputBuffer,
50                          desc.format);
51     }
52 }
53 
~AutoBackendTexture()54 AutoBackendTexture::~AutoBackendTexture() {
55     if (mBackendTexture.isValid()) {
56         mDeleteProc(mImageCtx);
57         mBackendTexture = {};
58     }
59 }
60 
unref(bool releaseLocalResources)61 void AutoBackendTexture::unref(bool releaseLocalResources) {
62     if (releaseLocalResources) {
63         mSurface = nullptr;
64         mImage = nullptr;
65     }
66 
67     mUsageCount--;
68     if (mUsageCount <= 0) {
69         mCleanupMgr.add(this);
70     }
71 }
72 
73 // releaseSurfaceProc is invoked by SkSurface, when the texture is no longer in use.
74 // "releaseContext" contains an "AutoBackendTexture*".
releaseSurfaceProc(SkSurface::ReleaseContext releaseContext)75 void AutoBackendTexture::releaseSurfaceProc(SkSurface::ReleaseContext releaseContext) {
76     AutoBackendTexture* textureRelease = reinterpret_cast<AutoBackendTexture*>(releaseContext);
77     textureRelease->unref(false);
78 }
79 
80 // releaseImageProc is invoked by SkImage, when the texture is no longer in use.
81 // "releaseContext" contains an "AutoBackendTexture*".
releaseImageProc(SkImage::ReleaseContext releaseContext)82 void AutoBackendTexture::releaseImageProc(SkImage::ReleaseContext releaseContext) {
83     AutoBackendTexture* textureRelease = reinterpret_cast<AutoBackendTexture*>(releaseContext);
84     textureRelease->unref(false);
85 }
86 
logFatalTexture(const char * msg,const GrBackendTexture & tex,ui::Dataspace dataspace,SkColorType colorType)87 void logFatalTexture(const char* msg, const GrBackendTexture& tex, ui::Dataspace dataspace,
88                      SkColorType colorType) {
89     switch (tex.backend()) {
90         case GrBackendApi::kOpenGL: {
91             GrGLTextureInfo textureInfo;
92             bool retrievedTextureInfo = tex.getGLTextureInfo(&textureInfo);
93             LOG_ALWAYS_FATAL("%s isTextureValid:%d dataspace:%d"
94                              "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
95                              "texType: %i\n\t\tGrGLTextureInfo: success: %i fTarget: %u fFormat: %u"
96                              " colorType %i",
97                              msg, tex.isValid(), dataspace, tex.width(), tex.height(),
98                              tex.hasMipmaps(), tex.isProtected(),
99                              static_cast<int>(tex.textureType()), retrievedTextureInfo,
100                              textureInfo.fTarget, textureInfo.fFormat, colorType);
101             break;
102         }
103         case GrBackendApi::kVulkan: {
104             GrVkImageInfo imageInfo;
105             bool retrievedImageInfo = tex.getVkImageInfo(&imageInfo);
106             LOG_ALWAYS_FATAL("%s isTextureValid:%d dataspace:%d"
107                              "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
108                              "texType: %i\n\t\tVkImageInfo: success: %i fFormat: %i "
109                              "fSampleCount: %u fLevelCount: %u colorType %i",
110                              msg, tex.isValid(), dataspace, tex.width(), tex.height(),
111                              tex.hasMipmaps(), tex.isProtected(),
112                              static_cast<int>(tex.textureType()), retrievedImageInfo,
113                              imageInfo.fFormat, imageInfo.fSampleCount, imageInfo.fLevelCount,
114                              colorType);
115             break;
116         }
117         default:
118             LOG_ALWAYS_FATAL("%s Unexpected backend %u", msg, static_cast<unsigned>(tex.backend()));
119             break;
120     }
121 }
122 
makeImage(ui::Dataspace dataspace,SkAlphaType alphaType,GrDirectContext * context)123 sk_sp<SkImage> AutoBackendTexture::makeImage(ui::Dataspace dataspace, SkAlphaType alphaType,
124                                              GrDirectContext* context) {
125     ATRACE_CALL();
126 
127     if (mBackendTexture.isValid()) {
128         mUpdateProc(mImageCtx, context);
129     }
130 
131     auto colorType = mColorType;
132     if (alphaType == kOpaque_SkAlphaType) {
133         if (colorType == kRGBA_8888_SkColorType) {
134             colorType = kRGB_888x_SkColorType;
135         }
136     }
137 
138     sk_sp<SkImage> image =
139             SkImage::MakeFromTexture(context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType,
140                                      alphaType, toSkColorSpace(dataspace), releaseImageProc, this);
141     if (image.get()) {
142         // The following ref will be counteracted by releaseProc, when SkImage is discarded.
143         ref();
144     }
145 
146     mImage = image;
147     mDataspace = dataspace;
148     if (!mImage) {
149         logFatalTexture("Unable to generate SkImage.", mBackendTexture, dataspace, colorType);
150     }
151     return mImage;
152 }
153 
getOrCreateSurface(ui::Dataspace dataspace,GrDirectContext * context)154 sk_sp<SkSurface> AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace,
155                                                         GrDirectContext* context) {
156     ATRACE_CALL();
157     LOG_ALWAYS_FATAL_IF(!mIsOutputBuffer, "You can't generate a SkSurface for a read-only texture");
158     if (!mSurface.get() || mDataspace != dataspace) {
159         sk_sp<SkSurface> surface =
160                 SkSurface::MakeFromBackendTexture(context, mBackendTexture,
161                                                   kTopLeft_GrSurfaceOrigin, 0, mColorType,
162                                                   toSkColorSpace(dataspace), nullptr,
163                                                   releaseSurfaceProc, this);
164         if (surface.get()) {
165             // The following ref will be counteracted by releaseProc, when SkSurface is discarded.
166             ref();
167         }
168         mSurface = surface;
169     }
170 
171     mDataspace = dataspace;
172     if (!mSurface) {
173         logFatalTexture("Unable to generate SkSurface.", mBackendTexture, dataspace, mColorType);
174     }
175     return mSurface;
176 }
177 
178 } // namespace skia
179 } // namespace renderengine
180 } // namespace android
181