• 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 
17 #include "rs_sub_thread_cache.h"
18 
19 #include <memory>
20 
21 #include "impl_interface/region_impl.h"
22 #include "rs_trace.h"
23 
24 #include "common/rs_color.h"
25 #include "common/rs_common_def.h"
26 #include "common/rs_obj_abs_geometry.h"
27 #include "common/rs_optional_trace.h"
28 #include "draw/brush.h"
29 #include "drawable/rs_surface_render_node_drawable.h"
30 #include "feature/uifirst/rs_sub_thread_manager.h"
31 #include "feature/uifirst/rs_uifirst_manager.h"
32 #include "memory/rs_tag_tracker.h"
33 #include "params/rs_screen_render_params.h"
34 #include "params/rs_surface_render_params.h"
35 #include "pipeline/render_thread/rs_uni_render_thread.h"
36 #include "pipeline/render_thread/rs_uni_render_util.h"
37 #include "pipeline/main_thread/rs_main_thread.h"
38 #include "pipeline/rs_paint_filter_canvas.h"
39 #include "pipeline/rs_surface_render_node.h"
40 #include "pipeline/sk_resource_manager.h"
41 #include "platform/common/rs_log.h"
42 #include "render/rs_drawing_filter.h"
43 #include "rs_profiler.h"
44 #include "rs_frame_report.h"
45 #include "utils/rect.h"
46 #include "utils/region.h"
47 #ifdef RS_ENABLE_VK
48 #ifdef USE_M133_SKIA
49 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
50 #else
51 #include "include/gpu/GrBackendSurface.h"
52 #endif
53 #include "platform/ohos/backend/native_buffer_utils.h"
54 #include "platform/ohos/backend/rs_vulkan_context.h"
55 #endif
56 
57 #undef LOG_TAG
58 #define LOG_TAG "RsSubThreadCache"
59 
60 namespace {
__anon4cca00ee0202() 61 static const OHOS::Rosen::Drawing::Matrix IDENTITY_MATRIX = []() {
62     OHOS::Rosen::Drawing::Matrix matrix;
63     matrix.SetMatrix(1.0f, 0.0f, 0.0f,
64                      0.0f, 1.0f, 0.0f,
65                      0.0f, 0.0f, 1.0f);
66     return matrix;
67 }();
68 constexpr float SCALE_DIFF = 0.01f;
69 }
70 
71 namespace OHOS::Rosen::DrawableV2 {
RsSubThreadCache()72 RsSubThreadCache::RsSubThreadCache()
73     : syncUifirstDirtyManager_(std::make_shared<RSDirtyRegionManager>())
74 {}
75 
BufferFormatNeedUpdate(std::shared_ptr<Drawing::Surface> cacheSurface,bool isNeedFP16)76 bool RsSubThreadCache::BufferFormatNeedUpdate(std::shared_ptr<Drawing::Surface> cacheSurface,
77     bool isNeedFP16)
78 {
79     bool bufferFormatNeedUpdate = cacheSurface ? isNeedFP16 &&
80         cacheSurface->GetImageInfo().GetColorType() != Drawing::ColorType::COLORTYPE_RGBA_F16 : false;
81     RS_LOGD("BufferFormatNeedUpdate: %{public}d", bufferFormatNeedUpdate);
82     return bufferFormatNeedUpdate;
83 }
84 
GetCacheSurfaceProcessedStatus() const85 CacheProcessStatus RsSubThreadCache::GetCacheSurfaceProcessedStatus() const
86 {
87     return uiFirstParams.cacheProcessStatus_.load();
88 }
89 
SetCacheSurfaceProcessedStatus(CacheProcessStatus cacheProcessStatus)90 void RsSubThreadCache::SetCacheSurfaceProcessedStatus(CacheProcessStatus cacheProcessStatus)
91 {
92     if (cacheProcessStatus == CacheProcessStatus::DONE || cacheProcessStatus == CacheProcessStatus::SKIPPED) {
93         RSUiFirstProcessStateCheckerHelper::NotifyAll([this, cacheProcessStatus] {
94             uiFirstParams.cacheProcessStatus_.store(cacheProcessStatus);
95         });
96     } else {
97         uiFirstParams.cacheProcessStatus_.store(cacheProcessStatus);
98     }
99 }
100 
GetCacheSurface(uint32_t threadIndex)101 std::shared_ptr<Drawing::Surface> RsSubThreadCache::GetCacheSurface(uint32_t threadIndex)
102 {
103     if (cacheSurfaceThreadIndex_ == threadIndex) {
104         return cacheSurface_;
105     }
106     return nullptr;
107 }
108 
ClearCacheSurfaceInThread()109 void RsSubThreadCache::ClearCacheSurfaceInThread()
110 {
111     RS_TRACE_NAME_FMT("ClearCacheSurfaceInThread id:%" PRIu64, nodeId_);
112     RS_LOGI("ClearCacheSurfaceInThread id:%{public}" PRIu64, nodeId_);
113     std::scoped_lock<std::recursive_mutex> lock(completeResourceMutex_);
114     if (clearCacheSurfaceFunc_) {
115         clearCacheSurfaceFunc_(std::move(cacheSurface_), std::move(cacheCompletedSurface_),
116             cacheSurfaceThreadIndex_, completedSurfaceThreadIndex_);
117     }
118     ClearCacheSurface();
119 }
120 
ClearCacheSurfaceOnly()121 void RsSubThreadCache::ClearCacheSurfaceOnly()
122 {
123     RS_TRACE_NAME_FMT("ClearCacheSurfaceOnly id:%" PRIu64, nodeId_);
124     RS_LOGI("ClearCacheSurfaceOnly id:%{public}" PRIu64, nodeId_);
125     if (cacheSurface_ == nullptr) {
126         return;
127     }
128     if (clearCacheSurfaceFunc_) {
129         clearCacheSurfaceFunc_(
130             std::move(cacheSurface_), nullptr, cacheSurfaceThreadIndex_, completedSurfaceThreadIndex_);
131     }
132     ClearCacheSurface(false);
133     cacheSurface_.reset();
134 }
135 
GetCompletedImage(RSPaintFilterCanvas & canvas,uint32_t threadIndex,bool isUIFirst)136 std::shared_ptr<Drawing::Image> RsSubThreadCache::GetCompletedImage(
137     RSPaintFilterCanvas& canvas, uint32_t threadIndex, bool isUIFirst)
138 {
139     auto gpuContext = canvas.GetGPUContext();
140     if (!gpuContext) {
141         RS_LOGE("GetCompletedImage GetGPUContext nullptr");
142         return nullptr;
143     }
144     if (isUIFirst) {
145 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
146         std::scoped_lock<std::recursive_mutex> lock(completeResourceMutex_);
147         if (!cacheCompletedBackendTexture_.IsValid()) {
148             RS_LOGE("GetCompletedImage invalid grBackendTexture_");
149             return nullptr;
150         }
151         auto colorType = Drawing::COLORTYPE_RGBA_8888;
152 #ifdef RS_ENABLE_VK
153         if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::VULKAN ||
154             OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::DDGR) {
155             if (!cacheCompletedSurface_ || !cacheCompletedCleanupHelper_) {
156                 RS_LOGE("GetCompletedImage %{public}s is nullptr",
157                     cacheCompletedSurface_ == nullptr ? "surface" : "cleanupHelper");
158                 return nullptr;
159             }
160         }
161         auto vkTexture = cacheCompletedBackendTexture_.GetTextureInfo().GetVKTextureInfo();
162         // When the colorType is FP16, the colorspace of the uifirst buffer must be sRGB
163         // In other cases, ensure the image's color space matches the target surface's color profile.
164         auto colorSpace = Drawing::ColorSpace::CreateSRGB();
165         if (vkTexture != nullptr && vkTexture->format == VK_FORMAT_R16G16B16A16_SFLOAT) {
166             colorType = Drawing::ColorType::COLORTYPE_RGBA_F16;
167         } else if (cacheCompletedSurface_) {
168             colorSpace = cacheCompletedSurface_->GetImageInfo().GetColorSpace();
169         }
170 #endif
171         auto image = std::make_shared<Drawing::Image>();
172         Drawing::TextureOrigin origin = Drawing::TextureOrigin::BOTTOM_LEFT;
173         Drawing::BitmapFormat info = Drawing::BitmapFormat{ colorType,
174             Drawing::ALPHATYPE_PREMUL };
175 #ifdef RS_ENABLE_GL
176         if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::VULKAN &&
177             OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::DDGR) {
178             image->BuildFromTexture(*gpuContext, cacheCompletedBackendTexture_.GetTextureInfo(),
179                 origin, info, nullptr);
180         }
181 #endif
182 
183 #ifdef RS_ENABLE_VK
184         if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::VULKAN ||
185             OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::DDGR) {
186             image->BuildFromTexture(*gpuContext, cacheCompletedBackendTexture_.GetTextureInfo(),
187                 origin, info, colorSpace, NativeBufferUtils::DeleteVkImage, cacheCompletedCleanupHelper_->Ref());
188         }
189 #endif
190         return image;
191 #endif
192     }
193 
194     if (!cacheCompletedSurface_) {
195         RS_LOGE("GetCompletedImage invalid cacheCompletedSurface");
196         return nullptr;
197     }
198     auto completeImage = cacheCompletedSurface_->GetImageSnapshot();
199     if (!completeImage) {
200         RS_LOGE("GetCompletedImage Get complete image failed");
201         return nullptr;
202     }
203     if (threadIndex == completedSurfaceThreadIndex_) {
204         return completeImage;
205     }
206 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
207     Drawing::TextureOrigin origin = Drawing::TextureOrigin::BOTTOM_LEFT;
208     auto backendTexture = completeImage->GetBackendTexture(false, &origin);
209     if (!backendTexture.IsValid()) {
210         RS_LOGE("GetCompletedImage get backendTexture failed");
211         return nullptr;
212     }
213     SharedTextureContext* sharedContext = new SharedTextureContext(completeImage);
214     auto cacheImage = std::make_shared<Drawing::Image>();
215     Drawing::BitmapFormat info =
216         Drawing::BitmapFormat{ completeImage->GetColorType(), completeImage->GetAlphaType() };
217     bool ret = cacheImage->BuildFromTexture(*gpuContext, backendTexture.GetTextureInfo(),
218         origin, info, nullptr, SKResourceManager::DeleteSharedTextureContext, sharedContext);
219     if (!ret) {
220         RS_LOGE("GetCompletedImage image BuildFromTexture failed");
221         return nullptr;
222     }
223     return cacheImage;
224 #else
225     return completeImage;
226 #endif
227 }
228 
DrawCacheSurface(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,RSPaintFilterCanvas & canvas,const Vector2f & boundSize,uint32_t threadIndex,bool isUIFirst)229 bool RsSubThreadCache::DrawCacheSurface(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
230     RSPaintFilterCanvas& canvas, const Vector2f& boundSize, uint32_t threadIndex, bool isUIFirst)
231 {
232     if (!surfaceDrawable) {
233         RS_LOGE("DrawCacheSurface surfaceDrawable is nullptr. id:%{public}" PRIu64, nodeId_);
234         return false;
235     }
236     if (ROSEN_EQ(surfaceDrawable->boundsWidth_, 0.f) || ROSEN_EQ(surfaceDrawable->boundsHeight_, 0.f)) {
237         RS_LOGE("DrawCacheSurface surface bound is 0. id:%{public}" PRIu64, nodeId_);
238         return false;
239     }
240 
241     auto cacheImage = GetCompletedImage(canvas, threadIndex, isUIFirst);
242     RSBaseRenderUtil::WriteCacheImageRenderNodeToPng(cacheImage, "cacheImage");
243     if (cacheImage == nullptr || ROSEN_EQ(cacheImage->GetWidth(), 0) ||
244         ROSEN_EQ(cacheImage->GetHeight(), 0)) {
245         RS_LOGE("DrawCacheSurface cacheImage invalid. id:%{public}" PRIu64, nodeId_);
246         return false;
247     }
248     canvas.Save();
249     const auto& gravityMatrix = surfaceDrawable->GetGravityMatrix(cacheImage->GetWidth(), cacheImage->GetHeight());
250     float scaleX = boundSize.x_ / static_cast<float>(cacheImage->GetWidth());
251     float scaleY = boundSize.y_ / static_cast<float>(cacheImage->GetHeight());
252     if (ROSEN_EQ(scaleY, scaleX, SCALE_DIFF)) {
253         canvas.Scale(scaleX, scaleY);
254     } else {
255         canvas.Scale(gravityMatrix.Get(Drawing::Matrix::SCALE_X), gravityMatrix.Get(Drawing::Matrix::SCALE_Y));
256     }
257     if (RSSystemProperties::GetRecordingEnabled()) {
258         if (cacheImage->IsTextureBacked()) {
259             RS_LOGI("DrawCacheSurface convert cacheImage from texture to raster image");
260             cacheImage = cacheImage->MakeRasterImage();
261             if (!cacheImage) {
262                 RS_LOGE("DrawCacheSurface: MakeRasterImage failed");
263                 canvas.Restore();
264                 return false;
265             }
266         }
267     }
268     Drawing::Brush brush;
269     canvas.AttachBrush(brush);
270     auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
271     auto translateX = gravityMatrix.Get(Drawing::Matrix::TRANS_X);
272     auto translateY = gravityMatrix.Get(Drawing::Matrix::TRANS_Y);
273     DrawBehindWindowBeforeCache(canvas, translateX, translateY);
274     auto stencilVal = canvas.GetStencilVal();
275     if (stencilVal > Drawing::Canvas::INVALID_STENCIL_VAL && stencilVal < canvas.GetMaxStencilVal()) {
276         RS_OPTIONAL_TRACE_NAME_FMT("DrawImageWithStencil, stencilVal: %" PRId64 "", stencilVal);
277         RS_LOGD("DrawImageWithStencil, stencilVal: %{public}" PRId64 "", stencilVal);
278         canvas.DrawImageWithStencil(*cacheImage, translateX, translateY, samplingOptions,
279             static_cast<uint32_t>(stencilVal));
280     } else {
281         canvas.DrawImage(*cacheImage, translateX, translateY, samplingOptions);
282     }
283     canvas.DetachBrush();
284     canvas.Restore();
285     return true;
286 }
287 
InitCacheSurface(Drawing::GPUContext * gpuContext,std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable,ClearCacheSurfaceFunc func,uint32_t threadIndex,bool isNeedFP16)288 void RsSubThreadCache::InitCacheSurface(Drawing::GPUContext* gpuContext,
289     std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable,
290     ClearCacheSurfaceFunc func, uint32_t threadIndex, bool isNeedFP16)
291 {
292     RS_TRACE_NAME_FMT("InitCanvasSurface id:%" PRIu64" targetColorGamut:%d isNeedFP16:%d",
293         nodeId_, targetColorGamut_, isNeedFP16);
294     if (!nodeDrawable) {
295         RS_LOGE("InitCacheSurface nodeDrawable is nullptr");
296         return;
297     }
298     if (func) {
299         cacheSurfaceThreadIndex_ = threadIndex;
300         if (!clearCacheSurfaceFunc_) {
301             clearCacheSurfaceFunc_ = func;
302         }
303         if (cacheSurface_) {
304             func(std::move(cacheSurface_), nullptr,
305                 cacheSurfaceThreadIndex_, completedSurfaceThreadIndex_);
306             cacheSurface_ = nullptr;
307         }
308     } else {
309         cacheSurface_ = nullptr;
310     }
311 
312     float width = 0.0f;
313     float height = 0.0f;
314     if (const auto& params = nodeDrawable->GetRenderParams()) {
315         auto size = params->GetCacheSize();
316         nodeDrawable->boundsWidth_ = size.x_;
317         nodeDrawable->boundsHeight_ = size.y_;
318     } else {
319         RS_LOGE("uifirst cannot get cachesize");
320     }
321 
322     width = nodeDrawable->boundsWidth_;
323     height = nodeDrawable->boundsHeight_;
324 
325 #if (defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)) && (defined RS_ENABLE_EGLIMAGE)
326     if (gpuContext == nullptr) {
327         if (func) {
328             std::scoped_lock<std::recursive_mutex> lock(completeResourceMutex_);
329             func(std::move(cacheSurface_), std::move(cacheCompletedSurface_),
330                 cacheSurfaceThreadIndex_, completedSurfaceThreadIndex_);
331             ClearCacheSurface();
332         }
333         RS_LOGE("InitCacheSurface gpuContext == nullptr");
334         return;
335     }
336 #ifdef RS_ENABLE_GL
337     if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::VULKAN &&
338         OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::DDGR) {
339         Drawing::ImageInfo info = Drawing::ImageInfo::MakeN32Premul(width, height);
340         cacheSurface_ = Drawing::Surface::MakeRenderTarget(gpuContext, true, info);
341     }
342 #endif
343 #ifdef RS_ENABLE_VK
344     if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::VULKAN ||
345         OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::DDGR) {
346         VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
347         auto colorType = Drawing::ColorType::COLORTYPE_RGBA_8888;
348         // When the colorType is FP16, the colorspace of the uifirst buffer must be sRGB
349         // In other cases, the colorspace follows the targetColorGamut_
350         auto colorSpace = Drawing::ColorSpace::CreateSRGB();
351         RS_LOGD("InitCacheSurface sub thread cache's targetColorGamut_ is [%{public}d]", targetColorGamut_);
352         if (isNeedFP16) {
353             format = VK_FORMAT_R16G16B16A16_SFLOAT;
354             colorType = Drawing::ColorType::COLORTYPE_RGBA_F16;
355             RS_LOGD("InitCacheSurface colorType is FP16, take colorspace to sRGB");
356         } else if (targetColorGamut_ != GRAPHIC_COLOR_GAMUT_SRGB) {
357             colorSpace =
358                 Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB, Drawing::CMSMatrixType::DCIP3);
359         }
360         cacheBackendTexture_ = NativeBufferUtils::MakeBackendTexture(
361             width, height, ExtractPid(nodeDrawable->nodeId_), format);
362         auto vkTextureInfo = cacheBackendTexture_.GetTextureInfo().GetVKTextureInfo();
363         if (!cacheBackendTexture_.IsValid() || !vkTextureInfo) {
364             if (func) {
365                 std::scoped_lock<std::recursive_mutex> lock(completeResourceMutex_);
366                 func(std::move(cacheSurface_), std::move(cacheCompletedSurface_),
367                     cacheSurfaceThreadIndex_, completedSurfaceThreadIndex_);
368                 ClearCacheSurface();
369             }
370             RS_LOGE("InitCacheSurface !cacheBackendTexture_.IsValid() || !vkTextureInfo");
371             return;
372         }
373         cacheCleanupHelper_ = new NativeBufferUtils::VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
374             vkTextureInfo->vkImage, vkTextureInfo->vkAlloc.memory, vkTextureInfo->vkAlloc.statName);
375         cacheSurface_ = Drawing::Surface::MakeFromBackendTexture(
376             gpuContext, cacheBackendTexture_.GetTextureInfo(), Drawing::TextureOrigin::BOTTOM_LEFT,
377             1, colorType, colorSpace, NativeBufferUtils::DeleteVkImage, cacheCleanupHelper_);
378     }
379 #endif
380 #else
381     cacheSurface_ = Drawing::Surface::MakeRasterN32Premul(width, height);
382 #endif
383 }
384 
ResetUifirst(bool isOnlyClearCache)385 void RsSubThreadCache::ResetUifirst(bool isOnlyClearCache)
386 {
387     RS_LOGI("ResetUifirst id:%{public}" PRIu64 ", isOnlyClearCache:%{public}d", nodeId_, isOnlyClearCache);
388     if (isOnlyClearCache) {
389         ClearCacheSurfaceOnly();
390     } else {
391         ClearCacheSurfaceInThread();
392     }
393 }
394 
HasCachedTexture() const395 bool RsSubThreadCache::HasCachedTexture() const
396 {
397     return isCacheCompletedValid_;
398 }
399 
IsCacheValid() const400 bool RsSubThreadCache::IsCacheValid() const
401 {
402     return isCacheValid_;
403 }
404 
NeedInitCacheSurface(RSSurfaceRenderParams * surfaceParams)405 bool RsSubThreadCache::NeedInitCacheSurface(RSSurfaceRenderParams* surfaceParams)
406 {
407     int width = 0;
408     int height = 0;
409 
410     if (surfaceParams) {
411         auto size = surfaceParams->GetCacheSize();
412         width =  size.x_;
413         height = size.y_;
414     }
415 
416     if (cacheSurface_ == nullptr) {
417         return true;
418     }
419     auto cacheCanvas = cacheSurface_->GetCanvas();
420     if (cacheCanvas == nullptr) {
421         return true;
422     }
423     return cacheCanvas->GetWidth() != width || cacheCanvas->GetHeight() != height;
424 }
425 
426 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
UpdateBackendTexture()427 void RsSubThreadCache::UpdateBackendTexture()
428 {
429     RS_TRACE_NAME_FMT("UpdateBackendTexture");
430     if (cacheSurface_ == nullptr) {
431         RS_LOGE("UpdateBackendTexture cacheSurface is nullptr");
432         return;
433     }
434     cacheBackendTexture_ = cacheSurface_->GetBackendTexture();
435     isCacheValid_ = true;
436 }
437 #endif
438 
UpdateCompletedCacheSurface()439 void RsSubThreadCache::UpdateCompletedCacheSurface()
440 {
441     RS_TRACE_NAME_FMT("UpdateCompletedCacheSurface id:%" PRIu64, nodeId_);
442     RS_LOGD("UpdateCompletedCacheSurface id:%{public}" PRIu64, nodeId_);
443     if (cacheSurface_ == nullptr || !IsCacheValid()) {
444         RS_LOGE("cacheSurface is nullptr, cache and completeCache swap failed");
445         isCacheValid_ = false;
446         return;
447     }
448     // renderthread not use, subthread done not use
449     std::swap(cacheSurface_, cacheCompletedSurface_);
450     std::swap(cacheSurfaceThreadIndex_, completedSurfaceThreadIndex_);
451     std::swap(cacheSurfaceInfo_, cacheCompletedSurfaceInfo_);
452     std::swap(cacheBehindWindowData_, cacheCompletedBehindWindowData_);
453 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
454     std::swap(cacheBackendTexture_, cacheCompletedBackendTexture_);
455 #ifdef RS_ENABLE_VK
456     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
457         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
458         std::swap(cacheCleanupHelper_, cacheCompletedCleanupHelper_);
459     }
460 #endif
461     std::swap(isCacheValid_, isCacheCompletedValid_);
462     isTextureValid_.store(true);
463     SetCacheSurfaceNeedUpdated(false);
464 #endif
465     RSBaseRenderUtil::WriteCacheImageRenderNodeToPng(cacheSurface_, "cacheSurface_");
466     RSBaseRenderUtil::WriteCacheImageRenderNodeToPng(cacheCompletedSurface_, "cacheCompletedSurface_");
467 }
468 
ClearCacheSurface(bool isClearCompletedCacheSurface)469 void RsSubThreadCache::ClearCacheSurface(bool isClearCompletedCacheSurface)
470 {
471     cacheSurface_ = nullptr;
472     cacheSurfaceInfo_ = { -1, -1, -1.f };
473     isCacheValid_ = false;
474     ResetCacheBehindWindowData();
475 #ifdef RS_ENABLE_VK
476     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
477         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
478         cacheCleanupHelper_ = nullptr;
479     }
480 #endif
481     if (isClearCompletedCacheSurface) {
482         std::scoped_lock<std::recursive_mutex> lock(completeResourceMutex_);
483         cacheCompletedSurface_ = nullptr;
484         cacheCompletedSurfaceInfo_ = { -1, -1, -1.f };
485         isCacheCompletedValid_ = false;
486         ResetCacheCompletedBehindWindowData();
487 #ifdef RS_ENABLE_VK
488         if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
489             RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
490             cacheCompletedCleanupHelper_ = nullptr;
491         }
492 #endif
493 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
494         isTextureValid_.store(false);
495 #endif
496     }
497 }
498 
SetTaskFrameCount(uint64_t frameCount)499 void RsSubThreadCache::SetTaskFrameCount(uint64_t frameCount)
500 {
501     frameCount_ = frameCount;
502 }
503 
GetTaskFrameCount() const504 uint64_t RsSubThreadCache::GetTaskFrameCount() const
505 {
506     return frameCount_;
507 }
508 
GetSyncUifirstDirtyManager() const509 std::shared_ptr<RSDirtyRegionManager> RsSubThreadCache::GetSyncUifirstDirtyManager() const
510 {
511     return syncUifirstDirtyManager_;
512 }
513 
UpdateCacheSurfaceDirtyManager(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,bool hasCompletateCache,bool isLastFrameSkip)514 bool RsSubThreadCache::UpdateCacheSurfaceDirtyManager(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
515     bool hasCompletateCache, bool isLastFrameSkip)
516 {
517     if (!surfaceDrawable) {
518         RS_LOGE("UpdateCacheSurfaceDirtyManager surfaceDrawable is nullptr");
519         return false;
520     }
521     if (!syncUifirstDirtyManager_ || !surfaceDrawable->syncDirtyManager_) {
522         RS_LOGE("UpdateCacheSurfaceDirtyManager dirty manager is nullptr");
523         return false;
524     }
525     syncUifirstDirtyManager_->Clear();
526     auto curDirtyRegion = surfaceDrawable->syncDirtyManager_->GetDirtyRegion();
527     auto& curFrameDirtyRegion = surfaceDrawable->syncDirtyManager_->GetUifirstFrameDirtyRegion();
528     curDirtyRegion = curDirtyRegion.JoinRect(curFrameDirtyRegion);
529     if (isLastFrameSkip) {
530         curDirtyRegion = curDirtyRegion.JoinRect(syncUifirstDirtyManager_->GetUiLatestHistoryDirtyRegions(1));
531     }
532     auto surfaceParams = static_cast<RSSurfaceRenderParams*>(surfaceDrawable->GetRenderParams().get());
533     if (!surfaceParams) {
534         RS_LOGE("UpdateCacheSurfaceDirtyManager surfaceParams is nullptr");
535         return false;
536     }
537     if (!hasCompletateCache) {
538         curDirtyRegion = surfaceParams->GetAbsDrawRect();
539     }
540     RS_TRACE_NAME_FMT("UpdateCacheSurfaceDirtyManager[%s] %" PRIu64", curDirtyRegion[%d %d %d %d], hasCache:%d",
541         surfaceDrawable->GetName().c_str(), surfaceDrawable->GetId(), curDirtyRegion.GetLeft(),
542         curDirtyRegion.GetTop(), curDirtyRegion.GetWidth(), curDirtyRegion.GetHeight(), hasCompletateCache);
543     syncUifirstDirtyManager_->MergeDirtyRect(curDirtyRegion);
544     // set history dirty count
545     syncUifirstDirtyManager_->SetBufferAge(1); // 1 means buffer age
546     // update history dirty count
547     syncUifirstDirtyManager_->UpdateDirty(false);
548     return true;
549 }
550 
UpdateUifirstDirtyManager(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable)551 void RsSubThreadCache::UpdateUifirstDirtyManager(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable)
552 {
553     if (!(RSUifirstManager::Instance().GetUiFirstType() == UiFirstCcmType::MULTI &&
554         RSSystemProperties::GetUIFirstDirtyEnabled())) {
555         return;
556     }
557     if (!surfaceDrawable) {
558         RS_LOGE("UpdateUifirstDirtyManager surfaceDrawable is nullptr");
559         return;
560     }
561     auto surfaceParams = static_cast<RSSurfaceRenderParams*>(surfaceDrawable->GetRenderParams().get());
562     if (!surfaceParams) {
563         RS_LOGE("UpdateUifirstDirtyManager params is nullptr");
564         UpdateDirtyRecordCompletatedState(false);
565         return;
566     }
567     bool isCacheValid = IsCacheValid();
568     bool isLastFrameSkip = GetSurfaceSkipCount() > 0;
569     auto isRecordCompletate = UpdateCacheSurfaceDirtyManager(surfaceDrawable, isCacheValid, isLastFrameSkip);
570     // nested surfacenode uifirstDirtyManager update is required
571     for (const auto& nestedDrawable : surfaceDrawable->
572         GetDrawableVectorById(surfaceParams->GetAllSubSurfaceNodeIds())) {
573         auto surfaceNodeDrawable = std::static_pointer_cast<RSSurfaceRenderNodeDrawable>(nestedDrawable);
574         if (surfaceNodeDrawable) {
575             isRecordCompletate = isRecordCompletate && surfaceNodeDrawable->GetRsSubThreadCache()
576                 .UpdateCacheSurfaceDirtyManager(surfaceNodeDrawable.get(), isCacheValid, isLastFrameSkip);
577         }
578     }
579     UpdateDirtyRecordCompletatedState(isRecordCompletate);
580 }
581 
IsDirtyRecordCompletated()582 bool RsSubThreadCache::IsDirtyRecordCompletated()
583 {
584     bool isDirtyRecordCompletated = isDirtyRecordCompletated_;
585     isDirtyRecordCompletated_ = false;
586     return isDirtyRecordCompletated;
587 }
588 
UpdateDirtyRecordCompletatedState(bool isCompletate)589 void RsSubThreadCache::UpdateDirtyRecordCompletatedState(bool isCompletate)
590 {
591     isDirtyRecordCompletated_ = isCompletate;
592 }
593 
SetUifirstDirtyRegion(Drawing::Region dirtyRegion)594 void RsSubThreadCache::SetUifirstDirtyRegion(Drawing::Region dirtyRegion)
595 {
596     uifirstDirtyRegion_ = dirtyRegion;
597 }
598 
GetUifirstDirtyRegion() const599 Drawing::Region RsSubThreadCache::GetUifirstDirtyRegion() const
600 {
601     return uifirstDirtyRegion_;
602 }
603 
SetUifrstDirtyEnableFlag(bool dirtyEnableFlag)604 void RsSubThreadCache::SetUifrstDirtyEnableFlag(bool dirtyEnableFlag)
605 {
606     uifrstDirtyEnableFlag_ = dirtyEnableFlag;
607 }
608 
GetUifrstDirtyEnableFlag() const609 bool RsSubThreadCache::GetUifrstDirtyEnableFlag() const
610 {
611     return uifrstDirtyEnableFlag_;
612 }
613 
GetCurDirtyRegionWithMatrix(const Drawing::Matrix & matrix,Drawing::RectF & latestDirtyRect,Drawing::RectF & absDrawRect)614 bool RsSubThreadCache::GetCurDirtyRegionWithMatrix(const Drawing::Matrix& matrix,
615     Drawing::RectF& latestDirtyRect, Drawing::RectF& absDrawRect)
616 {
617     Drawing::Matrix inverseMatrix;
618     if (!matrix.Invert(inverseMatrix)) {
619         return false;
620     }
621     Drawing::RectF latestDirtyRectTemp = {0, 0, 0, 0};
622     Drawing::RectF absDrawRectTemp = {0, 0, 0, 0};
623     std::swap(latestDirtyRectTemp, latestDirtyRect);
624     std::swap(absDrawRectTemp, absDrawRect);
625     inverseMatrix.MapRect(latestDirtyRect, latestDirtyRectTemp);
626     inverseMatrix.MapRect(absDrawRect, absDrawRectTemp);
627     return true;
628 }
629 
CalculateUifirstDirtyRegion(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,Drawing::RectI & dirtyRect)630 bool RsSubThreadCache::CalculateUifirstDirtyRegion(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
631     Drawing::RectI& dirtyRect)
632 {
633     if (!surfaceDrawable) {
634         RS_LOGE("CalculateUifirstDirtyRegion surfaceDrawable is nullptr");
635         return false;
636     }
637     auto uifirstDirtyManager = GetSyncUifirstDirtyManager();
638     if (!uifirstDirtyManager) {
639         RS_LOGE("CalculateUifirstDirtyRegion uifirstDirtyManager is nullptr");
640         return false;
641     }
642     auto surfaceParams = static_cast<RSSurfaceRenderParams*>(surfaceDrawable->GetRenderParams().get());
643     if (!surfaceParams) {
644         RS_LOGE("CalculateUifirstDirtyRegion surfaceParams is nullptr");
645         return false;
646     }
647     RectI latestDirtyRect = uifirstDirtyManager->GetUiLatestHistoryDirtyRegions();
648     if (latestDirtyRect.IsEmpty()) {
649         dirtyRect = {};
650         return true;
651     }
652     auto absDrawRect = surfaceParams->GetAbsDrawRect();
653     if (absDrawRect.GetWidth() == 0 || absDrawRect.GetHeight() == 0 ||
654         !absDrawRect.IsInsideOf(surfaceParams->GetScreenRect())) {
655         RS_LOGD("absRect params is err or out of dispaly");
656         return false;
657     }
658     Drawing::RectF curDrityRegion = Drawing::RectF(latestDirtyRect.GetLeft(), latestDirtyRect.GetTop(),
659         latestDirtyRect.GetRight(), latestDirtyRect.GetBottom());
660     Drawing::RectF curAbsDrawRect = Drawing::RectF(absDrawRect.GetLeft(), absDrawRect.GetTop(),
661         absDrawRect.GetRight(), absDrawRect.GetBottom());
662     if (!GetCurDirtyRegionWithMatrix(surfaceParams->GetDirtyRegionMatrix(), curDrityRegion, curAbsDrawRect)) {
663         return false;
664     }
665     auto surfaceBounds = surfaceParams->GetBounds();
666     float widthScale = surfaceBounds.GetWidth() / curAbsDrawRect.GetWidth();
667     float heightScale = surfaceBounds.GetHeight() / curAbsDrawRect.GetHeight();
668     float left = (curDrityRegion.GetLeft() - curAbsDrawRect.GetLeft()) * widthScale;
669     float top = (curDrityRegion.GetTop() - curAbsDrawRect.GetTop()) * heightScale;
670     float width = curDrityRegion.GetWidth() * widthScale;
671     float height = curDrityRegion.GetHeight() * heightScale;
672     Drawing::RectF tempRect = Drawing::RectF(left, top, left + width, top + height);
673     dirtyRect = tempRect.RoundOut();
674     RS_TRACE_NAME_FMT("lR[%.1f %.1f %.1f %.1f], absR[%.1f %.1f %.1f %.1f], resultR[%d %d %d %d]",
675         curDrityRegion.GetLeft(), curDrityRegion.GetTop(), curDrityRegion.GetWidth(), curDrityRegion.GetHeight(),
676         curAbsDrawRect.GetLeft(), curAbsDrawRect.GetTop(), curAbsDrawRect.GetWidth(), curAbsDrawRect.GetHeight(),
677         dirtyRect.GetLeft(), dirtyRect.GetTop(), dirtyRect.GetWidth(), dirtyRect.GetHeight());
678     return true;
679 }
680 
MergeUifirstAllSurfaceDirtyRegion(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,Drawing::RectI & dirtyRects)681 bool RsSubThreadCache::MergeUifirstAllSurfaceDirtyRegion(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
682     Drawing::RectI& dirtyRects)
683 {
684     if (!(RSUifirstManager::Instance().GetUiFirstType() == UiFirstCcmType::MULTI &&
685         RSSystemProperties::GetUIFirstDirtyEnabled())) {
686         return false;
687     }
688     if (!surfaceDrawable) {
689         RS_LOGE("MergeUifirstAllSurfaceDirtyRegion surfaceDrawable is nullptr");
690         return false;
691     }
692     uifirstMergedDirtyRegion_ = {};
693     auto surfaceParams = static_cast<RSSurfaceRenderParams*>(surfaceDrawable->GetUifirstRenderParams().get());
694     if (!surfaceParams) {
695         RS_LOGE("CalculateUifirstDirtyRegion params is nullptr");
696         return false;
697     }
698     if (!surfaceParams->IsLeashWindow() || !IsDirtyRecordCompletated()) {
699         RS_LOGD("MergeUifirstAllSurfaceDirtyRegion not support");
700         return false;
701     }
702     Drawing::RectI tempRect = {};
703     bool isCalculateSucc = CalculateUifirstDirtyRegion(surfaceDrawable, tempRect);
704     uifirstMergedDirtyRegion_.SetRect(tempRect);
705     dirtyRects.Join(tempRect);
706     for (const auto& nestedDrawable : surfaceDrawable->
707         GetDrawableVectorById(surfaceParams->GetAllSubSurfaceNodeIds())) {
708         auto surfaceNodeDrawable = std::static_pointer_cast<RSSurfaceRenderNodeDrawable>(nestedDrawable);
709         if (surfaceNodeDrawable) {
710             tempRect = {};
711             isCalculateSucc = isCalculateSucc && surfaceNodeDrawable->GetRsSubThreadCache().
712                 CalculateUifirstDirtyRegion(surfaceNodeDrawable.get(), tempRect);
713             Drawing::Region resultRegion;
714             resultRegion.SetRect(tempRect);
715             uifirstMergedDirtyRegion_.Op(resultRegion, Drawing::RegionOp::UNION);
716             dirtyRects.Join(tempRect);
717         }
718     }
719     return isCalculateSucc;
720 }
721 
UpadteAllSurfaceUifirstDirtyEnableState(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,bool isEnableDirtyRegion)722 void RsSubThreadCache::UpadteAllSurfaceUifirstDirtyEnableState(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
723     bool isEnableDirtyRegion)
724 {
725     if (!(RSUifirstManager::Instance().GetUiFirstType() == UiFirstCcmType::MULTI &&
726         RSSystemProperties::GetUIFirstDirtyEnabled())) {
727         return;
728     }
729     if (!surfaceDrawable) {
730         RS_LOGE("UpadteAllSurfaceUifirstDirtyEnableState surfaceDrawable is nullptr");
731         return;
732     }
733     SetUifirstDirtyRegion(uifirstMergedDirtyRegion_);
734     SetUifrstDirtyEnableFlag(isEnableDirtyRegion);
735     auto surfaceParams = static_cast<RSSurfaceRenderParams*>(surfaceDrawable->GetUifirstRenderParams().get());
736     if (!surfaceParams) {
737         RS_LOGE("UpadteAllSurfaceUifirstDirtyState params is nullptr");
738         return;
739     }
740     for (const auto& nestedDrawable : surfaceDrawable->
741         GetDrawableVectorById(surfaceParams->GetAllSubSurfaceNodeIds())) {
742         auto surfaceNodeDrawable = std::static_pointer_cast<RSSurfaceRenderNodeDrawable>(nestedDrawable);
743         if (surfaceNodeDrawable) {
744             surfaceNodeDrawable->GetRsSubThreadCache().SetUifirstDirtyRegion(uifirstMergedDirtyRegion_);
745             surfaceNodeDrawable->GetRsSubThreadCache().SetUifrstDirtyEnableFlag(isEnableDirtyRegion);
746         }
747     }
748 }
749 
PushDirtyRegionToStack(RSPaintFilterCanvas & canvas,Drawing::Region & resultRegion)750 void RsSubThreadCache::PushDirtyRegionToStack(RSPaintFilterCanvas& canvas, Drawing::Region& resultRegion)
751 {
752     if (canvas.GetIsParallelCanvas()) {
753         if (GetUifrstDirtyEnableFlag()) {
754             auto uifirstDirtyRegion = GetUifirstDirtyRegion();
755             canvas.PushDirtyRegion(uifirstDirtyRegion);
756         }
757     } else {
758         canvas.PushDirtyRegion(resultRegion);
759     }
760 }
761 
UifirstDirtyRegionDfx(Drawing::Canvas & canvas,Drawing::RectI & surfaceDrawRect)762 void RsSubThreadCache::UifirstDirtyRegionDfx(Drawing::Canvas& canvas, Drawing::RectI& surfaceDrawRect)
763 {
764     if (!RSSystemProperties::GetUIFirstDirtyDebugEnabled()) {
765         return;
766     }
767     const int defaultTextOffsetX = 6; // text position is 6 pixelSize right side of the Rect
768     const int defaultTextOffsetY = 30; // text position has 30 pixelSize under the Rect
769     Drawing::Brush rectBrush;
770     rectBrush.SetColor(Drawing::Color(0x80FFB6C1));
771     rectBrush.SetAntiAlias(true);
772     rectBrush.SetAlphaF(0.4f); // alpha 0.4 by default
773     std::shared_ptr<Drawing::Typeface> typeFace = nullptr;
774     std::string position = "pos:[" + surfaceDrawRect.ToString() + "]";
775     // font size: 24
776     std::shared_ptr<Drawing::TextBlob> textBlob =
777         Drawing::TextBlob::MakeFromString(position.c_str(), Drawing::Font(typeFace, 24.0f, 0.6f, 0.0f));
778     canvas.AttachBrush(rectBrush);
779     canvas.DrawRect(surfaceDrawRect);
780     canvas.DetachBrush();
781     canvas.AttachBrush(Drawing::Brush());
782     canvas.DrawTextBlob(textBlob.get(),
783         surfaceDrawRect.GetLeft() + defaultTextOffsetX, surfaceDrawRect.GetTop() + defaultTextOffsetY);
784     canvas.DetachBrush();
785 }
786 
SubDraw(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,Drawing::Canvas & canvas)787 void RsSubThreadCache::SubDraw(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable, Drawing::Canvas& canvas)
788 {
789     if (!surfaceDrawable) {
790         RS_LOGE("SubDraw surfaceDrawable is nullptr");
791         return;
792     }
793     const auto& uifirstParams = surfaceDrawable->GetUifirstRenderParams();
794     auto debugSize = uifirstParams ? uifirstParams->GetCacheSize() : Vector2f(0.f, 0.f);
795     RS_TRACE_NAME_FMT("RsSubThreadCache::SubDraw[%s] %" PRIu64 ", w:%.1f h:%.1f, isHigh:%d",
796         surfaceDrawable->GetName().c_str(), surfaceDrawable->GetId(), debugSize.x_, debugSize.y_,
797         IsHighPostPriority());
798 
799     auto rscanvas = reinterpret_cast<RSPaintFilterCanvas*>(&canvas);
800     if (!rscanvas) {
801         RS_LOGE("SubDraw, rscanvas is nullptr");
802         return;
803     }
804     Drawing::Rect bounds = uifirstParams ? uifirstParams->GetBounds() : Drawing::Rect(0, 0, 0, 0);
805 
806     auto parentSurfaceMatrix = RSRenderParams::GetParentSurfaceMatrix();
807     RSRenderParams::SetParentSurfaceMatrix(IDENTITY_MATRIX);
808 
809     // merge uifirst dirty region
810     Drawing::RectI uifirstSurfaceDrawRects = {};
811     auto dirtyEnableFlag = MergeUifirstAllSurfaceDirtyRegion(surfaceDrawable, uifirstSurfaceDrawRects);
812     UpadteAllSurfaceUifirstDirtyEnableState(surfaceDrawable, dirtyEnableFlag);
813     if (!dirtyEnableFlag) {
814         rscanvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
815     } else {
816         rscanvas->ClipRegion(uifirstMergedDirtyRegion_);
817         rscanvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
818     }
819     {
820         RS_TRACE_NAME_FMT("uifirstDirtyMerged[%d %d %d %d], dirtyEnableFlag:%d",
821             uifirstSurfaceDrawRects.GetLeft(), uifirstSurfaceDrawRects.GetTop(),
822             uifirstSurfaceDrawRects.GetWidth(), uifirstSurfaceDrawRects.GetHeight(), dirtyEnableFlag);
823     }
824 
825     ClearTotalProcessedSurfaceCount();
826     RSRenderNodeDrawable::ClearProcessedNodeCount();
827     surfaceDrawable->DrawUifirstContentChildren(*rscanvas, bounds);
828     int totalNodes = RSRenderNodeDrawable::GetProcessedNodeCount();
829     int totalSurfaces = GetTotalProcessedSurfaceCount();
830     RS_TRACE_NAME_FMT("SubDraw totalSurfaces:%d totalNodes:%d", totalSurfaces, totalNodes);
831     if (totalSurfaces <= 0 || totalNodes <= 0) {
832         RS_LOGI("subDraw id:%{public}" PRIu64 ",name:%{public}s,totalSurfaces:%{public}d,totalNodes:%{public}d",
833             surfaceDrawable->GetId(), surfaceDrawable->name_.c_str(), totalSurfaces, totalNodes);
834     } else {
835         RS_LOGD("subDraw id:%{public}" PRIu64 ",name:%{public}s,totalSurfaces:%{public}d,totalNodes:%{public}d",
836             surfaceDrawable->GetId(), surfaceDrawable->name_.c_str(), totalSurfaces, totalNodes);
837     }
838     RSRenderParams::SetParentSurfaceMatrix(parentSurfaceMatrix);
839     // uifirst dirty dfx
840     UifirstDirtyRegionDfx(*rscanvas, uifirstSurfaceDrawRects);
841 }
842 
SetSubThreadSkip(bool isSubThreadSkip)843 void RsSubThreadCache::SetSubThreadSkip(bool isSubThreadSkip)
844 {
845     isSubThreadSkip_ = isSubThreadSkip;
846 }
847 
GetTotalProcessedSurfaceCount() const848 int RsSubThreadCache::GetTotalProcessedSurfaceCount() const
849 {
850     return totalProcessedSurfaceCount_;
851 }
852 
TotalProcessedSurfaceCountInc(RSPaintFilterCanvas & canvas)853 void RsSubThreadCache::TotalProcessedSurfaceCountInc(RSPaintFilterCanvas& canvas)
854 {
855     if (canvas.GetIsParallelCanvas()) {
856         ++totalProcessedSurfaceCount_;
857     }
858 }
859 
ClearTotalProcessedSurfaceCount()860 void RsSubThreadCache::ClearTotalProcessedSurfaceCount()
861 {
862     totalProcessedSurfaceCount_ = 0;
863 }
864 
ProcessSurfaceSkipCount()865 void RsSubThreadCache::ProcessSurfaceSkipCount()
866 {
867     isSurfaceSkipCount_++;
868 }
869 
ResetSurfaceSkipCount()870 void RsSubThreadCache::ResetSurfaceSkipCount()
871 {
872     isSurfaceSkipCount_ = 0;
873     isSurfaceSkipPriority_ = 0;
874 }
875 
GetSurfaceSkipCount() const876 int32_t RsSubThreadCache::GetSurfaceSkipCount() const
877 {
878     return isSurfaceSkipCount_;
879 }
880 
GetSurfaceSkipPriority()881 int32_t RsSubThreadCache::GetSurfaceSkipPriority()
882 {
883     return ++isSurfaceSkipPriority_;
884 }
885 
GetUifirstPostOrder() const886 uint32_t RsSubThreadCache::GetUifirstPostOrder() const
887 {
888     return uifirstPostOrder_;
889 }
890 
SetUifirstPostOrder(uint32_t order)891 void RsSubThreadCache::SetUifirstPostOrder(uint32_t order)
892 {
893     uifirstPostOrder_ = order;
894 }
895 
IsHighPostPriority()896 bool RsSubThreadCache::IsHighPostPriority()
897 {
898     return isHighPostPriority_;
899 }
900 
SetHighPostPriority(bool postPriority)901 void RsSubThreadCache::SetHighPostPriority(bool postPriority)
902 {
903     isHighPostPriority_ = postPriority;
904 }
905 
UpdateCacheSurfaceInfo(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)906 void RsSubThreadCache::UpdateCacheSurfaceInfo(std::shared_ptr<DrawableV2::RSSurfaceRenderNodeDrawable> nodeDrawable)
907 {
908     if (!nodeDrawable) {
909         return;
910     }
911     const auto& params = nodeDrawable->GetRenderParams();
912     if (params) {
913         cacheSurfaceInfo_.processedSurfaceCount = GetTotalProcessedSurfaceCount();
914         cacheSurfaceInfo_.processedNodeCount = RSRenderNodeDrawable::GetProcessedNodeCount();
915         cacheSurfaceInfo_.alpha = params->GetGlobalAlpha();
916     }
917 }
918 
DrawUIFirstCache(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,RSPaintFilterCanvas & rscanvas,bool canSkipWait)919 bool RsSubThreadCache::DrawUIFirstCache(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
920     RSPaintFilterCanvas& rscanvas, bool canSkipWait)
921 {
922     if (!surfaceDrawable) {
923         RS_LOGE("DrawUIFirstCache surfaceDrawable is nullptr");
924         return false;
925     }
926     RS_TRACE_NAME_FMT("DrawUIFirstCache_NOSTARTING");
927     const auto& params = surfaceDrawable->GetRenderParams();
928     if (!params) {
929         RS_LOGE("DrawUIFirstCache params is nullptr");
930         return false;
931     }
932 
933     static constexpr int REQUEST_SET_FRAME_LOAD_ID = 100006;
934     static constexpr int REQUEST_FRAME_AWARE_LOAD = 90;
935     static constexpr int REQUEST_FRAME_STANDARD_LOAD = 50;
936     if (!HasCachedTexture()) {
937         RS_TRACE_NAME_FMT("HandleSubThreadNode wait %d %" PRIu64 "", canSkipWait, surfaceDrawable->nodeId_);
938         if (canSkipWait) {
939             RS_LOGI("uifirst skip wait id:%{public}" PRIu64 ",name:%{public}s", surfaceDrawable->nodeId_,
940                 surfaceDrawable->name_.c_str());
941             return false; // draw nothing
942         }
943 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
944         bool frameParamEnable = RsFrameReport::GetInstance().GetEnable();
945         if (frameParamEnable) {
946             RsFrameReport::GetInstance().SetFrameParam(
947                 REQUEST_SET_FRAME_LOAD_ID, REQUEST_FRAME_AWARE_LOAD, 0, GetLastFrameUsedThreadIndex());
948         }
949         RSSubThreadManager::Instance()->WaitNodeTask(surfaceDrawable->nodeId_);
950         if (frameParamEnable) {
951             RsFrameReport::GetInstance().SetFrameParam(
952                 REQUEST_SET_FRAME_LOAD_ID, REQUEST_FRAME_STANDARD_LOAD, 0, GetLastFrameUsedThreadIndex());
953         }
954         UpdateCompletedCacheSurface();
955 #endif
956     }
957     return DrawCacheSurface(surfaceDrawable, rscanvas, params->GetCacheSize(), UNI_MAIN_THREAD_INDEX, true);
958 }
959 
DrawUIFirstCacheWithStarting(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,RSPaintFilterCanvas & rscanvas,NodeId startingWindowId)960 bool RsSubThreadCache::DrawUIFirstCacheWithStarting(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
961     RSPaintFilterCanvas& rscanvas, NodeId startingWindowId)
962 {
963     if (!surfaceDrawable) {
964         RS_LOGE("DrawUIFirstCacheWithStarting surfaceDrawable is nullptr");
965         return false;
966     }
967     bool hasCachedTexture = HasCachedTexture();
968     RS_TRACE_NAME_FMT("DrawUIFirstCacheWithStarting hasCache:%d, nodeId:%" PRIu64, hasCachedTexture, startingWindowId);
969     auto startingNodeDrawable = RSRenderNodeDrawableAdapter::GetDrawableById(startingWindowId);
970     if (UNLIKELY(!hasCachedTexture && !startingNodeDrawable)) {
971         RS_LOGI("DrawUIFirstCacheWithStarting with no cache and no starting window. id:%{public}" PRIu64,
972             surfaceDrawable->GetId());
973         // no cache and starting window, we should wait subthread
974         return DrawUIFirstCache(surfaceDrawable, rscanvas, false);
975     }
976     bool ret = true;
977     if (startingNodeDrawable) {
978         const auto& startingParams = startingNodeDrawable->GetRenderParams();
979         if (!hasCachedTexture && startingParams && !ROSEN_EQ(startingParams->GetAlpha(), 1.0f)) {
980             // no cache and starting window alpha is not 1.0, we should wait subthread
981             ret = DrawUIFirstCache(surfaceDrawable, rscanvas, false);
982             RS_TRACE_NAME_FMT("wait and drawStarting, GetAlpha:%f, GetGlobalAlpha:%f",
983                 startingParams->GetAlpha(), startingParams->GetGlobalAlpha());
984             startingNodeDrawable->Draw(rscanvas);
985             return ret;
986         }
987     }
988     const auto& params = surfaceDrawable->GetRenderParams();
989     if (!params) {
990         RS_LOGE("RSUniRenderUtil::HandleSubThreadNodeDrawable params is nullptr");
991         return false;
992     }
993     // draw surface content
994     if (hasCachedTexture) {
995         ret = DrawCacheSurface(surfaceDrawable, rscanvas, params->GetCacheSize(), UNI_MAIN_THREAD_INDEX, true);
996     }
997     // draw starting window
998     if (startingNodeDrawable) {
999         RS_TRACE_NAME_FMT("drawStarting");
1000         startingNodeDrawable->Draw(rscanvas);
1001     }
1002     return ret;
1003 }
1004 
DealWithUIFirstCache(DrawableV2::RSSurfaceRenderNodeDrawable * surfaceDrawable,RSPaintFilterCanvas & canvas,RSSurfaceRenderParams & surfaceParams,RSRenderThreadParams & uniParams)1005 bool RsSubThreadCache::DealWithUIFirstCache(DrawableV2::RSSurfaceRenderNodeDrawable* surfaceDrawable,
1006     RSPaintFilterCanvas& canvas, RSSurfaceRenderParams& surfaceParams, RSRenderThreadParams& uniParams)
1007 {
1008     if (!surfaceDrawable) {
1009         RS_LOGE("DealWithUIFirstCache surfaceDrawable is nullptr");
1010         return false;
1011     }
1012     if (drawWindowCache_.DealWithCachedWindow(surfaceDrawable, canvas, surfaceParams, uniParams)) {
1013         return true;
1014     }
1015     auto enableType = surfaceParams.GetUifirstNodeEnableParam();
1016     auto cacheState = GetCacheSurfaceProcessedStatus();
1017     if ((!RSUniRenderThread::GetCaptureParam().isSnapshot_ && enableType == MultiThreadCacheType::NONE &&
1018         // WAITING may change to DOING in subThread at any time
1019         cacheState != CacheProcessStatus::WAITING && cacheState != CacheProcessStatus::DOING) ||
1020         (RSUniRenderThread::GetCaptureParam().isSnapshot_ && !HasCachedTexture())) {
1021         return false;
1022     }
1023     if (RSUniRenderThread::GetCaptureParam().isSnapshot_) {
1024         RS_LOGI("%{public}s name:%{public}s surfaceCount:%{public}d nodeCount:%{public}d alpha:%{public}f",
1025             __func__, surfaceDrawable->GetName().c_str(), cacheCompletedSurfaceInfo_.processedSurfaceCount,
1026             cacheCompletedSurfaceInfo_.processedNodeCount, cacheCompletedSurfaceInfo_.alpha);
1027     }
1028     RS_TRACE_NAME_FMT("DrawUIFirstCache [%s] %" PRIu64 ", type %d, cacheState:%d",
1029         surfaceParams.GetName().c_str(), surfaceParams.GetId(), enableType, cacheState);
1030     Drawing::Rect bounds = surfaceParams.GetBounds();
1031     RSAutoCanvasRestore acr(&canvas);
1032     // Alpha and matrix have been applied in func CaptureSurface
1033     if (!RSUniRenderThread::GetCaptureParam().isSnapshot_ && !RSUniRenderThread::GetCaptureParam().isMirror_) {
1034         canvas.MultiplyAlpha(surfaceParams.GetAlpha());
1035         canvas.ConcatMatrix(surfaceParams.GetMatrix());
1036     }
1037     // This branch is entered only when the conditions for executing the DrawUIFirstCache function are met.
1038     if (surfaceParams.GetGlobalPositionEnabled() &&
1039         surfaceParams.GetUifirstUseStarting() == INVALID_NODEID) {
1040         auto matrix = surfaceParams.GetMatrix();
1041         Drawing::Matrix inverseMatrix;
1042         if (!matrix.Invert(inverseMatrix)) {
1043             RS_LOGW("%{public}s name: %{public}s matrix invert inverseMatrix Failed", __func__,
1044                     surfaceParams.GetName().c_str());
1045         }
1046         canvas.ConcatMatrix(inverseMatrix);
1047         canvas.Translate(-surfaceDrawable->offsetX_, -surfaceDrawable->offsetY_);
1048         canvas.ConcatMatrix(matrix);
1049         RS_LOGD("DealWithUIFirstCache Translate screenId=[%{public}" PRIu64 "] "
1050             "offsetX=%{public}d offsetY=%{public}d", surfaceDrawable->curDisplayScreenId_, surfaceDrawable->offsetX_,
1051             surfaceDrawable->offsetY_);
1052     }
1053 
1054     auto stencilVal = surfaceParams.GetStencilVal();
1055     if (surfaceParams.IsLeashWindow()) {
1056         surfaceDrawable->DrawLeashWindowBackground(canvas, bounds,
1057             uniParams.IsStencilPixelOcclusionCullingEnabled(), stencilVal);
1058     } else {
1059         surfaceDrawable->DrawBackground(canvas, bounds);
1060     }
1061     canvas.SetStencilVal(stencilVal);
1062     bool drawCacheSuccess = true;
1063     if (surfaceParams.GetUifirstUseStarting() != INVALID_NODEID) {
1064         drawCacheSuccess = DrawUIFirstCacheWithStarting(surfaceDrawable, canvas, surfaceParams.GetUifirstUseStarting());
1065     } else {
1066         drawCacheSuccess = DrawUIFirstCache(surfaceDrawable, canvas, false);
1067     }
1068     canvas.SetStencilVal(Drawing::Canvas::INVALID_STENCIL_VAL);
1069     if (!drawCacheSuccess) {
1070         surfaceDrawable->SetDrawSkipType(DrawSkipType::UI_FIRST_CACHE_FAIL);
1071         RS_TRACE_NAME_FMT("[%s] reuse failed!", surfaceParams.GetName().c_str());
1072         RS_LOGI("uifirst %{public}s drawcache failed! id:%{public}" PRIu64, surfaceDrawable->name_.c_str(),
1073             surfaceDrawable->nodeId_);
1074     }
1075     surfaceDrawable->DrawForeground(canvas, bounds);
1076     surfaceDrawable->DrawWatermark(canvas, surfaceParams);
1077     if (uniParams.GetUIFirstDebugEnabled()) {
1078         DrawUIFirstDfx(canvas, enableType, surfaceParams, drawCacheSuccess);
1079     }
1080     return true;
1081 }
1082 
DrawUIFirstDfx(RSPaintFilterCanvas & canvas,MultiThreadCacheType enableType,RSSurfaceRenderParams & surfaceParams,bool drawCacheSuccess)1083 void RsSubThreadCache::DrawUIFirstDfx(RSPaintFilterCanvas& canvas, MultiThreadCacheType enableType,
1084     RSSurfaceRenderParams& surfaceParams, bool drawCacheSuccess)
1085 {
1086     auto sizeDebug = surfaceParams.GetCacheSize();
1087     Drawing::Brush rectBrush;
1088     if (drawCacheSuccess) {
1089         if (enableType == MultiThreadCacheType::ARKTS_CARD) {
1090             // rgba: Alpha 128, blue 128
1091             rectBrush.SetColor(Drawing::Color(0, 0, 128, 128));
1092         } else {
1093             // rgba: Alpha 128, green 128, blue 128
1094             rectBrush.SetColor(Drawing::Color(0, 128, 128, 128));
1095         }
1096     } else {
1097         // rgba: Alpha 128, red 128
1098         rectBrush.SetColor(Drawing::Color(128, 0, 0, 128));
1099     }
1100     canvas.AttachBrush(rectBrush);
1101     canvas.DrawRect(Drawing::Rect(0, 0, sizeDebug.x_, sizeDebug.y_));
1102     canvas.DetachBrush();
1103 }
1104 
SetCacheBehindWindowData(const std::shared_ptr<RSPaintFilterCanvas::CacheBehindWindowData> & data)1105 void RsSubThreadCache::SetCacheBehindWindowData(const std::shared_ptr<RSPaintFilterCanvas::CacheBehindWindowData>& data)
1106 {
1107     cacheBehindWindowData_ = data;
1108 }
1109 
SetCacheCompletedBehindWindowData(const std::shared_ptr<RSPaintFilterCanvas::CacheBehindWindowData> & data)1110 void RsSubThreadCache::SetCacheCompletedBehindWindowData(
1111     const std::shared_ptr<RSPaintFilterCanvas::CacheBehindWindowData>& data)
1112 {
1113     cacheCompletedBehindWindowData_ = data;
1114 }
1115 
ResetCacheBehindWindowData()1116 void RsSubThreadCache::ResetCacheBehindWindowData()
1117 {
1118     cacheBehindWindowData_.reset();
1119 }
1120 
ResetCacheCompletedBehindWindowData()1121 void RsSubThreadCache::ResetCacheCompletedBehindWindowData()
1122 {
1123     cacheCompletedBehindWindowData_.reset();
1124 }
1125 
DrawBehindWindowBeforeCache(RSPaintFilterCanvas & canvas,const Drawing::scalar px,const Drawing::scalar py)1126 void RsSubThreadCache::DrawBehindWindowBeforeCache(RSPaintFilterCanvas& canvas,
1127     const Drawing::scalar px, const Drawing::scalar py)
1128 {
1129     if (!cacheCompletedBehindWindowData_) {
1130         RS_LOGD("DrawBehindWindowBeforeCache no need to draw");
1131         return;
1132     }
1133     if (!cacheCompletedBehindWindowData_->filter_ || !cacheCompletedBehindWindowData_->rect_.IsValid()) {
1134         RS_LOGE("DrawBehindWindowBeforeCache data is not valid");
1135         return;
1136     }
1137     auto surface = canvas.GetSurface();
1138     if (!surface) {
1139         RS_LOGE("DrawBehindWindowBeforeCache surface is nullptr");
1140         return;
1141     }
1142     RSAutoCanvasRestore acr(&canvas, RSPaintFilterCanvas::SaveType::kCanvasAndAlpha);
1143     canvas.Translate(px, py);
1144     Drawing::Rect absRect;
1145     canvas.GetTotalMatrix().MapRect(absRect, cacheCompletedBehindWindowData_->rect_);
1146     Drawing::RectI imageRect(std::ceil(absRect.GetLeft()), std::ceil(absRect.GetTop()), std::ceil(absRect.GetRight()),
1147         std::ceil(absRect.GetBottom()));
1148     auto deviceRect = Drawing::RectI(0, 0, surface->Width(), surface->Height());
1149     imageRect.Intersect(deviceRect);
1150     auto filter = std::static_pointer_cast<RSDrawingFilter>(cacheCompletedBehindWindowData_->filter_);
1151     auto imageSnapshot = surface->GetImageSnapshot(imageRect);
1152     if (!imageSnapshot) {
1153         RS_LOGE("DrawBehindWindowBeforeCache imageSnapshot is nullptr");
1154         return;
1155     }
1156     filter->PreProcess(imageSnapshot);
1157     Drawing::Rect srcRect = Drawing::Rect(0, 0, imageSnapshot->GetWidth(), imageSnapshot->GetHeight());
1158     Drawing::Rect dstRect = imageRect;
1159     canvas.ResetMatrix();
1160     filter->DrawImageRect(canvas, imageSnapshot, srcRect, dstRect);
1161     filter->PostProcess(canvas);
1162     RS_TRACE_NAME_FMT("RsSubThreadCache::DrawBehindWindowBeforeCache imageRect:%s", imageRect.ToString().c_str());
1163 }
1164 } // namespace OHOS::Rosen
1165