Segfault Creating CUDA Surface from Mapped EGL Frame

My ultimate goal is to convert UYVY frames coming from a v4l2-only source to GRAY8 for disparity.

tegra_multimedia_api sample #12 shows how to pull the v4l2 buffers and register them with CUDA, which works. However as soon as I try to pull the luminance plane from the mapped CUeglFrame I get a segfault. I’m assuming there’s either something I did wrong or creating a surface is not supported when the frame comes from NvEGLImageFromFd()

I already have a YUV->GRAY8 kernel using a luminance surface, but would the better solution be to just write a kernel that uses the EGLImage directly like in samples/common/algorithm/cuda/NvCudaProc.cpp?

Here is the code, based on tegra_multimedia_api sample #12 (camera_v4l2_cuda). The segfault happens at line 40, cuSurfObjectCreate().

if(poll(&fds, 1, 5000) > 0) {
    // Dequeue camera buff
    memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    v4l2_buf.memory = V4L2_MEMORY_DMABUF;
    if(ioctl(cam_fd, VIDIOC_DQBUF, &v4l2_buf) < 0)
        ORIGINATE_ERROR("Failed to dequeue camera buff.");

    // Cache sync for VIC operation
    NvBufferMemSyncForDevice(
        g_buff[v4l2_buf.index].dmabuff_fd, 0, (void**)&g_buff[v4l2_buf.index].start
    );

    // Pull EGL image
    EGLImageKHR egl_image = NvEGLImageFromFd(egl_display, g_buff[v4l2_buf.index].dmabuff_fd);

    // Register EGL image
    CUgraphicsResource pResource;
    status = cuGraphicsEGLRegisterImage(&pResource, egl_image, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE);
    if(status != CUDA_SUCCESS) {
        ORIGINATE_ERROR("Register image failed (CUresult %s)",
            getCudaErrorString(status));
    }

    // Map EGL image
    CUeglFrame cudaEGLFrame;
    status = cuGraphicsResourceGetMappedEglFrame(&cudaEGLFrame, pResource, 0, 0);
    if(status != CUDA_SUCCESS) {
        ORIGINATE_ERROR("Mapping image failed (CUresult %s)",
            getCudaErrorString(status));
    }

    CUDA_RESOURCE_DESC cudaResourceDesc;
    memset(&cudaResourceDesc, 0, sizeof(cudaResourceDesc));
    cudaResourceDesc.resType = CU_RESOURCE_TYPE_ARRAY;

    // Create a surface from the luminance plane
    CUsurfObject cudaSurfLuma;
    cudaResourceDesc.res.array.hArray = cudaEGLFrame.frame.pArray[0];
    <b>status = cuSurfObjectCreate(&cudaSurfLuma, &cudaResourceDesc); // <-- Segfault</b>
    if(status != CUDA_SUCCESS) {
        ORIGINATE_ERROR("Unable to create the luma surface object (CUresult %s)",
            getCudaErrorString(status));
    }

    /****************************************
     * Call kernel here on luminance plane. *
     ****************************************/

    status = cuSurfObjectDestroy(cudaSurfLuma);
    if(status != CUDA_SUCCESS) {
        ORIGINATE_ERROR("Unable to destroy the luma surface object (CUresult %s)",
            getCudaErrorString(status));
    }

    status = cuGraphicsUnregisterResource(pResource);
    if(status != CUDA_SUCCESS) {
        ORIGINATE_ERROR("Failed to unregister resource (CUresult %s)",
            getCudaErrorString(status));
    }

    NvDestroyEGLImage(egl_display, egl_image);

    // Enqueue camera buff
    if(ioctl(cam_fd, VIDIOC_QBUF, &v4l2_buf))
        ORIGINATE_ERROR("Failed to queue camera buffers");
}

Thanks!

I just realized that unlike NV12, which I was working with before. UYVY is not planar, so that’s probably why I can’t create a surface. I’ll just write another kernel.