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