• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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_window_keyframe_buffer.h"
17 #include <algorithm>
18 #include "draw/brush.h"
19 #include "draw/surface.h"
20 #include "platform/common/rs_log.h"
21 #include "pipeline/render_thread/rs_uni_render_thread.h"
22 #include "rs_trace.h"
23 
24 namespace OHOS::Rosen {
25 
RSWindowKeyframeBuffer(DrawableV2::RSCanvasRenderNodeDrawable & drawable)26 RSWindowKeyframeBuffer::RSWindowKeyframeBuffer(DrawableV2::RSCanvasRenderNodeDrawable& drawable)
27     : canvasNodeDrawable_(drawable)
28 {
29 }
30 
NeedDrawWindowKeyFrame(const std::unique_ptr<RSRenderParams> & params)31 bool RSWindowKeyframeBuffer::NeedDrawWindowKeyFrame(const std::unique_ptr<RSRenderParams>& params)
32 {
33     if (UNLIKELY(params == nullptr)) {
34         RS_LOGE("RSWindowKeyframeBuffer::NeedDrawWindowKeyFrame params is nullptr");
35         return false;
36     }
37 
38     if (LIKELY(!params->IsWindowKeyFrameEnabled())) {
39         cachedOffscreenImg_ = nullptr;
40         preCachedOffscreenImg_ = nullptr;
41         return false;
42     }
43 
44     return true;
45 }
46 
OnDraw(Drawing::Canvas & canvas,const RSRenderParams & params)47 bool RSWindowKeyframeBuffer::OnDraw(Drawing::Canvas& canvas, const RSRenderParams& params)
48 {
49     auto& uniParams = RSUniRenderThread::Instance().GetRSRenderThreadParams();
50     if (UNLIKELY(uniParams == nullptr)) {
51         RS_LOGE("RSWindowKeyframeBuffer::DrawOffscreenToBuffer uniParams is nullptr");
52         return false;
53     }
54 
55     auto curCanvas = static_cast<RSPaintFilterCanvas*>(&canvas);
56     auto curSurface = curCanvas->GetSurface();
57     if (UNLIKELY(curSurface == nullptr)) {
58         RS_LOGE("RSWindowKeyframeBuffer::DrawOffscreenToBuffer surface is nullptr");
59         return false;
60     }
61 
62     auto bounds = params.GetFrameRect();
63     auto cacheSurface = curSurface->MakeSurface(bounds.GetWidth(), bounds.GetHeight());
64     if (UNLIKELY(cacheSurface == nullptr)) {
65         RS_LOGE("RSWindowKeyframeBuffer::DrawOffscreenToBuffer make surface failed");
66         return false;
67     }
68 
69     auto cacheCanvas = std::make_shared<RSPaintFilterCanvas>(cacheSurface.get());
70     if (UNLIKELY(cacheCanvas == nullptr)) {
71         RS_LOGE("RSWindowKeyframeBuffer::DrawOffscreenToBuffer make canvas failed");
72         return false;
73     }
74 
75     // Copy HDR properties into offscreen canvas
76     cacheCanvas->CopyHDRConfiguration(*curCanvas);
77 
78     // Copy current canvas properties into offscreen canvas
79     cacheCanvas->CopyConfigurationToOffscreenCanvas(*curCanvas);
80     cacheCanvas->SetDisableFilterCache(true);
81     RSAutoCanvasRestore acr(cacheCanvas, RSPaintFilterCanvas::SaveType::kCanvasAndAlpha);
82     cacheCanvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
83 
84     bool isOpDropped = uniParams->IsOpDropped();
85     uniParams->SetOpDropped(false); // temporarily close partial render
86     canvasNodeDrawable_.DrawableV2::RSCanvasRenderNodeDrawable::OnDraw(*cacheCanvas);
87     uniParams->SetOpDropped(isOpDropped);
88     params.ApplyAlphaAndMatrixToCanvas(*curCanvas, true);
89 
90     return DrawOffscreenImgToBuffer(canvas, params, bounds, cacheSurface);
91 }
92 
DrawOffscreenImgToBuffer(Drawing::Canvas & canvas,const RSRenderParams & params,const Drawing::Rect & bounds,std::shared_ptr<Drawing::Surface> & surface)93 bool RSWindowKeyframeBuffer::DrawOffscreenImgToBuffer(Drawing::Canvas& canvas, const RSRenderParams& params,
94     const Drawing::Rect& bounds, std::shared_ptr<Drawing::Surface>& surface)
95 {
96     // cache and draw snapshot of offscreen canvas onto target canvas
97     if (params.GetNeedSwapBuffer()) {
98         std::swap(cachedOffscreenImg_, preCachedOffscreenImg_);
99     }
100 
101     cachedOffscreenImg_ = surface->GetImageSnapshot();
102     if (cachedOffscreenImg_ == nullptr) {
103         RS_LOGE("RSWindowKeyframeBuffer::DrawOffscreenToBuffer get snapshot nullptr");
104         return false;
105     }
106 
107     if (preCachedOffscreenImg_ == nullptr && params.GetNeedSwapBuffer()) {
108         preCachedOffscreenImg_ = cachedOffscreenImg_;
109     }
110 
111     Drawing::Brush paint;
112     paint.SetAntiAlias(true);
113     canvas.AttachBrush(paint);
114     auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::NEAREST, Drawing::MipmapMode::NONE);
115     Drawing::Rect cacheBounds = params.GetCacheNodeFrameRect();
116     if (!cacheBounds.IsEmpty()) {
117         // keep aspect ratio for scale
118         Drawing::Rect srcRect;
119         srcRect.left_ = 0;
120         srcRect.top_ = 0;
121         if (bounds.GetWidth() * cacheBounds.GetHeight() / bounds.GetHeight() >= cacheBounds.GetWidth()) {
122             srcRect.right_ = bounds.GetHeight() * cacheBounds.GetWidth() / cacheBounds.GetHeight();
123             srcRect.bottom_ = bounds.GetHeight();
124         } else {
125             srcRect.right_ = bounds.GetWidth();
126             srcRect.bottom_ = bounds.GetWidth() * cacheBounds.GetHeight() / cacheBounds.GetWidth();
127         }
128         canvas.DrawImageRect(*cachedOffscreenImg_, srcRect, cacheBounds, samplingOptions);
129     } else {
130         canvas.DrawImageRect(*cachedOffscreenImg_, bounds, samplingOptions);
131     }
132     canvas.DetachBrush();
133 
134     return true;
135 }
136 
DrawOffscreenBuffer(RSPaintFilterCanvas & canvas,const Drawing::Rect & bounds,float alpha,bool isFreezed)137 bool RSWindowKeyframeBuffer::DrawOffscreenBuffer(
138     RSPaintFilterCanvas& canvas, const Drawing::Rect& bounds, float alpha, bool isFreezed)
139 {
140     if (preCachedOffscreenImg_ == nullptr) {
141         RS_LOGE("RSWindowKeyframeBuffer::DrawOffscreenToBuffer preCachedOffscreenImg_ is nullptr");
142         return false;
143     }
144 
145     float rootWidth = 0.0f;
146     float rootHeight = 0.0f;
147     const auto& params = canvasNodeDrawable_.GetRenderParams();
148     if (params != nullptr) {
149         rootWidth = params->GetFrameRect().GetWidth();
150         rootHeight = params->GetFrameRect().GetHeight();
151     }
152 
153     RS_TRACE_NAME_FMT("DrawCacheNode rootNode:(%.0f, %.0f), canvasNode:(%.0f, %.0f) alpha:%.2f, freeze:%d",
154         rootWidth, rootHeight, bounds.GetWidth(), bounds.GetHeight(), alpha, isFreezed);
155 
156     RSAutoCanvasRestore acr(&canvas);
157     Drawing::Brush paint;
158     paint.SetAntiAlias(true);
159     canvas.AttachBrush(paint);
160     auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::NEAREST, Drawing::MipmapMode::NONE);
161 
162     Drawing::Rect srcRect;
163     srcRect.left_ = 0;
164     srcRect.top_ = 0;
165     int imgW = preCachedOffscreenImg_->GetWidth();
166     int imgH = preCachedOffscreenImg_->GetHeight();
167     if (imgW <= 0 || imgH <= 0 || bounds.IsEmpty()) {
168         RS_LOGE("RSWindowKeyframeBuffer::DrawOffscreenToBuffer preCachedOffscreenImg size or bounds is invalid");
169         return false;
170     }
171 
172     // keep aspect ratio for scale
173     if (imgW * bounds.GetHeight() / imgH >= bounds.GetWidth()) {
174         srcRect.right_ = imgH * bounds.GetWidth() / bounds.GetHeight();
175         srcRect.bottom_ = imgH;
176     } else {
177         srcRect.right_ = imgW;
178         srcRect.bottom_ = imgW * bounds.GetHeight() / bounds.GetWidth();
179     }
180     canvas.DrawImageRect(*preCachedOffscreenImg_, srcRect, bounds, samplingOptions,
181         Drawing::SrcRectConstraint::STRICT_SRC_RECT_CONSTRAINT);
182     canvas.DetachBrush();
183 
184     return true;
185 }
186 
187 } // namespace OHOS::Rosen
188