xref: /aosp_15_r20/frameworks/base/libs/hwui/AutoBackendTextureRelease.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright 2019 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "AutoBackendTextureRelease.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <SkImage.h>
20*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/MutableTextureState.h>
21*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/GrBackendSurface.h>
22*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/GrDirectContext.h>
23*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/SkImageGanesh.h>
24*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/vk/VulkanMutableTextureState.h>
25*d57664e9SAndroid Build Coastguard Worker 
26*d57664e9SAndroid Build Coastguard Worker #include "renderthread/RenderThread.h"
27*d57664e9SAndroid Build Coastguard Worker #include "utils/Color.h"
28*d57664e9SAndroid Build Coastguard Worker #include "utils/PaintUtils.h"
29*d57664e9SAndroid Build Coastguard Worker 
30*d57664e9SAndroid Build Coastguard Worker using namespace android::uirenderer::renderthread;
31*d57664e9SAndroid Build Coastguard Worker 
32*d57664e9SAndroid Build Coastguard Worker namespace android {
33*d57664e9SAndroid Build Coastguard Worker namespace uirenderer {
34*d57664e9SAndroid Build Coastguard Worker 
AutoBackendTextureRelease(GrDirectContext * context,AHardwareBuffer * buffer)35*d57664e9SAndroid Build Coastguard Worker AutoBackendTextureRelease::AutoBackendTextureRelease(GrDirectContext* context,
36*d57664e9SAndroid Build Coastguard Worker                                                      AHardwareBuffer* buffer) {
37*d57664e9SAndroid Build Coastguard Worker     AHardwareBuffer_Desc desc;
38*d57664e9SAndroid Build Coastguard Worker     AHardwareBuffer_describe(buffer, &desc);
39*d57664e9SAndroid Build Coastguard Worker     bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
40*d57664e9SAndroid Build Coastguard Worker 
41*d57664e9SAndroid Build Coastguard Worker     GrBackendFormat backendFormat;
42*d57664e9SAndroid Build Coastguard Worker     GrBackendApi backend = context->backend();
43*d57664e9SAndroid Build Coastguard Worker     if (backend == GrBackendApi::kOpenGL) {
44*d57664e9SAndroid Build Coastguard Worker         backendFormat =
45*d57664e9SAndroid Build Coastguard Worker                 GrAHardwareBufferUtils::GetGLBackendFormat(context, desc.format, false);
46*d57664e9SAndroid Build Coastguard Worker         mBackendTexture =
47*d57664e9SAndroid Build Coastguard Worker                 GrAHardwareBufferUtils::MakeGLBackendTexture(context,
48*d57664e9SAndroid Build Coastguard Worker                                                              buffer,
49*d57664e9SAndroid Build Coastguard Worker                                                              desc.width,
50*d57664e9SAndroid Build Coastguard Worker                                                              desc.height,
51*d57664e9SAndroid Build Coastguard Worker                                                              &mDeleteProc,
52*d57664e9SAndroid Build Coastguard Worker                                                              &mUpdateProc,
53*d57664e9SAndroid Build Coastguard Worker                                                              &mImageCtx,
54*d57664e9SAndroid Build Coastguard Worker                                                              createProtectedImage,
55*d57664e9SAndroid Build Coastguard Worker                                                              backendFormat,
56*d57664e9SAndroid Build Coastguard Worker                                                              false);
57*d57664e9SAndroid Build Coastguard Worker     } else if (backend == GrBackendApi::kVulkan) {
58*d57664e9SAndroid Build Coastguard Worker         backendFormat =
59*d57664e9SAndroid Build Coastguard Worker                 GrAHardwareBufferUtils::GetVulkanBackendFormat(context,
60*d57664e9SAndroid Build Coastguard Worker                                                                buffer,
61*d57664e9SAndroid Build Coastguard Worker                                                                desc.format,
62*d57664e9SAndroid Build Coastguard Worker                                                                false);
63*d57664e9SAndroid Build Coastguard Worker         mBackendTexture =
64*d57664e9SAndroid Build Coastguard Worker                 GrAHardwareBufferUtils::MakeVulkanBackendTexture(context,
65*d57664e9SAndroid Build Coastguard Worker                                                                  buffer,
66*d57664e9SAndroid Build Coastguard Worker                                                                  desc.width,
67*d57664e9SAndroid Build Coastguard Worker                                                                  desc.height,
68*d57664e9SAndroid Build Coastguard Worker                                                                  &mDeleteProc,
69*d57664e9SAndroid Build Coastguard Worker                                                                  &mUpdateProc,
70*d57664e9SAndroid Build Coastguard Worker                                                                  &mImageCtx,
71*d57664e9SAndroid Build Coastguard Worker                                                                  createProtectedImage,
72*d57664e9SAndroid Build Coastguard Worker                                                                  backendFormat,
73*d57664e9SAndroid Build Coastguard Worker                                                                  false);
74*d57664e9SAndroid Build Coastguard Worker     } else {
75*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL("Unexpected backend %d", backend);
76*d57664e9SAndroid Build Coastguard Worker     }
77*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(!backendFormat.isValid(),
78*d57664e9SAndroid Build Coastguard Worker                         __FILE__ " Invalid GrBackendFormat. GrBackendApi==%" PRIu32
79*d57664e9SAndroid Build Coastguard Worker                                  ", AHardwareBuffer_Format==%" PRIu32 ".",
80*d57664e9SAndroid Build Coastguard Worker                         static_cast<int>(context->backend()), desc.format);
81*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(!mBackendTexture.isValid(),
82*d57664e9SAndroid Build Coastguard Worker                         __FILE__ " Invalid GrBackendTexture. Width==%" PRIu32 ", height==%" PRIu32
83*d57664e9SAndroid Build Coastguard Worker                                  ", protected==%d",
84*d57664e9SAndroid Build Coastguard Worker                         desc.width, desc.height, createProtectedImage);
85*d57664e9SAndroid Build Coastguard Worker }
86*d57664e9SAndroid Build Coastguard Worker 
unref(bool releaseImage)87*d57664e9SAndroid Build Coastguard Worker void AutoBackendTextureRelease::unref(bool releaseImage) {
88*d57664e9SAndroid Build Coastguard Worker     if (!RenderThread::isCurrent()) {
89*d57664e9SAndroid Build Coastguard Worker         // EGLImage needs to be destroyed on RenderThread to prevent memory leak.
90*d57664e9SAndroid Build Coastguard Worker         // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not
91*d57664e9SAndroid Build Coastguard Worker         // thread safe.
92*d57664e9SAndroid Build Coastguard Worker         RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); });
93*d57664e9SAndroid Build Coastguard Worker         return;
94*d57664e9SAndroid Build Coastguard Worker     }
95*d57664e9SAndroid Build Coastguard Worker 
96*d57664e9SAndroid Build Coastguard Worker     if (releaseImage) {
97*d57664e9SAndroid Build Coastguard Worker         mImage.reset();
98*d57664e9SAndroid Build Coastguard Worker     }
99*d57664e9SAndroid Build Coastguard Worker 
100*d57664e9SAndroid Build Coastguard Worker     mUsageCount--;
101*d57664e9SAndroid Build Coastguard Worker     if (mUsageCount <= 0) {
102*d57664e9SAndroid Build Coastguard Worker         if (mBackendTexture.isValid()) {
103*d57664e9SAndroid Build Coastguard Worker             mDeleteProc(mImageCtx);
104*d57664e9SAndroid Build Coastguard Worker             mBackendTexture = {};
105*d57664e9SAndroid Build Coastguard Worker         }
106*d57664e9SAndroid Build Coastguard Worker         delete this;
107*d57664e9SAndroid Build Coastguard Worker     }
108*d57664e9SAndroid Build Coastguard Worker }
109*d57664e9SAndroid Build Coastguard Worker 
110*d57664e9SAndroid Build Coastguard Worker // releaseProc is invoked by SkImage, when texture is no longer in use.
111*d57664e9SAndroid Build Coastguard Worker // "releaseContext" contains an "AutoBackendTextureRelease*".
releaseProc(SkImages::ReleaseContext releaseContext)112*d57664e9SAndroid Build Coastguard Worker static void releaseProc(SkImages::ReleaseContext releaseContext) {
113*d57664e9SAndroid Build Coastguard Worker     AutoBackendTextureRelease* textureRelease =
114*d57664e9SAndroid Build Coastguard Worker             reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
115*d57664e9SAndroid Build Coastguard Worker     textureRelease->unref(false);
116*d57664e9SAndroid Build Coastguard Worker }
117*d57664e9SAndroid Build Coastguard Worker 
makeImage(AHardwareBuffer * buffer,android_dataspace dataspace,GrDirectContext * context)118*d57664e9SAndroid Build Coastguard Worker void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer,
119*d57664e9SAndroid Build Coastguard Worker                                           android_dataspace dataspace,
120*d57664e9SAndroid Build Coastguard Worker                                           GrDirectContext* context) {
121*d57664e9SAndroid Build Coastguard Worker     AHardwareBuffer_Desc desc;
122*d57664e9SAndroid Build Coastguard Worker     AHardwareBuffer_describe(buffer, &desc);
123*d57664e9SAndroid Build Coastguard Worker     SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
124*d57664e9SAndroid Build Coastguard Worker     // The following ref will be counteracted by Skia calling releaseProc, either during
125*d57664e9SAndroid Build Coastguard Worker     // BorrowTextureFrom if there is a failure, or later when SkImage is discarded. It must
126*d57664e9SAndroid Build Coastguard Worker     // be called before BorrowTextureFrom, otherwise Skia may remove HWUI's ref on failure.
127*d57664e9SAndroid Build Coastguard Worker     ref();
128*d57664e9SAndroid Build Coastguard Worker     mImage = SkImages::BorrowTextureFrom(
129*d57664e9SAndroid Build Coastguard Worker             context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType,
130*d57664e9SAndroid Build Coastguard Worker             uirenderer::DataSpaceToColorSpace(dataspace), releaseProc, this);
131*d57664e9SAndroid Build Coastguard Worker }
132*d57664e9SAndroid Build Coastguard Worker 
newBufferContent(GrDirectContext * context)133*d57664e9SAndroid Build Coastguard Worker void AutoBackendTextureRelease::newBufferContent(GrDirectContext* context) {
134*d57664e9SAndroid Build Coastguard Worker     if (mBackendTexture.isValid()) {
135*d57664e9SAndroid Build Coastguard Worker         mUpdateProc(mImageCtx, context);
136*d57664e9SAndroid Build Coastguard Worker     }
137*d57664e9SAndroid Build Coastguard Worker }
138*d57664e9SAndroid Build Coastguard Worker 
releaseQueueOwnership(GrDirectContext * context)139*d57664e9SAndroid Build Coastguard Worker void AutoBackendTextureRelease::releaseQueueOwnership(GrDirectContext* context) {
140*d57664e9SAndroid Build Coastguard Worker     if (!context) {
141*d57664e9SAndroid Build Coastguard Worker         return;
142*d57664e9SAndroid Build Coastguard Worker     }
143*d57664e9SAndroid Build Coastguard Worker 
144*d57664e9SAndroid Build Coastguard Worker     if (!RenderThread::isCurrent()) {
145*d57664e9SAndroid Build Coastguard Worker         // releaseQueueOwnership needs to run on RenderThread to prevent multithread calling
146*d57664e9SAndroid Build Coastguard Worker         // setBackendTextureState will operate skia resource cache which need single owner
147*d57664e9SAndroid Build Coastguard Worker         RenderThread::getInstance().queue().post([this, context]() { releaseQueueOwnership(context); });
148*d57664e9SAndroid Build Coastguard Worker         return;
149*d57664e9SAndroid Build Coastguard Worker     }
150*d57664e9SAndroid Build Coastguard Worker 
151*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan);
152*d57664e9SAndroid Build Coastguard Worker     if (mBackendTexture.isValid()) {
153*d57664e9SAndroid Build Coastguard Worker         // Passing in VK_IMAGE_LAYOUT_UNDEFINED means we keep the old layout.
154*d57664e9SAndroid Build Coastguard Worker         skgpu::MutableTextureState newState = skgpu::MutableTextureStates::MakeVulkan(
155*d57664e9SAndroid Build Coastguard Worker                                                                   VK_IMAGE_LAYOUT_UNDEFINED,
156*d57664e9SAndroid Build Coastguard Worker                                                                   VK_QUEUE_FAMILY_FOREIGN_EXT);
157*d57664e9SAndroid Build Coastguard Worker 
158*d57664e9SAndroid Build Coastguard Worker         // The unref for this ref happens in the releaseProc passed into setBackendTextureState. The
159*d57664e9SAndroid Build Coastguard Worker         // releaseProc callback will be made when the work to set the new state has finished on the
160*d57664e9SAndroid Build Coastguard Worker         // gpu.
161*d57664e9SAndroid Build Coastguard Worker         ref();
162*d57664e9SAndroid Build Coastguard Worker         // Note that we don't have an explicit call to set the backend texture back onto the
163*d57664e9SAndroid Build Coastguard Worker         // graphics queue when we use the VkImage again. Internally, Skia will notice that the image
164*d57664e9SAndroid Build Coastguard Worker         // is not on the graphics queue and will do the transition automatically.
165*d57664e9SAndroid Build Coastguard Worker         context->setBackendTextureState(mBackendTexture, newState, nullptr, releaseProc, this);
166*d57664e9SAndroid Build Coastguard Worker     }
167*d57664e9SAndroid Build Coastguard Worker }
168*d57664e9SAndroid Build Coastguard Worker 
169*d57664e9SAndroid Build Coastguard Worker } /* namespace uirenderer */
170*d57664e9SAndroid Build Coastguard Worker } /* namespace android */
171