鸿蒙(API 12 Beta6版)图形【NativeImage开发指导 (C/C++)】方舟2D图形服务

news2024/11/14 21:49:03

场景介绍

NativeImage是提供Surface关联OpenGL外部纹理的模块,表示图形队列的消费者端。开发者可以通过NativeImage接口接收和使用Buffer,并将Buffer关联输出到OpenGL外部纹理。

针对NativeImage,常见的开发场景如下:

  • 通过NativeImage提供的Native API接口创建NativeImage实例作为消费者端,获取与该实例对应的NativeWindow作为生产者端。NativeWindow相关接口可用于填充Buffer内容并提交,NativeImage将Buffer内容更新到OpenGL外部纹理上。本模块需要配合NativeWindow、NativeBuffer、EGL、GLES3模块一起使用。

接口说明

接口名描述
OH_NativeImage_Create (uint32_t textureId, uint32_t textureTarget)创建一个OH_NativeImage实例,该实例与OpenGL ES的纹理ID和纹理目标相关联。
OH_NativeImage_AcquireNativeWindow (OH_NativeImage *image)获取与OH_NativeImage相关联的OHNativeWindow指针,该OHNativeWindow后续不再需要时需要调用 OH_NativeWindow_DestroyNativeWindow释放。
OH_NativeImage_AttachContext (OH_NativeImage *image, uint32_t textureId)将OH_NativeImage实例附加到当前OpenGL ES上下文,且该OpenGL ES纹理会绑定到 GL_TEXTURE_EXTERNAL_OES,并通过OH_NativeImage进行更新。
OH_NativeImage_DetachContext (OH_NativeImage *image)将OH_NativeImage实例从当前OpenGL ES上下文分离。
OH_NativeImage_UpdateSurfaceImage (OH_NativeImage *image)通过OH_NativeImage获取最新帧更新相关联的OpenGL ES纹理。
OH_NativeImage_GetTimestamp (OH_NativeImage *image)获取最近调用OH_NativeImage_UpdateSurfaceImage的纹理图像的相关时间戳。
OH_NativeImage_GetTransformMatrix (OH_NativeImage *image, float matrix[16])获取最近调用OH_NativeImage_UpdateSurfaceImage的纹理图像的变化矩阵。
OH_NativeImage_Destroy (OH_NativeImage **image)销毁通过OH_NativeImage_Create创建的OH_NativeImage实例,销毁后该OH_NativeImage指针会被赋值为空。

开发步骤

以下步骤描述了如何使用NativeImage提供的Native API接口,创建OH_NativeImage实例作为消费者端,将数据内容更新到OpenGL外部纹理上。

添加动态链接库

CMakeLists.txt中添加以下lib。

libEGL.so
libGLESv3.so
libnative_image.so
libnative_window.so
libnative_buffer.so

头文件

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <native_image/native_image.h>
#include <native_window/external_window.h>
#include <native_buffer/native_buffer.h>
  1. 初始化EGL环境

这里提供一份初始化EGL环境的代码示例。

#include <iostream>
#include <string>
#include <EGL/egl.h>
#include <EGL/eglext.h>

using GetPlatformDisplayExt = PFNEGLGETPLATFORMDISPLAYEXTPROC;
constexpr const char *EGL_EXT_PLATFORM_WAYLAND = "EGL_EXT_platform_wayland";
constexpr const char *EGL_KHR_PLATFORM_WAYLAND = "EGL_KHR_platform_wayland";
constexpr int32_t EGL_CONTEXT_CLIENT_VERSION_NUM = 2;
constexpr char CHARACTER_WHITESPACE = ' ';
constexpr const char *CHARACTER_STRING_WHITESPACE = " ";
constexpr const char *EGL_GET_PLATFORM_DISPLAY_EXT = "eglGetPlatformDisplayEXT";
EGLContext eglContext_ = EGL_NO_CONTEXT;
EGLDisplay eglDisplay_ = EGL_NO_DISPLAY;
static inline EGLConfig config_;
static inline EGLSurface eglsurface_;
// 从XComponent中获取到的OHNativeWindow
OHNativeWindow *eglNativeWindow_;

// 检查egl扩展
static bool CheckEglExtension(const char *extensions, const char *extension) {
    size_t extlen = strlen(extension);
    const char *end = extensions + strlen(extensions);

    while (extensions < end) {
        size_t n = 0;
        if (*extensions == CHARACTER_WHITESPACE) {
            extensions++;
            continue;
        }
        n = strcspn(extensions, CHARACTER_STRING_WHITESPACE);
        if (n == extlen && strncmp(extension, extensions, n) == 0) {
            return true;
        }
        extensions += n;
    }
    return false;
}

// 获取当前的显示设备
static EGLDisplay GetPlatformEglDisplay(EGLenum platform, void *native_display, const EGLint *attrib_list) {
    static GetPlatformDisplayExt eglGetPlatformDisplayExt = NULL;

    if (!eglGetPlatformDisplayExt) {
        const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
        if (extensions && (CheckEglExtension(extensions, EGL_EXT_PLATFORM_WAYLAND) ||
                           CheckEglExtension(extensions, EGL_KHR_PLATFORM_WAYLAND))) {
            eglGetPlatformDisplayExt = (GetPlatformDisplayExt)eglGetProcAddress(EGL_GET_PLATFORM_DISPLAY_EXT);
        }
    }

    if (eglGetPlatformDisplayExt) {
        return eglGetPlatformDisplayExt(platform, native_display, attrib_list);
    }

    return eglGetDisplay((EGLNativeDisplayType)native_display);
}

static void InitEGLEnv() {
    // 获取当前的显示设备
    eglDisplay_ = GetPlatformEglDisplay(EGL_PLATFORM_OHOS_KHR, EGL_DEFAULT_DISPLAY, NULL);
    if (eglDisplay_ == EGL_NO_DISPLAY) {
        std::cout << "Failed to create EGLDisplay gl errno : " << eglGetError() << std::endl;
    }

    EGLint major, minor;
    // 初始化EGLDisplay
    if (eglInitialize(eglDisplay_, &major, &minor) == EGL_FALSE) {
        std::cout << "Failed to initialize EGLDisplay" << std::endl;
    }

    // 绑定图形绘制的API为OpenGLES
    if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
        std::cout << "Failed to bind OpenGL ES API" << std::endl;
    }

    unsigned int ret;
    EGLint count;
    EGLint config_attribs[] = {EGL_SURFACE_TYPE,
                               EGL_WINDOW_BIT,
                               EGL_RED_SIZE,
                               8,
                               EGL_GREEN_SIZE,
                               8,
                               EGL_BLUE_SIZE,
                               8,
                               EGL_ALPHA_SIZE,
                               8,
                               EGL_RENDERABLE_TYPE,
                               EGL_OPENGL_ES3_BIT,
                               EGL_NONE};

    // 获取一个有效的系统配置信息
    ret = eglChooseConfig(eglDisplay_, config_attribs, &config_, 1, &count);
    if (!(ret && static_cast<unsigned int>(count) >= 1)) {
        std::cout << "Failed to eglChooseConfig" << std::endl;
    }

    static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE};

    // 创建上下文
    eglContext_ = eglCreateContext(eglDisplay_, config_, EGL_NO_CONTEXT, context_attribs);
    if (eglContext_ == EGL_NO_CONTEXT) {
        std::cout << "Failed to create egl context %{public}x, error:" << eglGetError() << std::endl;
    }

    // 创建eglSurface
    eglSurface_ = eglCreateWindowSurface(eglDisplay_, config_, eglNativeWindow_, context_attribs);
    if (eglSurface_ == EGL_NO_SURFACE) {
        std::cout << "Failed to create egl surface %{public}x, error:" << eglGetError() << std::endl;
    }

    // 关联上下文
    eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_);

    // EGL环境初始化完成
    std::cout << "Create EGL context successfully, version" << major << "." << minor << std::endl;
}
  1. 创建OH_NativeImage实例
// 创建 OpenGL 纹理
GLuint textureId;
glGenTextures(1, &textureId);
// 创建 NativeImage 实例,关联 OpenGL 纹理
OH_NativeImage* image = OH_NativeImage_Create(textureId, GL_TEXTURE_EXTERNAL_OES);
  1. 获取对应的数据生产者端NativeWindow
// 获取生产者NativeWindow
OHNativeWindow* nativeWindow = OH_NativeImage_AcquireNativeWindow(image);
  1. 设置NativeWindow的宽高
int code = SET_BUFFER_GEOMETRY;
int32_t width = 800;
int32_t height = 600;
int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, width, height);
  1. 将生产的内容写入NativeWindowBuffer

  2. 从NativeWindow中获取NativeWindowBuffer。

OHNativeWindowBuffer *buffer = nullptr;
int fenceFd;
// 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &buffer, &fenceFd);
 
BufferHandle *handle = OH_NativeWindow_GetBufferHandleFromNative(buffer);
  1. 将生产的内容写入NativeWindowBuffer。
#include <sys/mman.h>
 
// 使用系统mmap接口拿到bufferHandle的内存虚拟地址
void *mappedAddr = mmap(handle->virAddr, handle->size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0);
if (mappedAddr == MAP_FAILED) {
    // mmap failed
}
static uint32_t value = 0x00;
value++;
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;
    }
}
// 内存使用完记得去掉内存映射
int result = munmap(mappedAddr, handle->size);
if (result == -1) {
    // munmap failed
}
  1. 将NativeWindowBuffer提交到NativeWindow。
// 设置刷新区域,如果Region中的Rect为nullptr,或者rectNumber为0,则认为NativeWindowBuffer全部有内容更改。
Region region{nullptr, 0};
// 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。
OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, buffer, fenceFd, region);
  1. 用完需要销毁NativeWindow。
OH_NativeWindow_DestroyNativeWindow(nativeWindow);
  1. 更新内容到OpenGL纹理
// 更新内容到OpenGL纹理。
ret = OH_NativeImage_UpdateSurfaceImage(image);
if (ret != 0) {
    std::cout << "OH_NativeImage_UpdateSurfaceImage failed" << std::endl;
}
// 获取最近调用OH_NativeImage_UpdateSurfaceImage的纹理图像的时间戳和变化矩阵。
int64_t timeStamp = OH_NativeImage_GetTimestamp(image);
float matrix[16];
ret = OH_NativeImage_GetTransformMatrix(image, matrix);
if (ret != 0) {
    std::cout << "OH_NativeImage_GetTransformMatrix failed" << std::endl;
}

// 对update绑定到对应textureId的纹理做对应的opengl后处理后,将纹理上屏
EGLBoolean eglRet = eglSwapBuffers(eglDisplay_, eglSurface_);
if (eglRet == EGL_FALSE) {
    std::cout << "eglSwapBuffers failed" << std::endl;
}
  1. 解绑OpenGL纹理,绑定到新的外部纹理上
// 将OH_NativeImage实例从当前OpenGL ES上下文分离
ret = OH_NativeImage_DetachContext(image);
if (ret != 0) {
    std::cout << "OH_NativeImage_DetachContext failed" << std::endl;
}
// 将OH_NativeImage实例附加到当前OpenGL ES上下文, 且该OpenGL ES纹理会绑定到 GL_TEXTURE_EXTERNAL_OES, 并通过OH_NativeImage进行更新
GLuint textureId2;
glGenTextures(1, &textureId2);
ret = OH_NativeImage_AttachContext(image, textureId2);
  1. OH_NativeImage实例使用完需要销毁掉
// 销毁OH_NativeImage实例
OH_NativeImage_Destroy(&image);

最后呢

很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。

在这里插入图片描述

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。

  • 《鸿蒙 (OpenHarmony)开发学习视频》
  • 《鸿蒙生态应用开发V2.0白皮书》
  • 《鸿蒙 (OpenHarmony)开发基础到实战手册》
  • OpenHarmony北向、南向开发环境搭建
  • 《鸿蒙开发基础》
  • 《鸿蒙开发进阶》
  • 《鸿蒙开发实战》

在这里插入图片描述

总结

鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。

并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行! 自↓↓↓拿
1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2105062.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

服务器文件权限限制写入

1、先查看文件需要的用户权限。 ls -l2、判断自己的账户不具备写入权限 container里面建的文件&#xff0c;需要用户身份是root&#xff0c;如果你不在rootfile里file的话&#xff0c;是无法对需要root权限的文件增删改的。 3、创建container与宿主机共享的文件夹 如果想宿…

【Python】统计列表出现某个数字/字段的次数+去除列表的nan值+计算列表中的正负值百分比和绝对值

1. 统计一个列表出现某个数字或者字段的次数 A. 列表推导式法 原理&#xff1a;使用列表推导式找出所有等于0的元素&#xff0c;并用sum()函数计算它们的数量。 这个方法的优点是&#xff1a;可以筛选等于和不等于的&#xff0c;用来统计占比。如果需要筛选的是字符串&#…

【AQS源码】深入理解AQS的工作原理

【AQS源码】深入理解AQS的工作原理-CSDN博客

XXL-JOB分布式任务调度教程(持续更新~)

先大致声明一下流程&#xff08;具体细节在下面哦~&#xff09; 步骤&#xff1a; 1.下载xxl-job并配置以及启动 2.导入对应maven坐标 3.配置对应的配置文件以及编写对应的配置类config 4.编写要触发的方法并且给方法打上XXlJob("")注解 5.设置xxl-Job平台上的任务 …

环球佳酿:如何利用CRM系统实现营销管理数字化转型

在科技迅猛发展的今天&#xff0c;传统行业正在以空前的速度与数字技术相融合。面对从增量扩张转向存量竞争的白酒产业&#xff0c;培育新质生产力、推进数字化与智能化转型已成为业界的普遍共识。众多白酒企业纷纷探索数字化转型之路&#xff0c;力图通过创新和突破来提升竞争…

火狐浏览器设置秘籍:让https协议下的ws不加密时运行无阻(WebSocket connection HTTPS)

Uncaught (in promise) DOMException: Failed to construct ‘WebSocket’: An insecure WebSocket connection may not be initiated from a page loaded over HTTPS. 明确指出了一个常见的安全限制&#xff1a;当尝试从一个通过HTTPS加载的页面上发起一个不安全的&#xff08…

零基础国产GD32单片机编程入门(十三)单片机IAP(在应用编程)详解及实战源码

文章目录 一.概要二.GD32F103C8T6单片机IAP介绍1.GD32F103C8T6单片机IAP基本原理2.GD32F103C8T6单片机IAP基本流程 三.配置一个BOOT工程四.配置一个APP工程五.工程源代码下载六.小结 一.概要 GD32单片机程序升级方法有很多种&#xff0c;主要有以下几种&#xff1a; 1.将编译…

【unity知识】Animator动画状态的基本属性介绍

文章目录 动画状态的基本属性1、标签Tag2、Motion 该状态所管理的动画片段3、speed 动画的播放速度4、Motion Time 播放动画片段定在一个特定时间点5、Mirror镜像动画6、CycleOffset动画偏移7、FootIK8、Write Defaults 参考完结 动画状态的基本属性 1、标签Tag 通过打标签我们…

NIO笔记04-网络编程

文章目录 1 非阻塞 vs 阻塞 ★★★阻塞非阻塞多路复用 2 Selector创建绑定 Channel 事件监听 Channel 事件&#x1f4a1; select 何时不阻塞 3 处理 accept 事件&#x1f4a1; 事件发生后能否不处理 4 处理 read 事件处理添加区分事件类型&#xff0c;客户端发送数据时会报空指…

基于TCP的web端服务器数据库查询商品

背景描述 该系统为创建网络并发服务器&#xff0c;搭建HTML网络页面框架&#xff0c;通过HTTP超文本网络传输与用户建立连接&#xff08;TCP建立连接&#xff09;&#xff0c;从自己建立的数据库中查询用户所需信息&#xff0c;使用户能在网页中直接查询相关内容。本系统包括…

Elasticsearch设置密码报错:ERROR: X-Pack Security is disabled by configuration.

elasticsearch@6ef6c3f5ee45:~$ bin/elasticsearch-setup-passwords auto Unexpected response code [405] from calling GET http://172.17.0.2:9200/_security/_authenticate?pretty It doesn’t look like the X-Pack security feature is enabled on this Elasticsearch n…

Meshy-4:AI驱动3D建模的革命性工具,解锁虚拟创作新高度

Meshy发布了最新的AI驱动3D建模工具——Meshy-4&#xff0c;这是虚拟环境创作领域的一大进步。对设计师和开发者来说&#xff0c;Meshy-4的出现不仅是技术上的飞跃&#xff0c;更是创作效率的极大提升。 Meshy-4的亮点与功能 1. 更清晰、更专业的AI生成3D模型&#xff1a; Mes…

沉浸式体验:ARM 工控机携手 HT for Web 打造智能建筑监控

工业领域技术的进步不断推动着生产和管理方式的革新。随着物联网、大数据、云计算等技术的发展&#xff0c;工业自动化和信息化融合的趋势日益明显。在这样的背景下&#xff0c;HT for Web 和 ARM 工业计算机成为了工业智能化道路上的重要工具。 HT for Web 是一款基于WebGL的高…

2024国赛数学建模备赛|30种常用的算法模型之最优算法,线性规划

1.最优化理论基础 1.1 最优化问题的数学模型 通俗地说&#xff0c;所谓最优化问题&#xff0c;就是求一个多元函数在某个给定集合上的极 值. 几乎所有类型的最优化问题都可以用下面的数学模型来描述: 这里&#xff0c;&#x1d43e; 是某个给定的集合 (称为可行集或可行域)&a…

ffmpeg 视频编码及基本知识

理论 H264编码原理&#xff08;简略&#xff09; 1. 视频为什么需要进行编码压缩 降低视频数据大小&#xff0c;方便存储和传输 2. 为什么压缩的原始数据采用YUV格式 彩色图像的格式是 RGB 的&#xff0c;但RGB 三个颜色是有相关性的。 采用YUV格式&#xff0c;利用人对图像的…

LoRa芯片在RX时产生的中断顺序QA

目录 1 前言2 问题集锦及解答2.1 radio芯片在接包时&#xff0c;preamble、header和Rx done三个中断产生顺序是怎么样的&#xff1f;谁先谁后&#xff1f;2.2 产生了Header error中断后&#xff0c;radio芯片会继续接收本包还是立马丢弃本包&#xff1f;2.3 产生了CRC error中断…

语言中的类型转换

编程语言中必然有很多情况需要转换类型。比如引入const的概念就为了提高安全性&#xff0c;编译器提前检查&#xff0c;避免一些意外修改。当然&#xff0c;有时&#xff0c;我们希望手动转换一个变量的类型&#xff0c;让其变成常量&#xff0c;可以利用编译器提供的cast方法。…

保隆科技半年报:净利同比下滑近两成,ADAS/空悬业务仍亏损

2024年上半年&#xff0c;在全球产业链调整、局部战争仍未平息等事件长期影响下&#xff0c;叠加主要经济体货币政策调整、债务风险上升等周期性因素&#xff0c;全球经济复苏面临较大不确定性&#xff0c;汽车市场尚处在缓慢恢复阶段。 这也导致不少汽车零部件上市公司的半年报…

SQL语言的规则和规范

规则 是什么呢&#xff0c;规则就是我们最基本&#xff0c;每时每刻都要遵守的比如人行道靠右&#xff0c;不能逆行&#xff0c; 规范 呢就是锦上添花&#xff0c;如果你不这么做&#xff0c;是不那么道德&#xff0c;不那么好的&#xff0c;就像小学生见到老师要问好&#…