diff --git a/frameworks/core/components/image/rosen_render_image.cpp b/frameworks/core/components/image/rosen_render_image.cpp index 0e02c882b5529f49971d0526e60ef0a3d90eabc3..81e525ce50193216062f0e5062d93a2ff2b63316 100644 --- a/frameworks/core/components/image/rosen_render_image.cpp +++ b/frameworks/core/components/image/rosen_render_image.cpp @@ -775,7 +775,8 @@ void RosenRenderImage::CanvasDrawImageRect( auto recordingCanvas = static_cast(canvas); if (GetAdaptiveFrameRectFlag()) { recordingCanvas->translate(imageRenderPosition_.GetX() * -1, imageRenderPosition_.GetY() * -1); - Rosen::RsImageInfo rsImageInfo(fitNum, repeatNum, radii_, scale_); + Rosen::RsImageInfo rsImageInfo(fitNum, repeatNum, radii_, scale_, + 0, image_->compressWidth(), image_->compressHeight()); recordingCanvas->DrawImageWithParm(image_->image(), image_->compressData(), rsImageInfo, paint); image_->setCompress(nullptr, 0, 0); return; diff --git a/frameworks/core/components_ng/image_provider/adapter/flutter_image_provider.cpp b/frameworks/core/components_ng/image_provider/adapter/flutter_image_provider.cpp index 1a3c67cca825fc6b500cdd895ed53eb746056d3b..c2766370aa52d334eb2b42cb9629bacad2021b92 100644 --- a/frameworks/core/components_ng/image_provider/adapter/flutter_image_provider.cpp +++ b/frameworks/core/components_ng/image_provider/adapter/flutter_image_provider.cpp @@ -35,6 +35,7 @@ #include "core/components_ng/image_provider/svg_image_object.h" #include "core/components_ng/render/adapter/skia_canvas_image.h" #include "core/image/flutter_image_cache.h" +#include "core/image/image_compressor.h" #include "core/image/image_loader.h" #include "core/pipeline_ng/pipeline_context.h" @@ -48,6 +49,7 @@ namespace { static sk_sp ApplySizeToSkImage( const sk_sp& rawImage, int32_t dstWidth, int32_t dstHeight, const std::string& srcKey) { + ACE_SCOPED_TRACE("ApplySizeToSkImage"); auto scaledImageInfo = SkImageInfo::Make(dstWidth, dstHeight, rawImage->colorType(), rawImage->alphaType(), rawImage->refColorSpace()); SkBitmap scaledBitmap; @@ -208,7 +210,12 @@ void ImageProvider::MakeCanvasImage(const WeakPtr& imageObjWp, cons return; } // upload to gpu for render - auto image = ResizeSkImage(rawImage, obj->GetSourceInfo().GetSrc(), resizeTarget, forceResize); + auto key = ImageObject::GenerateCacheKey(obj->GetSourceInfo(), resizeTarget); + sk_sp image = rawImage; + auto compressFileData = ImageLoader::LoadImageDataFromFileCache(key, ".astc"); + if (!compressFileData) { + image = ResizeSkImage(rawImage, obj->GetSourceInfo().GetSrc(), resizeTarget, forceResize); + } flutter::SkiaGPUObject skiaGpuObjSkImage({ image, flutterRenderTaskHolder->unrefQueue }); #ifdef NG_BUILD auto canvasImage = CanvasImage::Create(); @@ -230,11 +237,13 @@ void ImageProvider::MakeCanvasImage(const WeakPtr& imageObjWp, cons auto obj = objWp.Upgrade(); CHECK_NULL_VOID(obj); obj->SetCanvasImage(canvasImage); + obj->SetData(nullptr); // clear raw image data loadCallbacks.loadSuccessCallback_(obj->GetSourceInfo()); }; ImageProvider::WrapTaskAndPostToUI(std::move(notifyLoadSuccessTask)); }; - ImageProvider::UploadImageToGPUForRender(canvasImage, std::move(uploadTask), renderTaskHolder); + ImageProvider::UploadImageToGPUForRender(canvasImage, std::move(uploadTask), renderTaskHolder, + key, resizeTarget, compressFileData); }; // TODO: add sync load ImageProvider::WrapTaskAndPostToBackground(std::move(canvasImageMakingTask)); @@ -258,7 +267,8 @@ RefPtr ImageProvider::CreateRenderTaskHolder() } void ImageProvider::UploadImageToGPUForRender(const RefPtr& canvasImage, - std::function)>&& callback, const RefPtr& renderTaskHolder) + std::function)>&& callback, const RefPtr& renderTaskHolder, + const std::string key, const SizeF& resizeTarget, const RefPtr& data) { callback(canvasImage); return; @@ -271,48 +281,68 @@ void ImageProvider::UploadImageToGPUForRender(const RefPtr& canvasI #else auto skiaCanvasImage = DynamicCast(canvasImage); CHECK_NULL_VOID(skiaCanvasImage); - auto skImage = skiaCanvasImage->GetCanvasImage(); - CHECK_NULL_VOID(skImage); - auto rasterizedImage = skImage->makeRasterImage(); - if (!rasterizedImage) { - LOGW("Rasterize image failed. callback."); + // load compress cache + if (data) { + int32_t dstWidth = static_cast(resizeTarget.Width() + 0.5); + int32_t dstHeight = static_cast(resizeTarget.Height() + 0.5); + + auto skiaImageData = DynamicCast(data); + CHECK_NULL_VOID(skiaImageData); + auto skdata = skiaImageData->GetSkData(); + auto stripped = ImageCompressor::StripFileHeader(skdata); + LOGI("use astc cache %{public}s %{public}d×%{public}d", key.c_str(), + dstWidth, dstHeight); + skiaCanvasImage->SetCompressData(stripped, dstWidth, dstHeight); + skiaCanvasImage->ReplaceSkImage({ nullptr, flutterRenderTaskHolder->unrefQueue }); + callback(skiaCanvasImage); + return; + } + if (!ImageCompressor::GetInstance()->CanCompress()) { callback(skiaCanvasImage); return; } - // replace skImage of [CanvasImage] with [rasterizedImage] - skiaCanvasImage->ReplaceSkImage({ rasterizedImage, flutterRenderTaskHolder->unrefQueue }); - auto task = [rasterizedImage, callback, flutterRenderTaskHolder, skiaCanvasImage, id = Container::CurrentId()] { + + auto task = [callback, flutterRenderTaskHolder, skiaCanvasImage, + id = Container::CurrentId(), src = key] { ContainerScope scope(id); if (!flutterRenderTaskHolder) { LOGW("flutterRenderTaskHolder has been released."); return; } - // weak reference of io manager must be check and used on io thread, because io manager is created on io thread. - if (!flutterRenderTaskHolder->ioManager) { - // Shell is closing. + auto skImage = skiaCanvasImage->GetCanvasImage(); + CHECK_NULL_VOID(skImage); + auto rasterizedImage = skImage->makeRasterImage(); + if (!rasterizedImage) { + LOGW("Rasterize image failed. callback."); callback(skiaCanvasImage); return; } ACE_DCHECK(!rasterizedImage->isTextureBacked()); - auto resContext = flutterRenderTaskHolder->ioManager->GetResourceContext(); - if (!resContext) { - callback(skiaCanvasImage); - return; - } SkPixmap pixmap; if (!rasterizedImage->peekPixels(&pixmap)) { LOGW("Could not peek pixels of image for texture upload."); callback(skiaCanvasImage); return; } - auto textureImage = -#ifdef NG_BUILD - SkImage::MakeCrossContextFromPixmap(resContext.get(), pixmap, true, true); -#else - SkImage::MakeCrossContextFromPixmap(resContext.get(), pixmap, true, pixmap.colorSpace(), true); -#endif - if (textureImage) { - skiaCanvasImage->ReplaceSkImage({ textureImage, flutterRenderTaskHolder->unrefQueue }); + int32_t width = static_cast(pixmap.width()); + int32_t height = static_cast(pixmap.height()); + if (ImageCompressor::GetInstance()->CanCompress()) { + auto compressData = ImageCompressor::GetInstance()->GpuCompress(src, pixmap, width, height); + ImageCompressor::GetInstance()->WriteToFile(src, compressData, { width, height }); + if (compressData) { + // replace skImage of [CanvasImage] with [rasterizedImage] + skiaCanvasImage->SetCompressData(compressData, width, height); + skiaCanvasImage->ReplaceSkImage({ nullptr, flutterRenderTaskHolder->unrefQueue }); + } else { + skiaCanvasImage->ReplaceSkImage({ rasterizedImage, flutterRenderTaskHolder->unrefQueue }); + } + auto releaseTask = ImageCompressor::GetInstance()->ScheduleReleaseTask(); + if (flutterRenderTaskHolder->ioTaskRunner) { + flutterRenderTaskHolder->ioTaskRunner->PostDelayedTask(releaseTask, + fml::TimeDelta::FromMilliseconds(ImageCompressor::releaseTimeMs)); + } else { + ImageProvider::WrapTaskAndPostToBackground(std::move(releaseTask)); + } } callback(skiaCanvasImage); // Trigger purge cpu bitmap resource, after image upload to gpu. diff --git a/frameworks/core/components_ng/image_provider/image_provider.h b/frameworks/core/components_ng/image_provider/image_provider.h index c59e2203e45d8de2891faa23b2b4c21f2bb9b4db..45efd05148142e36bd1afffe6e768f09a86d8644 100644 --- a/frameworks/core/components_ng/image_provider/image_provider.h +++ b/frameworks/core/components_ng/image_provider/image_provider.h @@ -128,7 +128,9 @@ public: const SizeF& resizeTarget, const RefPtr& renderTaskHolder, bool forceResize = false); static void MakeCanvasImageForSVG(const WeakPtr& imageObjWp, const LoadCallbacks& loadCallbacks); static void UploadImageToGPUForRender(const RefPtr& canvasImage, - std::function)>&& callback, const RefPtr& renderTaskHolder); + std::function)>&& callback, + const RefPtr& renderTaskHolder, const std::string key, + const SizeF& resizeTarget, const RefPtr& data); static RefPtr BuildImageObject(const ImageSourceInfo& sourceInfo, const RefPtr& encodedInfo, const RefPtr& data, const std::optional& svgFillColor, const LoadCallbacks& loadCallbacks, ImageObjectType imageObjectType); diff --git a/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp b/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp index 558b14c19fedc6c96dbc81c41834eae8c74696a8..edc0d9664550ea0d42a70c69c416b07470fc9473 100644 --- a/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp +++ b/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp @@ -284,9 +284,11 @@ void RosenRenderContext::PaintBackground() auto skiaCanvasImage = DynamicCast(bgLoadingCtx_->GetCanvasImage()); CHECK_NULL_VOID(skiaCanvasImage); auto skImage = skiaCanvasImage->GetCanvasImage(); - CHECK_NULL_VOID(skImage); auto rosenImage = std::make_shared(); rosenImage->SetImage(skImage); + auto compressData = skiaCanvasImage->GetCompressData(); + rosenImage->SetCompressData(compressData, skiaCanvasImage->GetUniqueID(), + skiaCanvasImage->GetCompressWidth(), skiaCanvasImage->GetCompressHeight()); rosenImage->SetImageRepeat(static_cast(GetBackgroundImageRepeat().value_or(ImageRepeat::NOREPEAT))); rsNode_->SetBgImage(rosenImage); diff --git a/frameworks/core/components_ng/render/adapter/skia_canvas_image.cpp b/frameworks/core/components_ng/render/adapter/skia_canvas_image.cpp index aa2bf9a0a39bcb1f9c42e970375ada96643eb92c..a70c083bec2f847ffe3ca0b2b21be6681c7b3db9 100644 --- a/frameworks/core/components_ng/render/adapter/skia_canvas_image.cpp +++ b/frameworks/core/components_ng/render/adapter/skia_canvas_image.cpp @@ -21,6 +21,12 @@ #include "core/components_ng/render/canvas_image.h" #include "core/components_ng/render/drawing.h" +#ifdef ENABLE_ROSEN_BACKEND +#include "render_service_client/core/ui/rs_node.h" +#include "render_service_client/core/ui/rs_surface_node.h" +#include "render_service_client/core/ui/rs_ui_director.h" +#endif + namespace OHOS::Ace::NG { RefPtr CanvasImage::Create(void* rawImage) @@ -138,7 +144,7 @@ int32_t SkiaCanvasImage::GetWidth() const #ifdef NG_BUILD return 0; #else - return image_->width(); + return image_->image() ? image_->width() : image_->compressWidth(); #endif } @@ -147,7 +153,7 @@ int32_t SkiaCanvasImage::GetHeight() const #ifdef NG_BUILD return 0; #else - return image_->height(); + return image_->image() ? image_->height() : image_->compressHeight(); #endif } @@ -156,7 +162,39 @@ void SkiaCanvasImage::DrawToRSCanvas(RSCanvas& canvas, const RSRect& srcRect, co auto image = GetCanvasImage(); RSImage rsImage(&image); RSSamplingOptions options; + +#ifdef ENABLE_ROSEN_BACKEND + auto rsCanvas = canvas.GetImpl(); + if (rsCanvas == nullptr) { + canvas.DrawImageRect(rsImage, srcRect, dstRect, options); + return; + } + auto skCanvas = rsCanvas->ExportSkCanvas(); + if (skCanvas == nullptr) { + canvas.DrawImageRect(rsImage, srcRect, dstRect, options); + return; + } + auto recordingCanvas = static_cast(skCanvas); + if (recordingCanvas == nullptr) { + canvas.DrawImageRect(rsImage, srcRect, dstRect, options); + return; + } + SkPaint paint; + SkVector radii[4] = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } }; + Rosen::RsImageInfo rsImageInfo( + (int)(imagePaintConfig_->imageFit_), + (int)(imagePaintConfig_->imageRepeat_), + radii, + 1.0, + GetUniqueID(), + GetCompressWidth(), + GetCompressHeight() + ); + auto data = GetCompressData(); + recordingCanvas->DrawImageWithParm(image, std::move(data), rsImageInfo, paint); +#else canvas.DrawImageRect(rsImage, srcRect, dstRect, options); +#endif } } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/render/adapter/skia_canvas_image.h b/frameworks/core/components_ng/render/adapter/skia_canvas_image.h index 6de9b28c032c7971fc55bf3e74d1c89a6ed0746b..cba691ffadc41e914742643cceb4365d46f262b8 100644 --- a/frameworks/core/components_ng/render/adapter/skia_canvas_image.h +++ b/frameworks/core/components_ng/render/adapter/skia_canvas_image.h @@ -57,7 +57,50 @@ public: #endif return nullptr; } - + virtual sk_sp GetCompressData() const + { +#ifndef NG_BUILD + if (image_) { + return image_->compressData(); + } +#endif + return nullptr; + } + void SetCompressData(sk_sp data, int32_t w, int32_t h) + { +#ifndef NG_BUILD + if (image_) { + image_->setCompress(data, w, h); + auto skimage = image_->image(); + uniqueId_ = skimage ? skimage->uniqueID() : 0; + } +#endif + } + virtual int32_t GetCompressWidth() const + { +#ifndef NG_BUILD + if (image_) { + return image_->compressWidth(); + } +#endif + return 0; + } + virtual int32_t GetCompressHeight() const + { +#ifndef NG_BUILD + if (image_) { + return image_->compressHeight(); + } +#endif + return 0; + } + virtual uint32_t GetUniqueID() const + { +#ifndef NG_BUILD + return uniqueId_; +#endif + return 0; + } void ReplaceSkImage(flutter::SkiaGPUObject newSkGpuObjSkImage); int32_t GetWidth() const override; int32_t GetHeight() const override; @@ -72,6 +115,7 @@ public: private: // TODO: should not deps on flutter. #ifndef NG_BUILD + uint32_t uniqueId_; fml::RefPtr image_; #endif }; diff --git a/frameworks/core/image/image_compressor.cpp b/frameworks/core/image/image_compressor.cpp index f134b65474b3265cea6baf62f201a74d8ede0a15..bf4baf41a84316393b87d7de76b52d78343f8978 100644 --- a/frameworks/core/image/image_compressor.cpp +++ b/frameworks/core/image/image_compressor.cpp @@ -148,6 +148,7 @@ void ImageCompressor::ReleaseResource() sk_sp ImageCompressor::GpuCompress(std::string key, SkPixmap& pixmap, int32_t width, int32_t height) { #ifdef ENABLE_OPENCL + std::lock_guard lock(instanceMutex_); if (width <= 0 || height <= 0 || !clOk_ || IsFailedImage(key) || width > maxSize_ || height > maxSize_) { return nullptr; } diff --git a/frameworks/core/image/image_loader.cpp b/frameworks/core/image/image_loader.cpp index c518137757e619a4e1733d349f30c94592a6173f..bc63d33d5f33feb80f8e5f68c60d68a4e4ebadf3 100644 --- a/frameworks/core/image/image_loader.cpp +++ b/frameworks/core/image/image_loader.cpp @@ -169,6 +169,22 @@ void ImageLoader::CacheImageDataToImageCache(const std::string& key, const RefPt imageCache->CacheImageData(key, imageData); } +RefPtr ImageLoader::LoadImageDataFromFileCache(const std::string key, const std::string suffix) +{ + ACE_FUNCTION_TRACE(); + auto pipelineCtx = PipelineContext::GetCurrentContext(); + CHECK_NULL_RETURN(pipelineCtx, nullptr); + auto imageCache = pipelineCtx->GetImageCache(); + CHECK_NULL_RETURN(imageCache, nullptr); + std::string filePath = ImageCache::GetImageCacheFilePath(key) + suffix; + auto data = imageCache->GetDataFromCacheFile(filePath); + CHECK_NULL_RETURN(data, nullptr); + // add adapter layer to replace [SkiaCachedImageData] + auto skdata = AceType::DynamicCast(data)->imageData; + CHECK_NULL_RETURN(skdata, nullptr); + return NG::ImageData::MakeFromDataWrapper(reinterpret_cast(&skdata)); +} + RefPtr ImageLoader::GetImageData( const ImageSourceInfo& imageSourceInfo, const WeakPtr& context) { diff --git a/frameworks/core/image/image_loader.h b/frameworks/core/image/image_loader.h index 721e6687816414072fb9e3012cd8a96d51bd21dd..bf0d4b24e76075ccbe5954fb16d503707738862e 100644 --- a/frameworks/core/image/image_loader.h +++ b/frameworks/core/image/image_loader.h @@ -52,6 +52,7 @@ public: // implementation in adapter layer static sk_sp QueryImageDataFromImageCache(const ImageSourceInfo& sourceInfo); static void CacheImageDataToImageCache(const std::string& key, const RefPtr& imageData); + static RefPtr LoadImageDataFromFileCache(const std::string key, const std::string suffix); }; // File image provider: read image from file. diff --git a/frameworks/core/image/image_source_info.cpp b/frameworks/core/image/image_source_info.cpp index 573e723fed107adba4f9eb4d0a504b4b1d5ba659..abf6f582edfb05d1dbebc00ea92c7b2e9d7739e0 100644 --- a/frameworks/core/image/image_source_info.cpp +++ b/frameworks/core/image/image_source_info.cpp @@ -128,8 +128,7 @@ ImageSourceInfo::ImageSourceInfo(const std::string& imageSrc, Dimension width, D if (count > 1) { LOGW("multi image source set, only one will be load."); } - auto name = src_ + AceApplicationInfo::GetInstance().GetAbilityName(); - cacheKey_ = std::to_string(std::hash {}(name)) + std::to_string(static_cast(resourceId_)); + GenerateCacheKey(); } SrcType ImageSourceInfo::ResolveSrcType() const @@ -146,6 +145,12 @@ SrcType ImageSourceInfo::ResolveSrcType() const return SrcType::UNSUPPORTED; } +void ImageSourceInfo::GenerateCacheKey() +{ + auto name = src_ + AceApplicationInfo::GetInstance().GetAbilityName(); + cacheKey_ = std::to_string(std::hash {}(name)) + std::to_string(static_cast(resourceId_)); +} + void ImageSourceInfo::SetFillColor(const Color& color) { fillColor_.emplace(color.GetValue()); @@ -175,6 +180,7 @@ void ImageSourceInfo::SetSrc(const std::string& src, std::optional fillCo isSvg_ = IsSVGSource(src_, resourceId_); fillColor_ = fillColor; pixmap_ = nullptr; + GenerateCacheKey(); } const std::string& ImageSourceInfo::GetSrc() const @@ -190,6 +196,7 @@ void ImageSourceInfo::SetResourceId(InternalResource::ResourceId id, std::option isSvg_ = IsSVGSource(src_, resourceId_); fillColor_ = fillColor; pixmap_ = nullptr; + GenerateCacheKey(); } InternalResource::ResourceId ImageSourceInfo::GetResourceId() const diff --git a/frameworks/core/image/image_source_info.h b/frameworks/core/image/image_source_info.h index 75c3a3e14c1cd9f5896cbed492b28df38343a26c..cfb7270fb0109081e3ce2e676eb06085b1ef3eed 100644 --- a/frameworks/core/image/image_source_info.h +++ b/frameworks/core/image/image_source_info.h @@ -74,6 +74,7 @@ public: private: SrcType ResolveSrcType() const; + void GenerateCacheKey(); std::string src_; std::string cacheKey_; @@ -93,4 +94,4 @@ private: } // namespace OHOS::Ace -#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_ACE_IMAGE_SOURCE_INFO_H \ No newline at end of file +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_ACE_IMAGE_SOURCE_INFO_H