HarmonyOS 鸿蒙Next:Native里连续的像素刷新应该怎么做

发布于 1周前 作者 sinazl 来自 鸿蒙OS

HarmonyOS 鸿蒙Next:Native里连续的像素刷新应该怎么做

目前遇到问题,使用XComponent连续对同一区域buffer刷新,第一帧渲染正常的情况下,第二帧渲染前,一定会黑屏一下。imagePixel 一直是同一个,外部会有一次像素copy。不知道问题出在哪里? 即使连续的将 imagePixel 全部设置为全红色,一样会有黑屏问题

void PluginRender::RefreshBitmap(std::string &id, gpointer imagePixel, gint x, gint y, gint width, gint height) {
PluginRender *render = PluginRender::GetInstance(id);
if (render == nullptr) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, PluginRenderTag, “RefreshBitmap render = null”);
return;
}
// 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
OHNativeWindowBuffer *buffer = nullptr;
int releaseFenceFd = -1;
int32_t ret = OH_NativeWindow_NativeWindowRequestBuffer(render->nativeWindow_, &buffer, &releaseFenceFd);
if (ret != 0 || buffer == nullptr) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, PluginRenderTag, “RefreshBitmap failed, ret != 0”);
return;
}
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, PluginRenderTag, “RefreshBitmap OH_NativeWindow_NativeWindowRequestBuffer, fenceFd = %{public}d”, releaseFenceFd);
BufferHandle *bufferHandle = OH_NativeWindow_GetBufferHandleFromNative(buffer);
uint32_t *mappedAddr = static_cast<uint32_t *>(
// 使用内存映射函数mmap将bufferHandle对应的共享内存映射到用户空间,可以通过映射出来的虚拟地址向bufferHandle中写入图像数据
// bufferHandle->virAddr是bufferHandle在共享内存中的起始地址,bufferHandle->size是bufferHandle在共享内存中的内存占用大小
mmap(bufferHandle->virAddr, bufferHandle->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle->fd, 0));
if (mappedAddr == MAP_FAILED) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, PluginRenderTag, “RefreshBitmap mmap failed”);
return;
}

int retCode = -1;
uint32_t timeout = 3000;
if (releaseFenceFd != -1) {
struct pollfd pollfds = {0};
pollfds.fd = releaseFenceFd;
pollfds.events = POLLIN;
do {
retCode = poll(&pollfds, 1, timeout);
} while (retCode == -1 && (errno == EINTR || errno == EAGAIN));
close(releaseFenceFd); // 防止fd泄漏
}

// 画完后获取像素地址,地址指向的内存包含画布画的像素数据
uint32_t *value = static_cast<uint32_t *>(imagePixel);

// 使用mmap获取到的地址来访问内存
uint32_t *pixel = static_cast<uint32_t *>(mappedAddr);
for (uint32_t x = 0; x < width; x++) {
for (uint32_t y = 0; y < height; y++) {
*pixel++ = *value++;
}
}

// 如果Region中的Rect为nullptr,或者rectNumber为0,则认为OHNativeWindowBuffer全部有内容更改。
Region region;
region.rectNumber = 1;
region.rects = new Region::Rect[1]{{x, y, static_cast<uint32_t>(width), static_cast<uint32_t>(height)}};

OH_LOG_Print(LOG_APP, LOG_DEBUG, 0, PluginRenderTag, “RefreshBitmap OH_NativeWindow_NativeWindowFlushBuffer before, x:%{public}d, y:%{public}d, w:%{public}d, h:%{public}d”, region.rects[0].x,
region.rects[0].y, region.rects[0].w, region.rects[0].h);
int acquireFenceFd = -1;
// 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。
int32_t flushBufferRet = OH_NativeWindow_NativeWindowFlushBuffer(render->nativeWindow_, buffer, acquireFenceFd, region);
// 内存使用完记得去掉内存映射
int munmapRet = munmap(mappedAddr, bufferHandle->size);
OH_LOG_Print(LOG_APP, LOG_DEBUG, 0, PluginRenderTag, “RefreshBitmap OH_NativeWindow_NativeWindowFlushBuffer, flushBufferRet = %{public}d, munmapRet = %{public}d,”, flushBufferRet, munmapRet);
}

2 回复
do_color_convert(displayData, x, y, width, height);
std::string id = "xcomponentId";
PluginRender::RefreshBitmap(id, displayData->imageBitmap, x, y, width, height);

uint32_t Convert32xRGBToRGBA8888(uint32_t rgb) {
// uint8_t r = (rgb >> 16) & 0xFF; // 提取红色
// uint8_t g = (rgb >> 8) & 0xFF; // 提取绿色
// uint8_t b = rgb & 0xFF; // 提取蓝色
// uint8_t a = 255; // 设置 alpha 为 255

uint8_t r = 255;
uint8_t g = 0;
uint8_t b = 0;
uint8_t a = 255; // 设置 alpha 为 255

return (a << 24) | (r << 16) | (g << 8) | b; // 返回 RGBA 8888 格式
}

static void do_color_convert(SpiceDisplayData *displayData, gint x, gint y, gint w, gint h) {
OH_LOG_Print(LOG_APP, LOG_DEBUG, GLOBAL_RESMGR, tag, "do_color_convert, format: %{public}d, stride: %{public}d", displayData->imageFormat, displayData->stride);
int i, j, maxy, maxx, miny, minx;
guint32 *dest = (guint32 *)displayData->imageBitmap;
guint32 *src = (guint32 *)displayData->origin_imgdata;

miny = MAX(y, 0);
minx = MAX(x, 0);
maxy = MIN(y + h, displayData->height);
maxx = MIN(x + w, displayData->width);

dest += (displayData->stride / 4) * miny; // 计算目标行的起始地址
src += (displayData->stride / 2) * miny; // 计算源行的起始地址

for (j = miny; j < maxy; j++) {
for (i = minx; i < maxx; i++) {
dest[i] = Convert32xRGBToRGBA8888(src[i]);
}
dest += displayData->stride / 4; // 移动到下一行
src += displayData->stride / 2; // 移动到下一行
}
}

在HarmonyOS鸿蒙Next中,Native层实现连续的像素刷新通常涉及对图形界面的高效更新。以下是一些关键步骤和考虑因素:

  1. 使用高效的图形API:利用HarmonyOS提供的图形API(如Canvas、Surface等)进行像素绘制和更新。确保在绘制过程中尽量减少不必要的计算和渲染开销。
  2. 双缓冲技术:采用双缓冲机制,在后台缓冲区中绘制新帧,然后一次性将其切换到前台显示,以减少闪烁和撕裂现象。
  3. 异步更新:将像素更新操作放在异步线程中执行,避免阻塞主线程,确保界面流畅。
  4. 优化刷新策略:根据实际需求设计合理的刷新策略,如按需刷新、定时刷新或基于事件触发的刷新。
  5. 资源管理:合理管理图形资源,如内存、纹理等,避免资源泄漏和过度消耗。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部