• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "native_render.h"
16 #include <common/common.h>
17 #include <algorithm>
18 #include <cmath>
19 #include <native_image/native_image.h>
20 #include <poll.h>
21 #include <unistd.h>
22 #include <cerrno>
23 #include <cstdint>
24 #include <hilog/log.h>
25 
26 namespace {
27     // 动画相关
28     constexpr double ANIMATION_SPEED_INCREMENT = 0.6;   // 动画速度增量
29 
30     // 文件描述符和轮询相关
31     constexpr int INVALID_FD = -1;                      // 无效的文件描述符
32     constexpr uint32_t POLL_TIMEOUT_MS = 3000;          // poll 超时时间(毫秒)
33     constexpr nfds_t NUM_POLL_FDS = 1;                  // poll 的文件描述符数量
34     constexpr int NO_FENCE = -1;                        // 无同步栅栏
35     constexpr int MAX_RETRY = 3;                        // 最大重试次数
36 
37     // 返回状态码
38     constexpr int SUCCESS = 0;                          // 成功返回码
39     constexpr int FAILURE = -1;                         // 失败返回码
40 
41     // 颜色和像素相关
42     constexpr uint8_t MAX_COLOR_VALUE = 255;            // 颜色分量的最大值
43     constexpr int32_t BYTES_PER_PIXEL = 4;              // 每个像素的字节数
44 
45     // 颜色通道位移
46     constexpr uint8_t ALPHA_SHIFT = 24;                 // Alpha 通道位移
47     constexpr uint8_t RED_SHIFT = 16;                   // Red 通道位移
48     constexpr uint8_t GREEN_SHIFT = 8;                  // Green 通道位移
49     constexpr uint8_t BLUE_SHIFT = 0;                   // Blue 通道位移
50 
51     // 强度相关
52     constexpr double MAX_INTENSITY = 1.0;               // 最大强度值
53     constexpr double MIN_INTENSITY = 0.5;               // 最小强度值
54     constexpr double INTENSITY_MULTIPLIER = 2.0;        // 强度乘数
55     constexpr double INTENSITY_LIMIT = 1.0;             // 强度限制
56 
57     // 箭头绘制相关
58     constexpr int ARROW_SIZE_DIVISOR = 2;               // 箭头大小的除数
59     constexpr int STEM_WIDTH_DIVISOR = 6;               // 箭头柄宽度的除数
60     constexpr int HEAD_WIDTH_DIVISOR = 2;               // 箭头头部宽度的除数
61     constexpr int HEAD_LENGTH_DIVISOR = 3;              // 箭头头部长度的除数
62     constexpr double HEAD_SLOPE_MULTIPLIER = 0.5;       // 箭头头部斜率的乘数
63 }
64 
~OHNativeRender()65 OHNativeRender::~OHNativeRender()
66 {
67     if (nativeWindow_ != nullptr) {
68         (void)OH_NativeWindow_NativeObjectUnreference(nativeWindow_);
69         nativeWindow_ = nullptr;
70     }
71 }
72 
SetSurfaceWidthAndHeight(OH_NativeImage * image,uint64_t surfaceId,uint64_t width,uint64_t height)73 bool OHNativeRender::SetSurfaceWidthAndHeight(OH_NativeImage* image, uint64_t surfaceId, uint64_t width, uint64_t height)
74 {
75     if (nativeWindow_ != nullptr) {
76         (void)OH_NativeWindow_NativeObjectUnreference(nativeWindow_);
77         nativeWindow_ = nullptr;
78     }
79 
80     // 保存宽度和高度
81     width_ = width;
82     height_ = height;
83     //方式一: 从 NativeImage 创建 NativeWindow
84     nativeWindow_ = OH_NativeImage_AcquireNativeWindow(image);
85     //方式二: 从 SurfaceId 创建 NativeWindow
86     int ret = OH_NativeWindow_CreateNativeWindowFromSurfaceId(surfaceId, &nativeWindow_);
87     if (ret != SUCCESS) {
88         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "OHNativeRender",
89             "Failed to create NativeWindow from SurfaceId.");
90         return false;
91     }
92     (void)OH_NativeWindow_NativeObjectReference(nativeWindow_);
93 
94     // 设置缓冲区的大小等属性
95     int32_t result = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_BUFFER_GEOMETRY,
96         static_cast<int32_t>(width_), static_cast<int32_t>(height_));
97     if (result != SUCCESS) {
98         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "OHNativeRender", "Failed to set buffer geometry.");
99         return false;
100     }
101 
102     return true;
103 }
104 
RenderFrame()105 void OHNativeRender::RenderFrame()
106 {
107     OHNativeWindowBuffer *buffer = nullptr;
108     int releaseFenceFd = INVALID_FD;
109     int32_t result = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer, &releaseFenceFd);
110     if (result != SUCCESS || buffer == nullptr) {
111         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN,
112                      "OHNativeRender", "Failed to request buffer, ret : %{public}d.", result);
113         return;
114     }
115 
116     int retCode = FAILURE;
117     uint32_t timeout = POLL_TIMEOUT_MS;
118     if (releaseFenceFd != INVALID_FD) {
119         struct pollfd pollfds = {};
120         pollfds.fd = releaseFenceFd;
121         pollfds.events = POLLIN;
122 
123         int retryCount = 0;
124 
125         do {
126             retCode = poll(&pollfds, NUM_POLL_FDS, POLL_TIMEOUT_MS);
127             retryCount++;
128 
129             // 超过最大重试次数则退出
130             if (retryCount >= MAX_RETRY) {
131                 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN,
132                     "OHNativeRender", "Poll reached maximum retry count.");
133                 break;
134             }
135         } while (retCode == FAILURE && (errno == EINTR || errno == EAGAIN));
136 
137         close(releaseFenceFd);
138     }
139 
140     BufferHandle *handle = OH_NativeWindow_GetBufferHandleFromNative(buffer);
141     if (handle == nullptr) {
142         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "OHNativeRender", "Failed to get buffer handle.");
143         return;
144     }
145 
146     // 使用 mmap 获取虚拟地址
147     void *mappedAddr = mmap(nullptr, handle->size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0);
148     if (mappedAddr == MAP_FAILED) {
149         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "OHNativeRender", "Failed to mmap buffer.");
150         return;
151     }
152 
153     // 获取像素指针
154     uint32_t *pixel = static_cast<uint32_t *>(mappedAddr);
155 
156     // 调用封装的函数来绘制渐变
157     DrawGradient(pixel, handle->stride / BYTES_PER_PIXEL, height_);
158 
159     // 解除内存映射
160     result = munmap(mappedAddr, handle->size);
161     if (result == FAILURE) {
162         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "OHNativeRender", "Failed to munmap buffer.");
163     }
164 
165     std::lock_guard<std::mutex> lock(mutex_);
166     // 设置刷新区域
167     Region region{nullptr, 0};
168     // 提交给消费者
169     result = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer, NO_FENCE, region);
170     if (result != SUCCESS) {
171         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN,
172                      "OHNativeRender", "Failed to flush buffer, result : %{public}d.", result);
173     }
174 }
175 
DrawGradient(uint32_t * pixel,uint64_t width,uint64_t height)176 void OHNativeRender::DrawGradient(uint32_t* pixel, uint64_t width, uint64_t height)
177 {
178     static double time = 0.0;
179     time += ANIMATION_SPEED_INCREMENT;
180     double offset = (sin(time) + MAX_INTENSITY) / INTENSITY_MULTIPLIER;
181 
182     // 箭头参数
183     const int arrowSize = std::min(width, height) / ARROW_SIZE_DIVISOR;
184     const int arrowX = width / ARROW_SIZE_DIVISOR;
185     const int arrowY = height / ARROW_SIZE_DIVISOR;
186     const int stemWidth = arrowSize / STEM_WIDTH_DIVISOR;
187     const int headWidth = arrowSize / HEAD_WIDTH_DIVISOR;
188     const int headLength = arrowSize / HEAD_LENGTH_DIVISOR;
189     const int stemStart = arrowX - arrowSize / ARROW_SIZE_DIVISOR;
190     const int stemEnd = arrowX + arrowSize / ARROW_SIZE_DIVISOR - headLength;
191 
192     for (uint64_t y = 0; y < height; y++) {
193         for (uint64_t x = 0; x < width; x++) {
194             double normalizedX = static_cast<double>(x) / static_cast<double>(width - 1);
195             bool isArrow = false;
196 
197             if ((x >= stemStart && x <= stemEnd && y >= arrowY - stemWidth * HEAD_SLOPE_MULTIPLIER &&
198                 y <= arrowY + stemWidth * HEAD_SLOPE_MULTIPLIER) || (x >= stemEnd && x <= stemEnd + headLength &&
199                 fabs(static_cast<int>(y - arrowY)) <= (headWidth * HEAD_SLOPE_MULTIPLIER) *
200                 (1.0 - static_cast<double>(x - stemEnd) / headLength))) {
201                 isArrow = true;
202             }
203 
204             uint8_t red = static_cast<uint8_t>((1.0 - normalizedX) * MAX_COLOR_VALUE);
205             uint8_t blue = static_cast<uint8_t>(normalizedX * MAX_COLOR_VALUE);
206             uint8_t green = 0;
207             uint8_t alpha = MAX_COLOR_VALUE;
208             if (isArrow) {
209                 red = green = blue = MAX_COLOR_VALUE;
210             }
211             double intensity = fabs(normalizedX - offset);
212             intensity = MAX_INTENSITY - std::min(INTENSITY_MULTIPLIER * intensity, INTENSITY_LIMIT);
213             intensity = std::max(intensity, MIN_INTENSITY);
214 
215             red = static_cast<uint8_t>(red * intensity);
216             green = static_cast<uint8_t>(green * intensity);
217             blue = static_cast<uint8_t>(blue * intensity);
218 
219             *pixel++ = (static_cast<uint32_t>(alpha) << ALPHA_SHIFT) | (static_cast<uint32_t>(red) << RED_SHIFT) |
220                 (static_cast<uint32_t>(green) << GREEN_SHIFT) | (static_cast<uint32_t>(blue) << BLUE_SHIFT);
221         }
222     }
223 }