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