• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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