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