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