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