diff --git a/frameworks/innerkitsimpl/codec/src/image_source.cpp b/frameworks/innerkitsimpl/codec/src/image_source.cpp index 7e0994cb1b4605befd48a61a351883d2c0549ac9..a3fe3784c6af4f6efd662873e1c69d9b2018ebd9 100644 --- a/frameworks/innerkitsimpl/codec/src/image_source.cpp +++ b/frameworks/innerkitsimpl/codec/src/image_source.cpp @@ -265,6 +265,9 @@ unique_ptr ImageSource::CreateImageSource(const int fd, const Sourc errorCode = SUCCESS; #if !defined(_WIN32) && !defined(_APPLE) FinishTrace(HITRACE_TAG_ZIMAGE); +#endif +#ifdef IMAGE_PURGEABLE_PIXELMAP + sourcePtr->SetPurgeableMemResourceFd(fd); #endif return unique_ptr(sourcePtr); } @@ -1596,5 +1599,22 @@ uint32_t ImageSource::GetFrameCount(uint32_t &errorCode) return frameCount; } + +#ifdef IMAGE_PURGEABLE_PIXELMAP +size_t ImageSource::GetSourceSize() +{ + return sourceStreamPtr_ ? sourceStreamPtr_->GetStreamSize() : 0; +} + +int ImageSource::GetPurgeableMemResourceFd() +{ + return purgeableResourceFd_; +} + +void ImageSource::SetPurgeableMemResourceFd(int fd) +{ + purgeableResourceFd_ = fd; +} +#endif } // namespace Media } // namespace OHOS diff --git a/frameworks/innerkitsimpl/common/src/pixel_map.cpp b/frameworks/innerkitsimpl/common/src/pixel_map.cpp index bd216700ccd513ce0225fdd329562170ffcdd3b1..123fd60193785f54fe6cf3e55b672ce27d66d546 100644 --- a/frameworks/innerkitsimpl/common/src/pixel_map.cpp +++ b/frameworks/innerkitsimpl/common/src/pixel_map.cpp @@ -33,7 +33,13 @@ #include "memory.h" #endif -#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(A_PLATFORM) +#ifdef IMAGE_PURGEABLE_PIXELMAP +#include "purgeable_ashmem.h" +#include "purgeable_mem.h" +#include "purgeable_resource_manager.h" +#endif + +#if !defined(_WIN32) && !defined(_APPLE) &&!defined(IOS_PLATFORM) &&!defined(A_PLATFORM) #include #include "ashmem.h" #include "ipc_file_descriptor.h" @@ -60,6 +66,12 @@ constexpr uint8_t ALIGN_NUMBER = 4; PixelMap::~PixelMap() { FreePixelMap(); +#ifdef IMAGE_PURGEABLE_PIXELMAP + if (IsPurgeable()) { + PurgeableMem::PurgeableResourceManager::GetInstance().RemoveResource(this); + SetPurgeable(false); + } +#endif } void PixelMap::FreePixelMap() __attribute__((no_sanitize("cfi"))) @@ -1963,5 +1975,107 @@ uint32_t PixelMap::crop(const Rect &rect) return *grColorSpace_; } #endif + +#ifdef IMAGE_PURGEABLE_PIXELMAP +void PixelMap::SetBuilderToBePurgeable(std::unique_ptr &builder) +{ + HiLog::Debug(LABEL, "SetBuilderToBePurgeable in. allocatorType = %{public}d.", allocatorType_); + StartTrace(HITRACE_TAG_ZIMAGE, "PixelMap::SetBuilderToBePurgeable"); + if (builder == nullptr) { + FinishTrace(HITRACE_TAG_ZIMAGE); + return; + } + + if (allocatorType_ == AllocatorType::SHARE_MEM_ALLOC) { + std::shared_ptr tmpPtr = + std::make_shared(std::move(builder)); + bool isChanged = tmpPtr->ChangeAshmemData(pixelsSize_, *(static_cast(context_)), data_); + if (isChanged) { + purgeableMem_ = tmpPtr; + purgeableMem_->BeginRead(); + SetPurgeable(true); + } else { + HiLog::Error(LABEL, "ChangeAshmemData fail."); + SetPurgeable(false); + } + } else if (allocatorType_ == AllocatorType::HEAP_ALLOC) { + purgeableMem_ = std::make_shared(pixelsSize_, std::move(builder)); + purgeableMem_->BeginRead(); + SetPurgeable(true); + } + + FinishTrace(HITRACE_TAG_ZIMAGE); +} + +uint32_t PixelMap::BeginVisitPurgeableMem() +{ + StartTrace(HITRACE_TAG_ZIMAGE, "PurgeableResource::BeginVisitPurgeableMem"); + HiLog::Debug(LABEL, "PurgeableResource::BeginVisitPurgeableMem"); + if (purgeableMem_) { + purgeableMem_->BeginRead(); + } + + FinishTrace(HITRACE_TAG_ZIMAGE); + return 0; +} + +uint32_t PixelMap::EndVisitPurgeableMem() +{ + StartTrace(HITRACE_TAG_ZIMAGE, "PurgeableResource::EndVisitPurgeableMem"); + HiLog::Debug(LABEL, "PurgeableResource::EndVisitPurgeableMem"); + if (purgeableMem_) { + purgeableMem_->EndRead(); + } + + FinishTrace(HITRACE_TAG_ZIMAGE); + return 0; +} + +void PixelMap::VisitPurgeableMemForImageCallback() +{ + StartTrace(HITRACE_TAG_ZIMAGE, "PurgeableResource::VisitPurgeableMemForImageCallBack"); + if (callback_) { + HiLog::Debug(LABEL, "PurgeableResource::VisitPurgeableMemForImageCallBack"); + if (purgeableMem_->IfNeedRebuild_()) { + HiLog::Debug(LABEL, "PurgeableResource::need rebuild."); + if (purgeableMem_) { + purgeableMem_->BeginRead(); + } + + if (IsPurgeable() && GetIsNeedAddResourceManager()) { + HiLog::Debug(LABEL, "PurgeableResource::add to purgeableResourceManager."); + PurgeableMem::PurgeableResourceManager::GetInstance().AddResource(this); + } + } else { + HiLog::Debug(LABEL, "PurgeableResource::no need rebuild."); + } + + callback_(); + } + + FinishTrace(HITRACE_TAG_ZIMAGE); +} + +void PixelMap::EndVisitAndRemovePurgeableResource() +{ + StartTrace(HITRACE_TAG_ZIMAGE, "PurgeableResource::EndVisitAndRemovePurgeableResource"); + HiLog::Debug(LABEL, "PurgeableResource::EndVisitAndRemovePurgeableResource"); + if (IsPurgeable() && GetIsNeedAddResourceManager()) { + PurgeableMem::PurgeableResourceManager::GetInstance().RemoveResource(this); + } + + if (purgeableMem_) { + purgeableMem_->EndRead(); + } + FinishTrace(HITRACE_TAG_ZIMAGE); +} + +void PixelMap::SetPurgeableResRebuildCallback(std::function callback) +{ + StartTrace(HITRACE_TAG_ZIMAGE, "PurgeableResource::SetPurgeableResRebuildCallback"); + callback_ = callback; + FinishTrace(HITRACE_TAG_ZIMAGE); +} +#endif } // namespace Media } // namespace OHOS diff --git a/interfaces/innerkits/BUILD.gn b/interfaces/innerkits/BUILD.gn index 408d1e3fd03b9fa24e11e7670206c0327ca53e39..3cbf19c0e3f04f6dedba5e8b533fd0f2dee0bb4d 100644 --- a/interfaces/innerkits/BUILD.gn +++ b/interfaces/innerkits/BUILD.gn @@ -13,6 +13,7 @@ import("//build/ohos.gni") import("//build/ohos/ace/ace.gni") +import("//commonlibrary/memory_utils/purgeable_mem_config.gni") import("//foundation/multimedia/image_framework/ide/image_decode_config.gni") import("$image_subsystem/plugins/cross/image_native_android.gni") import("$image_subsystem/plugins/cross/image_native_ios.gni") @@ -220,6 +221,11 @@ if (use_clang_android) { ] } + if (purgeable_ashmem_enable) { + defines += [ "IMAGE_PURGEABLE_PIXELMAP" ] + external_deps += [ "memory_utils:libpurgeablemem" ] + } + # relative_install_dir = "module/multimedia" subsystem_name = "multimedia" part_name = "multimedia_image_framework" diff --git a/interfaces/innerkits/include/image_source.h b/interfaces/innerkits/include/image_source.h index 687602b052c6b9883e2b95e1f8725cf927a5edc0..e07c2ac2e6f8d57ec28ef2d4154f873caf6503b5 100644 --- a/interfaces/innerkits/include/image_source.h +++ b/interfaces/innerkits/include/image_source.h @@ -181,6 +181,12 @@ public: NATIVEEXPORT std::unique_ptr> GetDelayTime(uint32_t &errorCode); NATIVEEXPORT uint32_t GetFrameCount(uint32_t &errorCode); +#ifdef IMAGE_PURGEABLE_PIXELMAP + NATIVEEXPORT size_t GetSourceSize(); + NATIVEEXPORT int GetPurgeableMemResourceFd(); + NATIVEEXPORT void SetPurgeableMemResourceFd(int); +#endif + private: DISALLOW_COPY_AND_MOVE(ImageSource); using FormatAgentMap = std::map; @@ -249,6 +255,9 @@ private: bool isIncrementalSource_ = false; bool isIncrementalCompleted_ = false; MemoryUsagePreference preference_ = MemoryUsagePreference::DEFAULT; +#ifdef IMAGE_PURGEABLE_PIXELMAP + int purgeableResourceFd_ = -1; +#endif }; } // namespace Media } // namespace OHOS diff --git a/interfaces/innerkits/include/pixel_map.h b/interfaces/innerkits/include/pixel_map.h index 24652d57e2a35a495e85f37767f77b33c414e222..df9a8f7a6315bac2a5975c7982d9a3492ba445fc 100644 --- a/interfaces/innerkits/include/pixel_map.h +++ b/interfaces/innerkits/include/pixel_map.h @@ -26,6 +26,11 @@ #include "image_type.h" #include "parcel.h" +#ifdef IMAGE_PURGEABLE_PIXELMAP +#include "purgeable_mem_builder.h" +#include "purgeable_resource_interface.h" +#endif + namespace OHOS { namespace Media { using TransColorProc = bool (*)(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount); @@ -49,7 +54,11 @@ constexpr uint8_t ARGB_B_SHIFT = 0; // Define pixel map malloc max size 600MB constexpr int32_t PIXEL_MAP_MAX_RAM_SIZE = 600 * 1024 * 1024; +#ifdef IMAGE_PURGEABLE_PIXELMAP +class PixelMap : public Parcelable, public PurgeableMem::PurgeableResourceInterface { +#else class PixelMap : public Parcelable { +#endif public: PixelMap() { @@ -161,6 +170,16 @@ public: // -------[inner api for ImageSource/ImagePacker codec] it will get a colorspace object pointer----end------- #endif +#ifdef IMAGE_PURGEABLE_PIXELMAP + NATIVEEXPORT void SetBuilderToBePurgeable(std::unique_ptr &builder); + NATIVEEXPORT uint32_t BeginVisitPurgeableMem() override; + NATIVEEXPORT uint32_t EndVisitPurgeableMem() override; + NATIVEEXPORT void VisitPurgeableMemForImageCallback(); + NATIVEEXPORT void EndVisitAndRemovePurgeableResource(); + NATIVEEXPORT void SetPurgeableResRebuildCallback(std::function callback); + std::function callback_; +#endif + private: static constexpr uint8_t TLV_VARINT_BITS = 7; static constexpr uint8_t TLV_VARINT_MASK = 0x7F; @@ -261,6 +280,10 @@ private: #else std::shared_ptr grColorSpace_ = nullptr; #endif + +#ifdef IMAGE_PURGEABLE_PIXELMAP + std::shared_ptr purgeableMem_; +#endif }; } // namespace Media } // namespace OHOS diff --git a/interfaces/innerkits/include/purgeable_pixel_map_builder.h b/interfaces/innerkits/include/purgeable_pixel_map_builder.h new file mode 100644 index 0000000000000000000000000000000000000000..36a96cef6c2eb0e3f6bcf3cf3d06d518e836681a --- /dev/null +++ b/interfaces/innerkits/include/purgeable_pixel_map_builder.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef INTERFACES_INNERKITS_INCLUDE_PURGEABLE_PIXEL_MAP_BUILDER_H_ +#define INTERFACES_INNERKITS_INCLUDE_PURGEABLE_PIXEL_MAP_BUILDER_H_ + +#include "hitrace_meter.h" +#include "image_source.h" +#include "image_type.h" +#include "pixel_map.h" + +#ifdef IMAGE_PURGEABLE_PIXELMAP +#include "purgeable_ashmem.h" +#include "purgeable_mem_builder.h" +#include "purgeable_resource_manager.h" + +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +#endif // IMAGE_PURGEABLE_PIXELMAP + +namespace OHOS { +namespace Media { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001799, "PurgeablePixelMapBuilder" }; + +class PurgeablePixelMapBuilder : public PurgeableMem::PurgeableMemBuilder { +public: + PurgeablePixelMapBuilder(uint32_t index, std::unique_ptr &imageSource, + DecodeOptions opts, PixelMap *pixelMap) + : index_(index), opts_(opts), pixelMap_(pixelMap), imageSource_(move(imageSource)) {} + + bool Build(void *data, size_t size) + { + HiviewDFX::HiLog::Debug(LABEL, "purgeableMem build in."); + uint32_t errorCode; + if (imageSource_ == nullptr) { + return false; + } + + StartTraceArgs(HITRACE_TAG_ZIMAGE, "PixelMapPurgeableMemBuilder::Build:%d", + imageSource_->GetPurgeableMemResourceFd()); + std::unique_ptr pixelMap = imageSource_->CreatePixelMap(index_, opts_, errorCode); + if (pixelMap == nullptr || pixelMap_ == nullptr) { + return false; + } + + StartTrace(HITRACE_TAG_ZIMAGE, ("PixelMapPurgeableMemBuilder::memcpy_s:" + std::to_string(size))); + memcpy_s((char *)pixelMap_->GetPixels(), size, (char *)pixelMap->GetPixels(), size); + FinishTrace(HITRACE_TAG_ZIMAGE); // memcpy_s trace + FinishTrace(HITRACE_TAG_ZIMAGE); // PixelMapPurgeableMemBuilder::Build trace + + return true; + } + + size_t GetMetaDataSize() + { + return imageSource_ ? imageSource_->GetSourceSize() : 0; + } + + ~PurgeablePixelMapBuilder() {} + +private: + uint32_t index_; + DecodeOptions opts_; + PixelMap *pixelMap_; + std::unique_ptr imageSource_; +}; // class PurgeablePixelMapBuilder + +bool MakePixelMapToBePurgeable(std::unique_ptr &pixelMap, std::unique_ptr &backupImgSrc4Rebuild, + DecodeOptions &decodeOpts) +{ + HiviewDFX::HiLog::Debug(LABEL, "MakePixelMapToBePurgeable in."); + if (pixelMap == nullptr || backupImgSrc4Rebuild == nullptr) { + HiviewDFX::HiLog::Error(LABEL, "PixelMap or backupImgSrc4Rebuild is null."); + return false; + } + + // check pixelMap purgeable status + if (pixelMap->IsPurgeable()) { + HiviewDFX::HiLog::Error(LABEL, "PixelMap is already purgeable."); + return false; + } + + // 2048 * 1536 and 256 * 256 need manage by resource manager + Size size = decodeOpts.desiredSize; + if (size.height == 2048 && size.width == 1536) { + pixelMap->SetIsNeedAddResourceManager(true); + } + + if (size.height == 256 && size.width == 256) { + pixelMap->SetIsNeedAddResourceManager(true); + } + + // save ImageSource to builder + if (pixelMap->GetIsNeedAddResourceManager()) { + std::unique_ptr purgeableMemBuilder = + std::make_unique(0, backupImgSrc4Rebuild, decodeOpts, pixelMap.get()); + pixelMap->SetBuilderToBePurgeable(purgeableMemBuilder); + + if (pixelMap->IsPurgeable()) { + HiviewDFX::HiLog::Debug(LABEL, "Set pixelMap purgeable success, add to purgeableResourceManager."); + PurgeableMem::PurgeableResourceManager::GetInstance().AddResource(pixelMap.get()); + } + } + + return true; +} +} // namespace Media +} // namespace OHOS + +#endif // INTERFACES_INNERKITS_INCLUDE_PURGEABLE_PIXEL_MAP_BUILDER_H_ \ No newline at end of file