blob: 5f5ffe97e953267e0f8887adf57c57890d5a497a [file] [log] [blame]
Stan Ilievaaa9e832019-09-17 14:07:23 -04001/*
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
Kevin Lubickdd8b2ea2023-03-17 19:55:58 +000019#include <SkImage.h>
20#include <include/gpu/ganesh/SkImageGanesh.h>
Kevin Lubickb5ad05c2023-06-05 17:34:05 +000021#include <include/gpu/GrDirectContext.h>
22#include <include/gpu/GrBackendSurface.h>
Brian Osmanc2054ae2023-08-16 17:51:07 +000023#include <include/gpu/MutableTextureState.h>
Kevin Lubick41403bd2024-01-22 17:28:40 +000024#include <include/gpu/vk/VulkanMutableTextureState.h>
Stan Ilievaaa9e832019-09-17 14:07:23 -040025#include "renderthread/RenderThread.h"
26#include "utils/Color.h"
27#include "utils/PaintUtils.h"
28
29using namespace android::uirenderer::renderthread;
30
31namespace android {
32namespace uirenderer {
33
Adlai Hollerf8c434e2020-07-27 11:42:45 -040034AutoBackendTextureRelease::AutoBackendTextureRelease(GrDirectContext* context,
35 AHardwareBuffer* buffer) {
Stan Ilievaaa9e832019-09-17 14:07:23 -040036 AHardwareBuffer_Desc desc;
37 AHardwareBuffer_describe(buffer, &desc);
38 bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
Kevin Lubick60d06862023-08-07 15:29:12 +000039
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 }
Nolan Scobie2163e412022-10-24 19:57:43 -040076 LOG_ALWAYS_FATAL_IF(!backendFormat.isValid(),
77 __FILE__ " Invalid GrBackendFormat. GrBackendApi==%" PRIu32
78 ", AHardwareBuffer_Format==%" PRIu32 ".",
79 static_cast<int>(context->backend()), desc.format);
Nolan Scobie2163e412022-10-24 19:57:43 -040080 LOG_ALWAYS_FATAL_IF(!mBackendTexture.isValid(),
81 __FILE__ " Invalid GrBackendTexture. Width==%" PRIu32 ", height==%" PRIu32
82 ", protected==%d",
83 desc.width, desc.height, createProtectedImage);
Stan Ilievaaa9e832019-09-17 14:07:23 -040084}
85
86void 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*".
Kevin Lubick36e81af2023-05-11 14:58:45 +0000111static void releaseProc(SkImages::ReleaseContext releaseContext) {
Stan Ilievaaa9e832019-09-17 14:07:23 -0400112 AutoBackendTextureRelease* textureRelease =
113 reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
114 textureRelease->unref(false);
115}
116
Adlai Hollerf8c434e2020-07-27 11:42:45 -0400117void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer,
118 android_dataspace dataspace,
119 GrDirectContext* context) {
Stan Ilievaaa9e832019-09-17 14:07:23 -0400120 AHardwareBuffer_Desc desc;
121 AHardwareBuffer_describe(buffer, &desc);
122 SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
Nolan Scobie2163e412022-10-24 19:57:43 -0400123 // The following ref will be counteracted by Skia calling releaseProc, either during
Kevin Lubickdd8b2ea2023-03-17 19:55:58 +0000124 // 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.
Nolan Scobie2163e412022-10-24 19:57:43 -0400126 ref();
Kevin Lubickdd8b2ea2023-03-17 19:55:58 +0000127 mImage = SkImages::BorrowTextureFrom(
Stan Ilievaaa9e832019-09-17 14:07:23 -0400128 context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType,
129 uirenderer::DataSpaceToColorSpace(dataspace), releaseProc, this);
Stan Ilievaaa9e832019-09-17 14:07:23 -0400130}
131
Adlai Hollerf8c434e2020-07-27 11:42:45 -0400132void AutoBackendTextureRelease::newBufferContent(GrDirectContext* context) {
Stan Ilievaaa9e832019-09-17 14:07:23 -0400133 if (mBackendTexture.isValid()) {
134 mUpdateProc(mImageCtx, context);
135 }
136}
137
Greg Daniel27e1fa22021-05-26 09:24:15 -0400138void 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.
Kevin Lubick41403bd2024-01-22 17:28:40 +0000146 skgpu::MutableTextureState newState = skgpu::MutableTextureStates::MakeVulkan(
147 VK_IMAGE_LAYOUT_UNDEFINED,
148 VK_QUEUE_FAMILY_FOREIGN_EXT);
Greg Daniel27e1fa22021-05-26 09:24:15 -0400149
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
Stan Ilievaaa9e832019-09-17 14:07:23 -0400161} /* namespace uirenderer */
162} /* namespace android */