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 "rs_draw_window_cache.h"
17
18 #include "drawable/rs_surface_render_node_drawable.h"
19 #include "pipeline/main_thread/rs_main_thread.h"
20 #include "pipeline/render_thread/rs_uni_render_thread.h"
21 #include "rs_trace.h"
22
23 #undef LOG_TAG
24 #define LOG_TAG "RSDrawWindowCache"
25
26 namespace OHOS {
27 namespace Rosen {
28
29 namespace {
30 constexpr float SCALE_DIFF = 0.01f;
31 }
32
~RSDrawWindowCache()33 RSDrawWindowCache::~RSDrawWindowCache()
34 {
35 ClearCache();
36 }
37
DrawAndCacheWindowContent(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,RSPaintFilterCanvas & canvas,const Drawing::Rect & bounds)38 void RSDrawWindowCache::DrawAndCacheWindowContent(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
39 RSPaintFilterCanvas& canvas, const Drawing::Rect& bounds)
40 {
41 if (surfaceDrawable == nullptr) {
42 RS_LOGE("DrawAndCacheWindowContent drawable nullptr.");
43 return;
44 }
45
46 // prepare offscreen canvas
47 auto mainSurface = canvas.GetSurface();
48 if (mainSurface == nullptr) {
49 RS_LOGE("DrawAndCacheWindowContent main surface nullptr.");
50 return;
51 }
52 auto windowSurface = mainSurface->MakeSurface(bounds.GetWidth(), bounds.GetHeight());
53 if (windowSurface == nullptr) {
54 RS_LOGE("DrawAndCacheWindowContent surface nullptr.");
55 return;
56 }
57 auto windowCanvas = std::make_shared<RSPaintFilterCanvas>(windowSurface.get());
58 if (windowCanvas == nullptr) {
59 RS_LOGE("DrawAndCacheWindowContent canvas nullptr.");
60 windowSurface = nullptr;
61 return;
62 }
63 RS_TRACE_NAME_FMT("DrawAndCacheWindow node[%lld] %s", surfaceDrawable->GetId(), surfaceDrawable->GetName().c_str());
64 // copy HDR properties into offscreen canvas
65 windowCanvas->CopyHDRConfiguration(canvas);
66 // copy current canvas properties into offscreen canvas
67 windowCanvas->CopyConfigurationToOffscreenCanvas(canvas);
68 windowCanvas->SetDisableFilterCache(true);
69 windowCanvas->SetIsDrawingCache(true);
70 auto acr = std::make_unique<RSAutoCanvasRestore>(windowCanvas, RSPaintFilterCanvas::SaveType::kCanvasAndAlpha);
71 windowCanvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
72 #ifdef RS_ENABLE_GPU
73 // draw window content/children onto offscreen canvas
74 auto& uniParams = RSUniRenderThread::Instance().GetRSRenderThreadParams();
75 bool isOpDropped = uniParams != nullptr ? uniParams->IsOpDropped() : true;
76 if (uniParams) {
77 uniParams->SetOpDropped(false); // temporarily close partial render
78 }
79 DrawableV2::RSRenderNodeDrawable::ClearTotalProcessedNodeCount();
80 surfaceDrawable->DrawContent(*windowCanvas, bounds); // draw content
81 surfaceDrawable->DrawChildren(*windowCanvas, bounds); // draw children
82 RS_TRACE_NAME_FMT("total ProcessedNodes: %d", DrawableV2::RSRenderNodeDrawable::GetTotalProcessedNodeCount());
83 if (uniParams) {
84 uniParams->SetOpDropped(isOpDropped);
85 }
86 #endif
87 // cache and draw snapshot of offscreen canvas onto target canvas
88 image_ = windowSurface->GetImageSnapshot();
89 if (image_ == nullptr) {
90 RS_LOGE("DrawAndCacheWindowContent snapshot nullptr.");
91 return;
92 }
93 surfaceDrawable->GetRsSubThreadCache().SetCacheCompletedBehindWindowData(windowCanvas->GetCacheBehindWindowData());
94 surfaceDrawable->GetRsSubThreadCache().DrawBehindWindowBeforeCache(canvas);
95 Drawing::Brush paint;
96 paint.SetAntiAlias(true);
97 canvas.AttachBrush(paint);
98 auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::NEAREST, Drawing::MipmapMode::NONE);
99 canvas.DrawImage(*image_, 0, 0, samplingOptions);
100 canvas.DetachBrush();
101 }
102 #ifdef RS_ENABLE_GPU
DealWithCachedWindow(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,RSPaintFilterCanvas & canvas,RSSurfaceRenderParams & surfaceParams,RSRenderThreadParams & uniParam)103 bool RSDrawWindowCache::DealWithCachedWindow(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
104 RSPaintFilterCanvas& canvas, RSSurfaceRenderParams& surfaceParams, RSRenderThreadParams& uniParam)
105 {
106 if (surfaceDrawable == nullptr ||
107 surfaceDrawable->GetRsSubThreadCache().HasCachedTexture() ||
108 !HasCache()) {
109 ClearCache();
110 return false;
111 }
112 // Non-CrosNode not cache for uifirst need clear cache,
113 // and if node not execute prepre process in the second frame, cache type will still be MultiThreadCacheType::NONE,
114 // we should avoid clear cache by checking GetNeedCacheSurface
115 if (!surfaceParams.IsCrossNode() && surfaceParams.GetUifirstNodeEnableParam() == MultiThreadCacheType::NONE
116 && !surfaceParams.ClonedSourceNode() && !surfaceParams.GetNeedCacheSurface()) {
117 ClearCache();
118 return false;
119 }
120 // CrosNode no need to clear cache
121 if (surfaceParams.IsCrossNode() && (uniParam.IsMirrorScreen() ||
122 uniParam.IsFirstVisitCrossNodeDisplay() || uniParam.HasDisplayHdrOn())) {
123 return false;
124 }
125 if (ROSEN_EQ(image_->GetWidth(), 0) || ROSEN_EQ(image_->GetHeight(), 0)) {
126 RS_LOGE("DealWithCachedWindow buffer size is zero.");
127 return false;
128 }
129 RS_TRACE_NAME_FMT("DealWithCachedWindow node[%lld] %s",
130 surfaceDrawable->GetId(), surfaceDrawable->GetName().c_str());
131 RSAutoCanvasRestore acr(&canvas);
132 //Alpha and matrix have been applied in func CaptureSurface
133 if (!RSUniRenderThread::GetCaptureParam().isSnapshot_ && !RSUniRenderThread::GetCaptureParam().isMirror_) {
134 canvas.MultiplyAlpha(surfaceParams.GetAlpha());
135 canvas.ConcatMatrix(surfaceParams.GetMatrix());
136 }
137 if (surfaceParams.GetGlobalPositionEnabled()) {
138 auto matrix = surfaceParams.GetMatrix();
139 Drawing::Matrix inverseMatrix;
140 if (!matrix.Invert(inverseMatrix)) {
141 RS_LOGW("%{public}s name: %{public}s matrix invert inverseMatrix Failed", __func__,
142 surfaceParams.GetName().c_str());
143 }
144 canvas.ConcatMatrix(inverseMatrix);
145 canvas.Translate(-surfaceDrawable->offsetX_, -surfaceDrawable->offsetY_);
146 canvas.ConcatMatrix(matrix);
147 }
148 auto boundSize = surfaceParams.GetBounds();
149 // draw background
150 surfaceDrawable->DrawBackground(canvas, boundSize);
151 const auto& gravityMatrix = surfaceDrawable->GetGravityMatrix(image_->GetWidth(), image_->GetHeight());
152 float scaleX = boundSize.GetWidth() / static_cast<float>(image_->GetWidth());
153 float scaleY = boundSize.GetHeight() / static_cast<float>(image_->GetHeight());
154 if (ROSEN_EQ(scaleY, scaleX, SCALE_DIFF)) {
155 canvas.Scale(scaleX, scaleY);
156 } else {
157 canvas.Scale(gravityMatrix.Get(Drawing::Matrix::SCALE_X), gravityMatrix.Get(Drawing::Matrix::SCALE_Y));
158 }
159 if (RSSystemProperties::GetRecordingEnabled()) {
160 if (image_->IsTextureBacked()) {
161 RS_LOGI("DealWithCachedWindow convert image from texture to raster image.");
162 image_ = image_->MakeRasterImage();
163 }
164 }
165 Drawing::Brush brush;
166 canvas.AttachBrush(brush);
167 auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
168 auto translateX = gravityMatrix.Get(Drawing::Matrix::TRANS_X);
169 auto translateY = gravityMatrix.Get(Drawing::Matrix::TRANS_Y);
170 // draw BehindWindowFilter
171 surfaceDrawable->GetRsSubThreadCache().DrawBehindWindowBeforeCache(canvas, translateX, translateY);
172 // draw content/children
173 canvas.DrawImage(*image_, translateX, translateY, samplingOptions);
174 canvas.DetachBrush();
175 // draw foreground
176 surfaceDrawable->DrawForeground(canvas, boundSize);
177 // draw watermark
178 surfaceDrawable->DrawWatermark(canvas, surfaceParams);
179 if (surfaceParams.IsCrossNode() &&
180 uniParam.GetCrossNodeOffScreenStatus() == CrossNodeOffScreenRenderDebugType::ENABLE_DFX) {
181 // rgba: Alpha 128, red 255, green 128, blue 128
182 Drawing::Color color(255, 128, 128, 128);
183 DrawCrossNodeOffscreenDFX(canvas, surfaceParams, uniParam, color);
184 }
185 return true;
186 }
187 #endif
188
DrawCrossNodeOffscreenDFX(RSPaintFilterCanvas & canvas,RSSurfaceRenderParams & surfaceParams,RSRenderThreadParams & uniParams,const Drawing::Color & color)189 void RSDrawWindowCache::DrawCrossNodeOffscreenDFX(RSPaintFilterCanvas &canvas,
190 RSSurfaceRenderParams &surfaceParams, RSRenderThreadParams &uniParams, const Drawing::Color& color)
191 {
192 std::string info = "IsCrossNode: " + std::to_string(surfaceParams.IsCrossNode());
193 info += " IsFirstVisitCrossNodeDisplay: " + std::to_string(uniParams.IsFirstVisitCrossNodeDisplay());
194
195 Drawing::Font font;
196 // 30.f:Scalar of font size
197 font.SetSize(50.f);
198 std::shared_ptr<Drawing::TextBlob> textBlob = Drawing::TextBlob::MakeFromString(info.c_str(), font);
199 Drawing::Brush brush;
200 brush.SetColor(Drawing::Color::COLOR_RED);
201 canvas.AttachBrush(brush);
202 // 50.f: Scalar x of drawing TextBlob; 100.f: Scalar y of drawing TextBlob
203 canvas.DrawTextBlob(textBlob.get(), 50.f, 100.f);
204
205 info = "";
206 info += " IsMirrorScreen: " + std::to_string(uniParams.IsMirrorScreen());
207 info += " NeedCacheSurface: " + std::to_string(surfaceParams.GetNeedCacheSurface());
208 textBlob = Drawing::TextBlob::MakeFromString(info.c_str(), font);
209 // 50.f: Scalar x of drawing TextBlob; 150.f: Scalar y of drawing TextBlob
210 canvas.DrawTextBlob(textBlob.get(), 50.f, 150.f);
211 canvas.DetachBrush();
212
213 if (image_) {
214 auto sizeDebug = surfaceParams.GetCacheSize();
215 Drawing::Brush rectBrush;
216 rectBrush.SetColor(color);
217 canvas.AttachBrush(rectBrush);
218 canvas.DrawRect(Drawing::Rect(0, 0, sizeDebug.x_, sizeDebug.y_));
219 canvas.DetachBrush();
220 }
221 }
222
ClearCache()223 void RSDrawWindowCache::ClearCache()
224 {
225 image_ = nullptr;
226 }
227
HasCache() const228 bool RSDrawWindowCache::HasCache() const
229 {
230 return image_ != nullptr;
231 }
232
233 } // Rosen
234 } // OHOS