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

打印 上一主题 下一主题

主题 1009|帖子 1009|积分 3027

场景先容

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。
  1. libEGL.so
  2. libGLESv3.so
  3. libnative_image.so
  4. libnative_window.so
  5. libnative_buffer.so
复制代码
头文件
  1. #include <EGL/egl.h>
  2. #include <EGL/eglext.h>
  3. #include <GLES3/gl3.h>
  4. #include <native_image/native_image.h>
  5. #include <native_window/external_window.h>
  6. #include <native_buffer/native_buffer.h>
复制代码

  • 初始化EGL情况
这里提供一份初始化EGL情况的代码示例。
  1. #include <iostream>
  2. #include <string>
  3. #include <EGL/egl.h>
  4. #include <EGL/eglext.h>
  5. using GetPlatformDisplayExt = PFNEGLGETPLATFORMDISPLAYEXTPROC;
  6. constexpr const char *EGL_EXT_PLATFORM_WAYLAND = "EGL_EXT_platform_wayland";
  7. constexpr const char *EGL_KHR_PLATFORM_WAYLAND = "EGL_KHR_platform_wayland";
  8. constexpr int32_t EGL_CONTEXT_CLIENT_VERSION_NUM = 2;
  9. constexpr char CHARACTER_WHITESPACE = ' ';
  10. constexpr const char *CHARACTER_STRING_WHITESPACE = " ";
  11. constexpr const char *EGL_GET_PLATFORM_DISPLAY_EXT = "eglGetPlatformDisplayEXT";
  12. EGLContext eglContext_ = EGL_NO_CONTEXT;
  13. EGLDisplay eglDisplay_ = EGL_NO_DISPLAY;
  14. static inline EGLConfig config_;
  15. static inline EGLSurface eglsurface_;
  16. // 从XComponent中获取到的OHNativeWindow
  17. OHNativeWindow *eglNativeWindow_;
  18. // 检查egl扩展
  19. static bool CheckEglExtension(const char *extensions, const char *extension) {
  20.     size_t extlen = strlen(extension);
  21.     const char *end = extensions + strlen(extensions);
  22.     while (extensions < end) {
  23.         size_t n = 0;
  24.         if (*extensions == CHARACTER_WHITESPACE) {
  25.             extensions++;
  26.             continue;
  27.         }
  28.         n = strcspn(extensions, CHARACTER_STRING_WHITESPACE);
  29.         if (n == extlen && strncmp(extension, extensions, n) == 0) {
  30.             return true;
  31.         }
  32.         extensions += n;
  33.     }
  34.     return false;
  35. }
  36. // 获取当前的显示设备
  37. static EGLDisplay GetPlatformEglDisplay(EGLenum platform, void *native_display, const EGLint *attrib_list) {
  38.     static GetPlatformDisplayExt eglGetPlatformDisplayExt = NULL;
  39.     if (!eglGetPlatformDisplayExt) {
  40.         const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
  41.         if (extensions && (CheckEglExtension(extensions, EGL_EXT_PLATFORM_WAYLAND) ||
  42.                            CheckEglExtension(extensions, EGL_KHR_PLATFORM_WAYLAND))) {
  43.             eglGetPlatformDisplayExt = (GetPlatformDisplayExt)eglGetProcAddress(EGL_GET_PLATFORM_DISPLAY_EXT);
  44.         }
  45.     }
  46.     if (eglGetPlatformDisplayExt) {
  47.         return eglGetPlatformDisplayExt(platform, native_display, attrib_list);
  48.     }
  49.     return eglGetDisplay((EGLNativeDisplayType)native_display);
  50. }
  51. static void InitEGLEnv() {
  52.     // 获取当前的显示设备
  53.     eglDisplay_ = GetPlatformEglDisplay(EGL_PLATFORM_OHOS_KHR, EGL_DEFAULT_DISPLAY, NULL);
  54.     if (eglDisplay_ == EGL_NO_DISPLAY) {
  55.         std::cout << "Failed to create EGLDisplay gl errno : " << eglGetError() << std::endl;
  56.     }
  57.     EGLint major, minor;
  58.     // 初始化EGLDisplay
  59.     if (eglInitialize(eglDisplay_, &major, &minor) == EGL_FALSE) {
  60.         std::cout << "Failed to initialize EGLDisplay" << std::endl;
  61.     }
  62.     // 绑定图形绘制的API为OpenGLES
  63.     if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
  64.         std::cout << "Failed to bind OpenGL ES API" << std::endl;
  65.     }
  66.     unsigned int ret;
  67.     EGLint count;
  68.     EGLint config_attribs[] = {EGL_SURFACE_TYPE,
  69.                                EGL_WINDOW_BIT,
  70.                                EGL_RED_SIZE,
  71.                                8,
  72.                                EGL_GREEN_SIZE,
  73.                                8,
  74.                                EGL_BLUE_SIZE,
  75.                                8,
  76.                                EGL_ALPHA_SIZE,
  77.                                8,
  78.                                EGL_RENDERABLE_TYPE,
  79.                                EGL_OPENGL_ES3_BIT,
  80.                                EGL_NONE};
  81.     // 获取一个有效的系统配置信息
  82.     ret = eglChooseConfig(eglDisplay_, config_attribs, &config_, 1, &count);
  83.     if (!(ret && static_cast<unsigned int>(count) >= 1)) {
  84.         std::cout << "Failed to eglChooseConfig" << std::endl;
  85.     }
  86.     static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE};
  87.     // 创建上下文
  88.     eglContext_ = eglCreateContext(eglDisplay_, config_, EGL_NO_CONTEXT, context_attribs);
  89.     if (eglContext_ == EGL_NO_CONTEXT) {
  90.         std::cout << "Failed to create egl context %{public}x, error:" << eglGetError() << std::endl;
  91.     }
  92.     // 创建eglSurface
  93.     eglSurface_ = eglCreateWindowSurface(eglDisplay_, config_, eglNativeWindow_, context_attribs);
  94.     if (eglSurface_ == EGL_NO_SURFACE) {
  95.         std::cout << "Failed to create egl surface %{public}x, error:" << eglGetError() << std::endl;
  96.     }
  97.     // 关联上下文
  98.     eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_);
  99.     // EGL环境初始化完成
  100.     std::cout << "Create EGL context successfully, version" << major << "." << minor << std::endl;
  101. }
复制代码

  • 创建OH_NativeImage实例
  1. // 创建 OpenGL 纹理
  2. GLuint textureId;
  3. glGenTextures(1, &textureId);
  4. // 创建 NativeImage 实例,关联 OpenGL 纹理
  5. OH_NativeImage* image = OH_NativeImage_Create(textureId, GL_TEXTURE_EXTERNAL_OES);
复制代码

  • 获取对应的数据生产者端NativeWindow
  1. // 获取生产者NativeWindow
  2. OHNativeWindow* nativeWindow = OH_NativeImage_AcquireNativeWindow(image);
复制代码

  • 设置NativeWindow的宽高
  1. int code = SET_BUFFER_GEOMETRY;
  2. int32_t width = 800;
  3. int32_t height = 600;
  4. int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, width, height);
复制代码

  • 将生产的内容写入NativeWindowBuffer
  • 从NativeWindow中获取NativeWindowBuffer。
  1. OHNativeWindowBuffer *buffer = nullptr;
  2. int fenceFd;
  3. // 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
  4. OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &buffer, &fenceFd);
  5. BufferHandle *handle = OH_NativeWindow_GetBufferHandleFromNative(buffer);
复制代码

  • 将生产的内容写入NativeWindowBuffer。
  1. #include <sys/mman.h>
  2. // 使用系统mmap接口拿到bufferHandle的内存虚拟地址
  3. void *mappedAddr = mmap(handle->virAddr, handle->size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0);
  4. if (mappedAddr == MAP_FAILED) {
  5.     // mmap failed
  6. }
  7. static uint32_t value = 0x00;
  8. value++;
  9. uint32_t *pixel = static_cast<uint32_t *>(mappedAddr);
  10. for (uint32_t x = 0; x < width; x++) {
  11.     for (uint32_t y = 0; y < height; y++) {
  12.         *pixel++ = value;
  13.     }
  14. }
  15. // 内存使用完记得去掉内存映射
  16. int result = munmap(mappedAddr, handle->size);
  17. if (result == -1) {
  18.     // munmap failed
  19. }
复制代码

  • 将NativeWindowBuffer提交到NativeWindow。
  1. // 设置刷新区域,如果Region中的Rect为nullptr,或者rectNumber为0,则认为NativeWindowBuffer全部有内容更改。
  2. Region region{nullptr, 0};
  3. // 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。
  4. OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, buffer, fenceFd, region);
复制代码

  • 用完必要烧毁NativeWindow。
  1. OH_NativeWindow_DestroyNativeWindow(nativeWindow);
复制代码

  • 更新内容到OpenGL纹理
  1. // 更新内容到OpenGL纹理。
  2. ret = OH_NativeImage_UpdateSurfaceImage(image);
  3. if (ret != 0) {
  4.     std::cout << "OH_NativeImage_UpdateSurfaceImage failed" << std::endl;
  5. }
  6. // 获取最近调用OH_NativeImage_UpdateSurfaceImage的纹理图像的时间戳和变化矩阵。
  7. int64_t timeStamp = OH_NativeImage_GetTimestamp(image);
  8. float matrix[16];
  9. ret = OH_NativeImage_GetTransformMatrix(image, matrix);
  10. if (ret != 0) {
  11.     std::cout << "OH_NativeImage_GetTransformMatrix failed" << std::endl;
  12. }
  13. // 对update绑定到对应textureId的纹理做对应的opengl后处理后,将纹理上屏
  14. EGLBoolean eglRet = eglSwapBuffers(eglDisplay_, eglSurface_);
  15. if (eglRet == EGL_FALSE) {
  16.     std::cout << "eglSwapBuffers failed" << std::endl;
  17. }
复制代码

  • 解绑OpenGL纹理,绑定到新的外部纹理上
  1. // 将OH_NativeImage实例从当前OpenGL ES上下文分离
  2. ret = OH_NativeImage_DetachContext(image);
  3. if (ret != 0) {
  4.     std::cout << "OH_NativeImage_DetachContext failed" << std::endl;
  5. }
  6. // 将OH_NativeImage实例附加到当前OpenGL ES上下文, 且该OpenGL ES纹理会绑定到 GL_TEXTURE_EXTERNAL_OES, 并通过OH_NativeImage进行更新
  7. GLuint textureId2;
  8. glGenTextures(1, &textureId2);
  9. ret = OH_NativeImage_AttachContext(image, textureId2);
复制代码

  • OH_NativeImage实例使用完必要烧毁掉
  1. // 销毁OH_NativeImage实例
  2. 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 万款的应用。那么这么多的应用必要开发,也就意味着必要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行! 自↓↓↓拿


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

宝塔山

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表