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