summaryrefslogtreecommitdiff
path: root/libs/hwui/AutoBackendTextureRelease.cpp
blob: ef5eacbdb4adc15739d4dc41e5bc202f06cc5d43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 * Copyright 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "AutoBackendTextureRelease.h"

#include "renderthread/RenderThread.h"
#include "utils/Color.h"
#include "utils/PaintUtils.h"

using namespace android::uirenderer::renderthread;

namespace android {
namespace uirenderer {

AutoBackendTextureRelease::AutoBackendTextureRelease(GrDirectContext* context,
                                                     AHardwareBuffer* buffer) {
    AHardwareBuffer_Desc desc;
    AHardwareBuffer_describe(buffer, &desc);
    bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
    GrBackendFormat backendFormat =
            GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false);
    mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
            context, buffer, desc.width, desc.height, &mDeleteProc, &mUpdateProc, &mImageCtx,
            createProtectedImage, backendFormat, false);
}

void AutoBackendTextureRelease::unref(bool releaseImage) {
    if (!RenderThread::isCurrent()) {
        // EGLImage needs to be destroyed on RenderThread to prevent memory leak.
        // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not
        // thread safe.
        RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); });
        return;
    }

    if (releaseImage) {
        mImage.reset();
    }

    mUsageCount--;
    if (mUsageCount <= 0) {
        if (mBackendTexture.isValid()) {
            mDeleteProc(mImageCtx);
            mBackendTexture = {};
        }
        delete this;
    }
}

// releaseProc is invoked by SkImage, when texture is no longer in use.
// "releaseContext" contains an "AutoBackendTextureRelease*".
static void releaseProc(SkImage::ReleaseContext releaseContext) {
    AutoBackendTextureRelease* textureRelease =
            reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
    textureRelease->unref(false);
}

void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer,
                                          android_dataspace dataspace,
                                          GrDirectContext* context) {
    AHardwareBuffer_Desc desc;
    AHardwareBuffer_describe(buffer, &desc);
    SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
    mImage = SkImage::MakeFromTexture(
            context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType,
            uirenderer::DataSpaceToColorSpace(dataspace), releaseProc, this);
    if (mImage.get()) {
        // The following ref will be counteracted by releaseProc, when SkImage is discarded.
        ref();
    }
}

void AutoBackendTextureRelease::newBufferContent(GrDirectContext* context) {
    if (mBackendTexture.isValid()) {
        mUpdateProc(mImageCtx, context);
    }
}

void AutoBackendTextureRelease::releaseQueueOwnership(GrDirectContext* context) {
    if (!context) {
        return;
    }

    LOG_ALWAYS_FATAL_IF(Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan);
    if (mBackendTexture.isValid()) {
        // Passing in VK_IMAGE_LAYOUT_UNDEFINED means we keep the old layout.
        GrBackendSurfaceMutableState newState(VK_IMAGE_LAYOUT_UNDEFINED,
                                              VK_QUEUE_FAMILY_FOREIGN_EXT);

        // The unref for this ref happens in the releaseProc passed into setBackendTextureState. The
        // releaseProc callback will be made when the work to set the new state has finished on the
        // gpu.
        ref();
        // Note that we don't have an explicit call to set the backend texture back onto the
        // graphics queue when we use the VkImage again. Internally, Skia will notice that the image
        // is not on the graphics queue and will do the transition automatically.
        context->setBackendTextureState(mBackendTexture, newState, nullptr, releaseProc, this);
    }
}

} /* namespace uirenderer */
} /* namespace android */