• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-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 "common/rs_background_thread.h"
17 #include "pipeline/render_thread/rs_uni_render_processor.h"
18 #include "pipeline/render_thread/rs_uni_render_util.h"
19 #include "pipeline/sk_resource_manager.h"
20 #include "rs_magic_pointer_render_manager.h"
21 #include "rs_trace.h"
22 #ifdef USE_M133_SKIA
23 #include "src/gpu/ganesh/gl/GrGLDefines.h"
24 #else
25 #include "src/gpu/gl/GrGLDefines.h"
26 #endif
27 
28 namespace OHOS {
29 namespace Rosen {
30 namespace {
31 static const std::string DISPLAY = "DisplayNode";
32 static const std::string POINTER = "pointer";
33 static const float RGB = 255.0f;
34 static const float HALF = 0.5f;
35 static const float MIN_BUFFER_NUMBER = 0.0f;
36 static const float MAX_BUFFER_NUMBER = 1.0f;
37 static const int64_t MAX_INTERVAL_TIME = 1000;
38 static const int32_t MAX_RANGE_SIZE = 100;
39 static const int32_t CALCULATE_MIDDLE = 2;
40 } // namespace
41 static std::unique_ptr<RSMagicPointerRenderManager> g_pointerRenderManagerInstance =
42     std::make_unique<RSMagicPointerRenderManager>();
43 
GetInstance()44 RSMagicPointerRenderManager& RSMagicPointerRenderManager::GetInstance()
45 {
46     return *g_pointerRenderManagerInstance;
47 }
48 
49 #if defined (RS_ENABLE_GL) && defined (RS_ENABLE_EGLIMAGE) || defined (RS_ENABLE_VK)
InitInstance(const std::shared_ptr<RSImageManager> & imageManager)50 void RSMagicPointerRenderManager::InitInstance(const std::shared_ptr<RSImageManager>& imageManager)
51 {
52     g_pointerRenderManagerInstance->imageManager_ = imageManager;
53 }
54 #endif
55 
GetCurrentTime()56 int64_t RSMagicPointerRenderManager::GetCurrentTime()
57 {
58     auto timeNow = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now());
59     return std::chrono::duration_cast<std::chrono::milliseconds>(timeNow.time_since_epoch()).count();
60 }
61 
SetPointerColorInversionConfig(float darkBuffer,float brightBuffer,int64_t interval,int32_t rangeSize)62 void RSMagicPointerRenderManager::SetPointerColorInversionConfig(float darkBuffer, float brightBuffer,
63     int64_t interval, int32_t rangeSize)
64 {
65     std::lock_guard<std::mutex> locker(mtx_);
66     if (darkBuffer > MIN_BUFFER_NUMBER && darkBuffer < MAX_BUFFER_NUMBER) {
67         darkBuffer_ = darkBuffer;
68     }
69     if (brightBuffer > MIN_BUFFER_NUMBER && brightBuffer < MAX_BUFFER_NUMBER) {
70         brightBuffer_ = brightBuffer;
71     }
72     if (interval > 0 && interval < MAX_INTERVAL_TIME) {
73         colorSamplingInterval_ = interval;
74     }
75     if (rangeSize > 0 && rangeSize < MAX_RANGE_SIZE) {
76         rangeSize_ = rangeSize;
77     }
78 }
79 
SetPointerColorInversionEnabled(bool enable)80 void RSMagicPointerRenderManager::SetPointerColorInversionEnabled(bool enable)
81 {
82     std::lock_guard<std::mutex> locker(mtx_);
83     isEnableCursorInversion_ = enable;
84 }
85 
GetPointerColorInversionEnabled()86 bool RSMagicPointerRenderManager::GetPointerColorInversionEnabled()
87 {
88     std::lock_guard<std::mutex> locker(mtx_);
89     return isEnableCursorInversion_;
90 }
91 
RegisterPointerLuminanceChangeCallback(pid_t pid,sptr<RSIPointerLuminanceChangeCallback> callback)92 void RSMagicPointerRenderManager::RegisterPointerLuminanceChangeCallback(pid_t pid,
93     sptr<RSIPointerLuminanceChangeCallback> callback)
94 {
95     std::lock_guard<std::mutex> locker(mtx_);
96     colorChangeListeners_[pid] = callback;
97 }
98 
UnRegisterPointerLuminanceChangeCallback(pid_t pid)99 void RSMagicPointerRenderManager::UnRegisterPointerLuminanceChangeCallback(pid_t pid)
100 {
101     std::lock_guard<std::mutex> locker(mtx_);
102     colorChangeListeners_.erase(pid);
103 }
104 
ExecutePointerLuminanceChangeCallback(int32_t brightness)105 void RSMagicPointerRenderManager::ExecutePointerLuminanceChangeCallback(int32_t brightness)
106 {
107     for (auto it = colorChangeListeners_.begin(); it != colorChangeListeners_.end(); it++) {
108         if (it->second) {
109             it->second->OnPointerLuminanceChanged(brightness);
110         }
111     }
112 }
113 
CallPointerLuminanceChange(int32_t brightness)114 void RSMagicPointerRenderManager::CallPointerLuminanceChange(int32_t brightness)
115 {
116     RS_LOGD("RSMagicPointerRenderManager::CallPointerLuminanceChange brightness:%{public}d.", brightness);
117     lastColorPickerTime_ = RSMagicPointerRenderManager::GetCurrentTime();
118     if (brightnessMode_ == CursorBrightness::NONE) {
119         brightnessMode_ = brightness < static_cast<int32_t>(RGB * HALF) ?
120             CursorBrightness::DARK : CursorBrightness::BRIGHT;
121         ExecutePointerLuminanceChangeCallback(brightness);
122     } else if (brightnessMode_ == CursorBrightness::DARK) {
123         // Dark cursor to light cursor buffer
124         if (brightness > static_cast<int32_t>(RGB * darkBuffer_)) {
125             brightnessMode_ = CursorBrightness::BRIGHT;
126             ExecutePointerLuminanceChangeCallback(brightness);
127         }
128     } else {
129         // light cursor to Dark cursor buffer
130         if (brightness < static_cast<int32_t>(RGB * brightBuffer_)) {
131             brightnessMode_ = CursorBrightness::DARK;
132             ExecutePointerLuminanceChangeCallback(brightness);
133         }
134     }
135 }
136 
CheckColorPickerEnabled()137 bool RSMagicPointerRenderManager::CheckColorPickerEnabled()
138 {
139     if (!isEnableCursorInversion_ || taskDoing_) {
140         return false;
141     }
142 
143     auto time = RSMagicPointerRenderManager::GetCurrentTime() - lastColorPickerTime_;
144     if (time < colorSamplingInterval_) {
145         return false;
146     }
147 
148     bool exists = false;
149     auto& threadParams = RSUniRenderThread::Instance().GetRSRenderThreadParams();
150     if (threadParams == nullptr) {
151         ROSEN_LOGE("RSMagicPointerRenderManager::CheckColorPickerEnabled threadParams == nullptr");
152         return false;
153     }
154     const auto& hardwareDrawables = threadParams->GetHardwareEnabledTypeDrawables();
155 
156     for (const auto& [_, __, drawable] : hardwareDrawables) {
157         if (drawable == nullptr) {
158             continue;
159         }
160         auto surfaceDrawable = std::static_pointer_cast<DrawableV2::RSSurfaceRenderNodeDrawable>(drawable);
161         if (surfaceDrawable != nullptr && surfaceDrawable->IsHardwareEnabledTopSurface()) {
162             exists = true;
163             break;
164         }
165     }
166 
167     return exists;
168 }
169 
ProcessColorPicker(std::shared_ptr<RSProcessor> processor,std::shared_ptr<Drawing::GPUContext> gpuContext)170 void RSMagicPointerRenderManager::ProcessColorPicker(std::shared_ptr<RSProcessor> processor,
171     std::shared_ptr<Drawing::GPUContext> gpuContext)
172 {
173     if (!CheckColorPickerEnabled()) {
174         ROSEN_LOGD("RSMagicPointerRenderManager::CheckColorPickerEnabled is false!");
175         return;
176     }
177 
178     RS_TRACE_BEGIN("RSMagicPointerRenderManager ProcessColorPicker");
179     std::lock_guard<std::mutex> locker(mtx_);
180 
181     if (cacheImgForPointer_) {
182         if (!GetIntersectImageBySubset(gpuContext)) {
183             ROSEN_LOGE("RSMagicPointerRenderManager::GetIntersectImageBySubset is false!");
184             return;
185         }
186     } else {
187         if (!CalculateTargetLayer(processor)) { // get the layer intersect with pointer and calculate the rect
188             ROSEN_LOGD("RSMagicPointerRenderManager::CalculateTargetLayer is false!");
189             return;
190         }
191     }
192 
193     // post color picker task to background thread
194     RunColorPickerTask();
195     RS_TRACE_END();
196 }
197 
GetIntersectImageBySubset(std::shared_ptr<Drawing::GPUContext> gpuContext)198 bool RSMagicPointerRenderManager::GetIntersectImageBySubset(std::shared_ptr<Drawing::GPUContext> gpuContext)
199 {
200     if (gpuContext == nullptr) {
201         return false;
202     }
203     const auto& hardwareDrawables =
204         RSUniRenderThread::Instance().GetRSRenderThreadParams()->GetHardwareEnabledTypeDrawables();
205     for (const auto& [_, __, drawable] : hardwareDrawables) {
206         auto surfaceDrawable = std::static_pointer_cast<DrawableV2::RSSurfaceRenderNodeDrawable>(drawable);
207         if (surfaceDrawable == nullptr || !surfaceDrawable->IsHardwareEnabledTopSurface()) {
208             continue;
209         }
210         auto& surfaceParams = surfaceDrawable->GetRenderParams();
211         if (!surfaceParams) {
212             continue;
213         }
214         image_ = std::make_shared<Drawing::Image>();
215         RectI pointerRect = surfaceParams->GetAbsDrawRect();
216         CalculateColorRange(pointerRect);
217         Drawing::RectI drawingPointerRect = Drawing::RectI(pointerRect.GetLeft(), pointerRect.GetTop(),
218             pointerRect.GetRight(), pointerRect.GetBottom());
219         image_->BuildSubset(cacheImgForPointer_, drawingPointerRect, *gpuContext);
220 
221         Drawing::TextureOrigin origin = Drawing::TextureOrigin::BOTTOM_LEFT;
222         backendTexture_ = image_->GetBackendTexture(false, &origin);
223         bitmapFormat_ = Drawing::BitmapFormat{ image_->GetColorType(), image_->GetAlphaType() };
224         return true;
225     }
226     return false;
227 }
228 
CalculateTargetLayer(std::shared_ptr<RSProcessor> processor)229 bool RSMagicPointerRenderManager::CalculateTargetLayer(std::shared_ptr<RSProcessor> processor)
230 {
231 #ifdef RS_ENABLE_GPU
232     auto uniRenderProcessor = std::static_pointer_cast<RSUniRenderProcessor>(processor);
233     if (uniRenderProcessor == nullptr) {
234         ROSEN_LOGE("RSMagicPointerRenderManager::CalculateTargetLayer uniRenderProcessor is null!");
235         return false;
236     }
237     std::vector<LayerInfoPtr> layers = uniRenderProcessor->GetLayers();
238     forceCPU_ = RSBaseRenderEngine::NeedForceCPU(layers);
239 
240     std::sort(layers.begin(), layers.end(), [](LayerInfoPtr a, LayerInfoPtr b) {
241         return a->GetZorder() < b->GetZorder();
242     });
243     // get pointer and display node layer
244     bool find = false;
245     RectI pRect;
246     int displayNodeIndex = INT_MAX;
247     for (int i = 0; i < static_cast<int>(layers.size()); ++i) {
248         std::string name = layers[i]->GetSurface()->GetName();
249         if (name.find(DISPLAY) != std::string::npos) {
250             displayNodeIndex = i;
251             continue;
252         }
253         if (name.find(POINTER) != std::string::npos) {
254             GraphicIRect rect = layers[i]->GetLayerSize();
255             pRect.SetAll(rect.x, rect.y, rect.w, rect.h);
256             find = true;
257             continue;
258         }
259     }
260 
261     if (!find || displayNodeIndex == INT_MAX) {
262         ROSEN_LOGD("RSMagicPointerRenderManager::CalculateTargetLayer cannot find pointer or display node.");
263         return false;
264     }
265     CalculateColorRange(pRect);
266     // calculate the max intersection layer and rect
267     GetRectAndTargetLayer(layers, pRect, displayNodeIndex);
268 #endif
269     return true;
270 }
271 
CalculateColorRange(RectI & pRect)272 void RSMagicPointerRenderManager::CalculateColorRange(RectI& pRect)
273 {
274     if (rangeSize_ > 0 && rangeSize_ < pRect.GetWidth() && rangeSize_ < pRect.GetHeight()) {
275         int left = pRect.GetLeft() + (pRect.GetWidth() - rangeSize_) / CALCULATE_MIDDLE;
276         int top = pRect.GetTop() + (pRect.GetHeight() - rangeSize_) / CALCULATE_MIDDLE;
277         pRect.SetAll(left, top, rangeSize_, rangeSize_);
278     }
279 }
280 
GetRectAndTargetLayer(std::vector<LayerInfoPtr> & layers,RectI & pRect,int displayNodeIndex)281 void RSMagicPointerRenderManager::GetRectAndTargetLayer(std::vector<LayerInfoPtr>& layers, RectI& pRect,
282     int displayNodeIndex)
283 {
284     target_ = nullptr;
285     rect_.Clear();
286 
287     for (int i = std::max(0, displayNodeIndex - 1); i >= 0; --i) {
288         if (layers[i]->GetSurface()->GetName().find(POINTER) != std::string::npos) {
289             continue;
290         }
291         GraphicIRect layerSize = layers[i]->GetLayerSize();
292         RectI curRect = RectI(layerSize.x, layerSize.y, layerSize.w, layerSize.h);
293         if (!curRect.Intersect(pRect)) {
294             continue;
295         }
296         RectI dstRect = curRect.IntersectRect(pRect);
297         if (dstRect.width_ * dstRect.height_ >= rect_.width_ * rect_.height_) {
298             rect_ = dstRect;
299             target_ = layers[i];
300         }
301     }
302 
303     // if not intersect with other layers, calculate the displayNode intersection rect
304     if (target_ == nullptr) {
305         target_ = layers[displayNodeIndex];
306         GraphicIRect layerSize = target_->GetLayerSize();
307         RectI curRect = RectI(layerSize.x, layerSize.y, layerSize.w, layerSize.h);
308         RectI dstRect = curRect.IntersectRect(pRect);
309     }
310 }
311 
CalcAverageLuminance(std::shared_ptr<Drawing::Image> image)312 int16_t RSMagicPointerRenderManager::CalcAverageLuminance(std::shared_ptr<Drawing::Image> image)
313 {
314     // create a 1x1 SkPixmap
315     uint32_t pixel[1] = { 0 };
316     Drawing::ImageInfo single_pixel_info(1, 1, Drawing::ColorType::COLORTYPE_RGBA_8888,
317         Drawing::AlphaType::ALPHATYPE_PREMUL);
318     Drawing::Bitmap single_pixel;
319     single_pixel.Build(single_pixel_info, single_pixel_info.GetBytesPerPixel());
320     single_pixel.SetPixels(pixel);
321 
322     // resize image to 1x1 to calculate average color
323     // kMedium_SkFilterQuality will do bilerp + mipmaps for down-scaling, we can easily get average color
324     image->ScalePixels(single_pixel,
325         Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::LINEAR));
326     // convert color format and return average luminance
327     auto color = SkColor4f::FromBytes_RGBA(pixel[0]).toSkColor();
328     return Drawing::Color::ColorQuadGetR(color) * 0.2126f + Drawing::Color::ColorQuadGetG(color) * 0.7152f +
329         Drawing::Color::ColorQuadGetB(color) * 0.0722f;
330 }
331 
RunColorPickerTaskBackground(BufferDrawParam & param)332 void RSMagicPointerRenderManager::RunColorPickerTaskBackground(BufferDrawParam& param)
333 {
334 #ifdef RS_ENABLE_UNI_RENDER
335     std::lock_guard<std::mutex> locker(mtx_);
336     std::shared_ptr<Drawing::Image> image;
337     auto context = RSBackgroundThread::Instance().GetShareGPUContext().get();
338     if (backendTexturePre_.IsValid()) {
339         image = std::make_shared<Drawing::Image>();
340         SharedTextureContext* sharedContext = new SharedTextureContext(imagePre_);
341         bool ret = image->BuildFromTexture(*context, backendTexturePre_.GetTextureInfo(),
342             Drawing::TextureOrigin::BOTTOM_LEFT, bitmapFormat_, nullptr,
343             SKResourceManager::DeleteSharedTextureContext, sharedContext);
344         if (!ret) {
345             RS_LOGE("RSMagicPointerRenderManager::RunColorPickerTaskBackground BuildFromTexture failed.");
346             return;
347         }
348     } else {
349         image = GetIntersectImageByLayer(param);
350     }
351     if (image == nullptr || !image->IsValid(context)) {
352         RS_LOGE("RSMagicPointerRenderManager::RunColorPickerTaskBackground image not valid.");
353         return;
354     }
355 
356     luminance_ = CalcAverageLuminance(image);
357 
358     CallPointerLuminanceChange(luminance_);
359 #endif
360 }
361 
RunColorPickerTask()362 void RSMagicPointerRenderManager::RunColorPickerTask()
363 {
364     if (!imagePre_ && (target_ == nullptr || rect_.IsEmpty())) {
365         ROSEN_LOGE("RSMagicPointerRenderManager::RunColorPickerTask failed for null target or rect is empty!");
366         return;
367     }
368 
369     BufferDrawParam param;
370     if (!imagePre_) {
371         param = RSUniRenderUtil::CreateLayerBufferDrawParam(target_, forceCPU_);
372     }
373     RSBackgroundThread::Instance().PostTask([this, param] () mutable {
374         taskDoing_ = true;
375         this->RunColorPickerTaskBackground(param);
376         backendTexturePre_ = backendTexture_;
377         backendTexture_ = Drawing::BackendTexture(false);
378         imagePre_ = image_;
379         image_ = nullptr;
380         taskDoing_ = false;
381     });
382 }
383 
GetIntersectImageByLayer(BufferDrawParam & param)384 std::shared_ptr<Drawing::Image> RSMagicPointerRenderManager::GetIntersectImageByLayer(BufferDrawParam& param)
385 {
386 #ifdef RS_ENABLE_UNI_RENDER
387     auto screenManager = CreateOrGetScreenManager();
388     if (screenManager == nullptr) {
389         RS_LOGE("RSPointerRenderManager::GetIntersectImageByLayer screenManager is null.");
390         return nullptr;
391     }
392     auto screenInfo = screenManager->QueryScreenInfo(param.screenId);
393     param.matrix.PostScale(screenInfo.GetRogWidthRatio(), screenInfo.GetRogHeightRatio());
394 
395     Drawing::Matrix mat;
396     bool flag = param.matrix.Invert(mat);
397     if (!flag) {
398         RS_LOGE("RSPointerRenderManager::GetIntersectImageByLayer param.matrix not invert.");
399         return nullptr;
400     }
401     Drawing::Rect rectOrigin = Drawing::Rect(rect_.GetLeft(), rect_.GetTop(), rect_.GetRight(), rect_.GetBottom());
402     Drawing::Rect imgCutRectF;
403     mat.MapRect(imgCutRectF, rectOrigin);
404     Drawing::RectI imgCutRect = Drawing::RectI(imgCutRectF.GetLeft(), imgCutRectF.GetTop(), imgCutRectF.GetRight(),
405         imgCutRectF.GetBottom());
406     const auto context = RSBackgroundThread::Instance().GetShareGPUContext();
407     if (context == nullptr) {
408         RS_LOGE("RSMagicPointerRenderManager::GetIntersectImageByLayer context is nullptr.");
409         return nullptr;
410     }
411     if (param.buffer == nullptr) {
412         ROSEN_LOGE("RSMagicPointerRenderManager::GetIntersectImageByLayer param buffer is nullptr");
413         return nullptr;
414     }
415 #if (defined(RS_ENABLE_GL) && defined(RS_ENABLE_EGLIMAGE)) || defined(RS_ENABLE_VK)
416     return imageManager_->GetIntersectImage(imgCutRect, context,
417         param.buffer, param.acquireFence, param.threadIndex);
418 #endif
419 #endif
420     return nullptr;
421 }
422 } // namespace Rosen
423 } // namespace OHOS