| /* | |
| * 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 */ |