This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] Linux/TDA2PXEVM:离屏 GPU 渲染到用户空间映射缓冲器

Guru**** 2577385 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/769511/linux-tda2pxevm-offscreen-gpu-rendering-to-userspace-mapped-buffer

器件型号:TDA2PXEVM

工具/软件:Linux

我将 tda2px 平台与 VISION SDK 配合使用:software-dl.ti.com/processor-sdk-vision/esd/TDAx/vision-sdk/latest/index_FDS.html

当前正在尝试设置在 GPU 和 CPU 之间共享工作负载的后台处理流水线。 GPU 需要呈现一些离屏数据、CPU 可以进一步处理这些数据。

为此、我需要将用户空间映射缓冲区作为 OpenGL 资源传递。

通常在 GPU 侧、这是由 GL/EGL 实现的:EGLImage -> eglImageTargetRenderbufferStorage -> glFrameBufferRenderBuffer -> glDraw*

我在 ADAS 演示中发现 VISION_SDK/links_FW/src/HLS/system/system_egl_context.h 中使用的实用程序、用于将摄像机帧映射为 GPU 资源。

System_EglWindowObj* pEglObj;
EGLCompatBuffer eglCBuf = pEglObj->eglInfo.get_EGL_attach_buffer (buf_width、buf_height、system_Df_RGB24_888 / mapbuf_format*、buf_memory_pointer);pegf_gap_gel_heel
(pegl_gel_gap_gel_gap_gel_gap_gel_gaps);peglesnative = pegr_gel_gel_gel_gel_gel_gap_gel_gap_gap_gel_gel_gap_gap_esnative、 

那么、现在的问题是如何获取在 GPU/CPU 之间共享的连续存储器区域、并将其映射到我们的进程。

我已经取得了很大的进展:

使用通用缓冲区管理器:TI_components/OS_tools/linux/targetfs/usr/include/GBM/gbm.h 创建共享缓冲区

使用直接渲染管理器:TI_components/OS_tools/linux/targetfs/usr/include/xf86drm.h 将缓冲区映射到处理用户空间

下面是一些省略了错误检查的伪代码:

struct GBM_DEVICE* gbmDev =(GBM_DEVICE_)pEglObj->nativeDisplay;

int FD = drmOpen ("omapdrm"、NULL);// DRM 句柄
struct struct GBM_bo* bo = GBM_BO_create (gbmDev、buf_width、buf_height、GBM_BO_format_GBM_SCBGBM_FORMAT_GBM*);GBM_GBM_SCBGBM_SCBGBM_FORMAT_SCBGBM*使用 GBM*
int bo_fd = GBM_bo_get_fd (bo);
union GBM_bo_handle bo_handle = GBM_bo_get_handle (bo);

struct drm_mode_map_dumb mreq ={0};
mreq.handle = bo_handle.ptr;
int ret = drmIoctl (fd /* bo_reert*、dumb mmap ={0}、mrebdumb
)、mfr_t_trl_remot_t_t_remote_remote_t*、t_dumb = mreq.offset);

GBM 缓冲区对象似乎已正确创建、具有句柄和文件描述符、但我无法映射它:

drmIoctl -返回-1、因此我们无法映射缓冲区对象以提供 get_EGL_attach_buffer 的指针。

这是解决此特定问题的正确方法还是实现此功能的更好方法?

后续问题将是高速缓存控制、当从 CPU 切换到 GPU 时、提供了哪些工具来使共享缓冲区无效/清除共享缓冲区、反之亦然?

提前感谢您、

此致、

Yavor

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您能否尝试使用"fd = open ("/dev/dri/card0、O_RDWR)"而不是 drmOpen 并告知我?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    drmOpen ("omapdrm"、NULL)似乎使用/dev/dri/card1
    我尝试使用 open ("/dev/dri/card0、O_RDWR)、但没有任何更改。
    map_dumb 仍然失败、因此我无法获取用于 mmap 缓冲区的适当偏移。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您使用的是哪个版本的 processor_sdk_vision?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    进一步发展:

    我尝试将 GBM_bo 转换为 OMAP-bo、因此我可以使用 OMAP-BO_MAP 函数:

    struct omap_device* omap_dev = omap_device_new (FD);
    struct omap_bo * omap_bo_= omap_bo_from_dabuf (omap_dev、bo_fd);
    void * omap_bo_userspace = omap_bo_map (omap_bo_); 

    但是、将此指针传递到 get_EGL_attach_buffer 会导致:

    SI 代码= 2 (映射对象的权限无效)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我正在使用的 rootfs 和处理器 SDK 的版本如下所示:

    tisdk-rootfs-image-dra7xx-evm_vsdk_3_5
    PROCESSOR_SDK_VISION_03_05_00_00_setuplinux

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    使用 OMAP-BO_MAP()时是否获得有效的用户空间地址? 你得到什么地址?
    函数 get_gl_attach_buffer 在哪里实现?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我尝试在堆上创建一个小的时间缓冲区、地址似乎是相关的:
    OMAP-BO_MAP 指针:0x8a167000
    处理 malloc 指针:0x8a136008

    CPU 测试向两个内存区域写入48KB 无故障通过:
    [GBM]写入 malloc 存储器
    [GBM]写入 OMAP-BO_userspace

    get_gl_attach_buffer 的声明位于:vision_sdk/links_fw/src/HLS/system/system_egl_context.h 中
    实现被隐藏、函数接收到一个指向定义的运行时指针。
    指向该函数的指针看起来正确、SDK 在 VISION_SDK/links_FW/src/HLS/system/system_gl_EGL_utils.c 中使用
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    除非在 QNX 上运行、否则不应使用 get_EGL_attach_buffer 函数。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我切换到使用 EGL_LINUX_DMA_BUF_EXT 扩展:(YUV 缓冲器成功)

    //生成具有用户空间映射
    的缓冲区对象 int fd = drmOpen ("omapdrm"、NULL);
    struct omapdrm* omap设备* omap_dev = omap_device_new (fd);
    struct omap_bo* omap_bo* omap_new (omap_dev、256*4、0* omap_bo_scanout);struct omap_bo* omap_bu_mbo* omap_ma_domap_new/omap_abitude_flags
    
    = omap_omap_omap_infotain/ omap_omap_omap_infotain/omap_omap_ma_domap_infotain/omap_ma_domap_ma_domap_ma_domap_
    
    
    
    EGL_Linux_DRM_FourCC_EXT、DRM_FORMAT_NV12、
    EGL_width、256、
    EGL_Height、256、
    EGL_DMA_BUF_PLANE0_Pit_EXT、256、
    EGL_DMA_BUF_PLANE0_OFFSET_EXT、0、
    EGL_DMA_BUF_PLANE0_FD_EXT、DMA_FD、
    EGL_DMA_BUF_Plane1_Pit_EXT、256、
    EGL_DMA_BUF_Plane1_OFFSET_EXT、0、
    EGL_DMA_BUF_Plane1_FD_EXT、DMA_FD、
    EGL_NONE、EGL_NONE
    };
    
    EGLImageKHR img = eglCreateImageKHR (pEglObj->display、EGL_NO_Context、EGL_Linux_DMA_BUF_EXT、NULL、attr);
    
    格网格纹理(1、纹理);
    格网纹理(GL_纹 理_external_OES、纹理);CGLW ();
    glEGLImageTargetTexture2DOES (gL_torture_external_OES、img);CGLW ();
    
    //从缓冲区对象
    EGLint attr[]生成 RGBA EGLImage
    EGL_Linux_DRM_FourCC_EXT、DRM_FORMAT_ARGB8888、
    EGL_width、256、
    EGL_Height、256、
    EGL_DMA_BUF_PLANE0_Pit_EXT、256*4、
    EGL_DMA_BUF_PLANE0_OFFSET_EXT、0、
    EGL_DMA_BUF_PLANE0_FD_EXT、DMA_FD、
    EGL_NONE、EGL_NONE
    };
    
    EGLImageKHR img = eglCreateImageKHR (pEglObj->display、EGL_NO_Context、EGL_Linux_DMA_BUF_EXT、NULL、attr);
    

    缓冲区对象、映射地址和 DMA FD 有效。

    已成功创建具有 DRM_FORMAT_NV12的 EGLImage、并且 EGL 资源可以映射到 GL_TEST_EXTERNAL_OES 纹理。 但是,此纹理不能作为渲染的颜色附件附加到帧缓冲区中。

    具有 DRM_FORMAT_ARGB8888格式的 EGLImage 返回 EGL_BAD_MATCH、但对于32位 ARGB 格式、GBM_DEVICE_IS _FORMAT_SUPPORTED 返回 true。

    我还尝试使用以下命令创建 DMA 缓冲区:

    struct GBM_bo* bo = GBM_BO_create (gbmDev、256、GBM_FORMAT_ARGB888/*格式*/、GBM_BO_USE_RELEASE/*标志*/);
    struct omap_bo * omap_bo_= omap_bo_from_dabuf (omap_dev、GBM_bo_get_fd (bo)); 

    但仍然无法创建渲染输出所需的 RGBA EGLImage。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Yavor、
    请在此源文件中引用 create_textorate()函数。
    git.ti.com/.../display-kmscube.c
    这演示了如何将 NV12/YV/ARGB 纹理添加到 eglImage 中。

    但这仅适用于 GBM 显示。 对于航迹显示、不支持 PIXMAP。

    谢谢
    Ramprasad
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的反馈、以下是使用 PIXMAP 而非 EGL_Linux_DMA_BUF_EXT 的有效解决方案:

    //离屏零复制 GPU 到用户空间渲染
    //注意:忽略错误检查和句柄关闭!
    
    // 1. 创建并映射共享缓冲区对象
    
    //我们必须有有效的 GBM 设备,在我的情况下,这是由流水线
    结构 GBM_DEVICE* gbmDev =(EGLNativeDisplayType) nativeDisplayDisplay;
    
    //打开 OMA_DEVICE 使用的 DRM 句柄
    int DRM = drmOpen ("omapdrm",NULL); //打开的设备是/dev/dri/card //
    
    创建 GenericBufferManager 缓冲区对象。 我们将使用此对象映射 EGL 图像
    结构 GBM_BO* bo = GBM_BO_create (gbmDev、256、GBM_FORMAT_ARGB888/GBM_GBM*/、GBM_BO_USE_Rendering /*flags*/);
    
    //使用 OMAP 器
    
    
    
    
    件将 GBM 缓冲区映射到用户空间结构 omap_device* omap_dev = omap_device_new (DRM);//打开 OMAP 器件结构 omap_bo * omap_bo_= GBM_bo_from_dmabuf (omap_dev、GBM_bo_get_fd (bo));//从 OMAP 缓冲区创建 GBM_bo_map_void 缓冲区对象/ omap_map_map_map_bu_band/ omap_map_map_void。 将 DMA 缓冲器连接到 EGL/GL 以供 GPU
    
    EGLDisplay 使用=...;//我们必须具有有效的 EGLDisplay,在我的情况下由流水线配置
    
    // EGL_Linux_DMA_BUF_EXT -除了 NV12缓冲器之外,似乎不能用于任何其他内容,这些缓冲器不能用于呈现?
    
    EGLint attrib_list = EGL_none;//使用像素图
    PFNEGLCREATEIMAGEKHRPROC eglImageKHR =(PFNEGLCREATEIMAGEKHRPROC) eglGetProAddress ("eglCreateImageKHR");//解析 PIGCREATEIMAGEL 的地址
    、EGLHR_INL 函数、EGINL、EGKHR_EGINL、INL、INTRIM_EGKHR = GEL_EGL_EGINL、INTRIFORT_EGLEST_EGL_EGRECH //将 DMA 缓冲区附加到 EGLImage
    
    //现在可以使用标准 OpenGL API 附加缓冲区以进行渲染
    
    //创建纹理和帧缓冲区,我们可以使用渲染
    GLuint 帧格尔 EGL、textraEGL;
    glGenFrameBuffers (1、&framebufferEGL);
    glGenTextures (1、&framebufferEGL) (&T);
    
    //将 EGLImage 附加到纹理
    格式纹理(GL_tecture_2D、texureEGL);
    PFNGLEGLOIMAGETTEXURE2DOSPROC 纹理格式图像目标格式2格式纹理=(PFNGLEGLEIMAGETTEXGETTEXROC);"GE2GEDEG)
    纹理格式2格式(GLDE);
    
    
    //将纹理附加到帧缓冲
    区 glBindFrameBuffer (GL_framebuffer、framebufferEGL);
    glFramebufferTexture2D (GL_framebuffer、GL_COLOR_ATTACHENT0、GL_tuture_2D、 TextureEGL、0);
    // glBindFrameBuffer (GL_Framebuffer、0);
    
    // GL 命令现在将呈现给 DMA 缓冲区对象
    //我们可以使用映射的用户空间指针从 CPU 访问缓冲区
    //注意:需要 GPU/CPU 同步(glFlush、SyncFinish、eglClientSyncNV/eglWaitKHR
    ): 如果缓存了 GBM 缓冲区对象、则需要使缓存无效!