1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "drawable/rs_surface_render_node_drawable.h"
17 #include "rs_draw_window_cache.h"
18 #include "rs_uni_render_thread.h"
19 #include "rs_trace.h"
20
21 namespace OHOS {
22 namespace Rosen {
23
~RSDrawWindowCache()24 RSDrawWindowCache::~RSDrawWindowCache()
25 {
26 ClearCache();
27 }
28
DrawAndCacheWindowContent(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,RSPaintFilterCanvas & canvas,const Drawing::Rect & bounds)29 void RSDrawWindowCache::DrawAndCacheWindowContent(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
30 RSPaintFilterCanvas& canvas, const Drawing::Rect& bounds)
31 {
32 if (surfaceDrawable == nullptr) {
33 RS_LOGE("RSDrawWindowCache::DrawAndCacheWindowContent drawable nullptr.");
34 return;
35 }
36
37 // prepare offscreen canvas
38 auto mainSurface = canvas.GetSurface();
39 if (mainSurface == nullptr) {
40 RS_LOGE("RSDrawWindowCache::DrawAndCacheWindowContent main surface nullptr.");
41 return;
42 }
43 auto windowSurface = mainSurface->MakeSurface(bounds.GetWidth(), bounds.GetHeight());
44 if (windowSurface == nullptr) {
45 RS_LOGE("RSDrawWindowCache::DrawAndCacheWindowContent surface nullptr.");
46 return;
47 }
48 auto windowCanvas = std::make_shared<RSPaintFilterCanvas>(windowSurface.get());
49 if (windowCanvas == nullptr) {
50 RS_LOGE("RSDrawWindowCache::DrawAndCacheWindowContent canvas nullptr.");
51 windowSurface = nullptr;
52 return;
53 }
54 RS_TRACE_NAME_FMT("DrawAndCacheWindow node[%lld] %s", surfaceDrawable->GetId(), surfaceDrawable->GetName().c_str());
55 // copy HDR properties into offscreen canvas
56 windowCanvas->CopyHDRConfiguration(canvas);
57 // copy current canvas properties into offscreen canvas
58 windowCanvas->CopyConfigurationToOffscreenCanvas(canvas);
59 windowCanvas->SetDisableFilterCache(true);
60 auto acr = std::make_unique<RSAutoCanvasRestore>(windowCanvas, RSPaintFilterCanvas::SaveType::kCanvasAndAlpha);
61 windowCanvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
62
63 // draw window content/children onto offscreen canvas
64 auto& uniParams = RSUniRenderThread::Instance().GetRSRenderThreadParams();
65 bool isOpDropped = uniParams != nullptr ? uniParams->IsOpDropped() : true;
66 if (uniParams) {
67 uniParams->SetOpDropped(false); // temporarily close partial render
68 }
69 surfaceDrawable->DrawContent(*windowCanvas, bounds); // draw content
70 surfaceDrawable->DrawChildren(*windowCanvas, bounds); // draw children
71 if (uniParams) {
72 uniParams->SetOpDropped(isOpDropped);
73 }
74
75 // cache and draw snapshot of offscreen canvas onto target canvas
76 image_ = windowSurface->GetImageSnapshot();
77 if (image_ == nullptr) {
78 RS_LOGE("RSDrawWindowCache::DrawAndCacheWindowContent snapshot nullptr.");
79 return;
80 }
81 Drawing::Brush paint;
82 paint.SetAntiAlias(true);
83 canvas.AttachBrush(paint);
84 auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::NEAREST, Drawing::MipmapMode::NONE);
85 canvas.DrawImage(*image_, 0, 0, samplingOptions);
86 canvas.DetachBrush();
87 }
88
DealWithCachedWindow(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,RSPaintFilterCanvas & canvas,RSSurfaceRenderParams & surfaceParams)89 bool RSDrawWindowCache::DealWithCachedWindow(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
90 RSPaintFilterCanvas& canvas, RSSurfaceRenderParams& surfaceParams)
91 {
92 if (surfaceDrawable == nullptr ||
93 surfaceDrawable->HasCachedTexture() ||
94 !HasCache() ||
95 surfaceParams.GetUifirstNodeEnableParam() == MultiThreadCacheType::NONE) {
96 ClearCache();
97 return false;
98 }
99 if (ROSEN_EQ(image_->GetWidth(), 0) || ROSEN_EQ(image_->GetHeight(), 0)) {
100 RS_LOGE("RSDrawWindowCache::DealWithCachedWindow buffer size is zero.");
101 return false;
102 }
103 RS_TRACE_NAME_FMT("DealWithCachedWindow node[%lld] %s",
104 surfaceDrawable->GetId(), surfaceDrawable->GetName().c_str());
105 RSAutoCanvasRestore acr(&canvas);
106 if (!RSUniRenderThread::GetCaptureParam().isSnapshot_) {
107 canvas.MultiplyAlpha(surfaceParams.GetAlpha());
108 canvas.ConcatMatrix(surfaceParams.GetMatrix());
109 }
110 auto boundSize = surfaceParams.GetFrameRect();
111 // draw background
112 surfaceDrawable->DrawBackground(canvas, boundSize);
113 float scaleX = boundSize.GetWidth() / static_cast<float>(image_->GetWidth());
114 float scaleY = boundSize.GetHeight() / static_cast<float>(image_->GetHeight());
115 canvas.Scale(scaleX, scaleY);
116 if (RSSystemProperties::GetRecordingEnabled()) {
117 if (image_->IsTextureBacked()) {
118 RS_LOGI("RSDrawWindowCache::DealWithCachedWindow convert image from texture to raster image.");
119 image_ = image_->MakeRasterImage();
120 }
121 }
122 Drawing::Brush brush;
123 canvas.AttachBrush(brush);
124 auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
125 auto gravityTranslate = surfaceDrawable->GetGravityTranslate(image_->GetWidth(), image_->GetHeight());
126 // draw content/children
127 canvas.DrawImage(*image_, gravityTranslate.x_, gravityTranslate.y_, samplingOptions);
128 canvas.DetachBrush();
129 // draw foreground
130 surfaceDrawable->DrawForeground(canvas, boundSize);
131 return true;
132 }
133
ClearCache()134 void RSDrawWindowCache::ClearCache()
135 {
136 image_ = nullptr;
137 }
138
HasCache() const139 bool RSDrawWindowCache::HasCache() const
140 {
141 return image_ != nullptr;
142 }
143
144 } // Rosen
145 } // OHOS