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