NvEGLRenderer with transparent background

Hi!

I am working on a project that creates two NvEglRenderer objects therefore I have two X windows.
I want to achieve transparency on the upper window. I managed to modify constructor of NvEglRenderer in a way it creates XWindow with transparent background as suggested here.
Window is created successfully and is in fact transparent but the problem occurs in NvEglRenderer::renderThread.
To be more specific here:

renderer->egl_surface = eglCreateWindowSurface(renderer->egl_display, renderer->egl_config,
                (EGLNativeWindowType) renderer->x_window, NULL);
    if (renderer->egl_surface == EGL_NO_SURFACE)
    {
        COMP_ERROR_MSG("Error in creating egl surface " << eglGetError());
        goto error;
    }

eglGetError() throws EGL_BAD_MATCH error. I have tried to modify the egl config but without luck.

Has anyone succeeded in doing something similar?

I am adding the code of modified NvEglRenderer constructor.

NvEglRenderer::NvEglRenderer(const char *name, uint32_t width, uint32_t height,
        uint32_t x_offset, uint32_t y_offset, bool transparent)
        :NvElement(name, valid_fields)
{
    this->transparent = transparent;
    int depth;
    int screen_num;
    XSetWindowAttributes window_attributes;
    x_window = 0;
    x_display = NULL;

    texture_id = 0;
    gc = NULL;
    fontinfo = NULL;

    egl_surface = EGL_NO_SURFACE;
    egl_context = EGL_NO_CONTEXT;
    egl_display = EGL_NO_DISPLAY;
    egl_config = NULL;

    memset(&last_render_time, 0, sizeof(last_render_time));
    stop_thread = false;
    render_thread = 0;
    render_fd = 0;

    memset(overlay_str, 0, sizeof(overlay_str));
    overlay_str_x_offset = 0;
    overlay_str_y_offset = 0;

    pthread_mutex_init(&render_lock, NULL);
    pthread_cond_init(&render_cond, NULL);

    setFPS(30);

    if (initEgl() < 0)
    {
        COMP_ERROR_MSG("Error getting EGL function addresses");
        goto error;
    }

    x_display = XOpenDisplay(NULL);
    if (NULL == x_display)
    {
        COMP_ERROR_MSG("Error in opening display");
        goto error;
    }

    screen_num = DefaultScreen(x_display);
    if (!width || !height)
    {
        width = DisplayWidth(x_display, screen_num);
        height = DisplayHeight(x_display, screen_num);
        x_offset = 0;
        y_offset = 0;
    }
    COMP_INFO_MSG("Setting Screen width " << width << " height " << height);

    COMP_DEBUG_MSG("Display opened successfully " << (size_t) x_display);

    if (transparent)
    {
        Visual *visual = DefaultVisual(x_display, 0);

        XVisualInfo vinfo;
        XMatchVisualInfo(x_display, DefaultScreen(x_display), 32, TrueColor, &vinfo);

        window_attributes.colormap = XCreateColormap(x_display, DefaultRootWindow(x_display), 
                vinfo.visual, AllocNone);
        window_attributes.border_pixel = 0;
        window_attributes.background_pixel = 0x80800000; // Red, semi-transparent
        window_attributes.override_redirect = 1;

        x_window = XCreateWindow(x_display, DefaultRootWindow(x_display), x_offset, y_offset,
                width, height, 0, 32, InputOutput, vinfo.visual,
                CWColormap | CWBorderPixel |  CWBackPixel | CWOverrideRedirect , &window_attributes);

        XSelectInput(x_display, (int32_t) x_window, ExposureMask);
        XMapWindow(x_display, (int32_t) x_window);
        gc = XCreateGC(x_display, x_window, 0, NULL);
    }
    else
    {
        depth = DefaultDepth(x_display, DefaultScreen(x_display));

        window_attributes.background_pixel =
            BlackPixel(x_display, DefaultScreen(x_display));

        window_attributes.override_redirect = 1;

        x_window = XCreateWindow(x_display,
                                DefaultRootWindow(x_display), x_offset,
                                y_offset, width, height,
                                0,
                                depth, CopyFromParent,
                                CopyFromParent,
                                (CWBackPixel | CWOverrideRedirect),
                                &window_attributes);

        XSelectInput(x_display, (int32_t) x_window, ExposureMask);
        XMapWindow(x_display, (int32_t) x_window);
        gc = XCreateGC(x_display, x_window, 0, NULL);
        
        XSetForeground(x_display, gc,
                    WhitePixel(x_display, DefaultScreen(x_display)) );
        fontinfo = XLoadQueryFont(x_display, "9x15bold");
    }
    
    pthread_mutex_lock(&render_lock);
    pthread_create(&render_thread, NULL, renderThread, this);
    pthread_setname_np(render_thread, "EglRenderer");
    pthread_cond_wait(&render_cond, &render_lock);
    pthread_mutex_unlock(&render_lock);

    if(isInError())
    {
        pthread_join(render_thread, NULL);
        goto error;
    }

    COMP_DEBUG_MSG("Renderer started successfully")
    return;

error:
    COMP_ERROR_MSG("Got ERROR closing display");
    is_in_error = 1;
}

Thank you in advance!

Hi,
This looks to be about how to use X functions. Since we don’t have much experience in enabling transparent background, this would need other users to share experience.

Another solution is to have single X window and use NvBufSurface APIs to achieve the same behavior. We have NvBufSurfTransformMultiInputBufCompositeBlend() which supports alpha blending. And you can use CUDA programming to access each pixel of NvbufSurface like:
Resources for custom nvivafilter for Jetpack 5.1.1 Jetson NX - #17 by DaneLLL

Hi, @DaneLLL !

Thank you for quick response! I tried using the function you suggested but cannot lose the NvBufSurfTransformError_Invalid_Params error.

I am sending piece of code that I created just to test the function.
Please let me know where am I making mistakes.

NvBufSurface* surfaces[2];
        NvBufSurface* joined_surface;

        // Initialize buffers
        NvBufSurfaceCreateParams createParams;
        createParams.gpuId = 0;
        createParams.colorFormat = NVBUF_COLOR_FORMAT_RGBA;
        createParams.height = SCREEN_SIZE.height();
        createParams.width = SCREEN_SIZE.width();
        createParams.layout = NVBUF_LAYOUT_PITCH;
        createParams.isContiguous = false;
        createParams.memType = NVBUF_MEM_DEFAULT;

        if(NvBufSurfaceCreate(&surfaces[0],1,&createParams) != 0) printf("Cannot create BufSurface\n");

        if(NvBufSurfaceCreate(&surfaces[1],1,&createParams) != 0) printf("Cannot create BufSurface\n");
        
        if(NvBufSurfaceCreate(&joined_surface,1,&createParams) != 0) printf("Cannot create BufSurface\n");

        NvBufSurfTransformCompositeBlendParamsEx para;
        float alpha[] = {0.5f, 0.5f};
        NvBufSurfTransform_Inter filters[] = {NvBufSurfTransformInter_Default};
        NvBufSurfTransformRect rects[2];
        NvBufSurfTransform_ColorParams color_bg = {1.0,1.0,0.0,1.0};

        rects[0].height = 1080;
        rects[0].width = 1920;
        rects[0].top = 0;
        rects[0].left = 0;
        
        rects[1].height = 1080;
        rects[1].width = 1920;
        rects[1].top = 0;
        rects[1].left = 0;
        
        para.alpha = alpha;
        para.composite_blend_filter = filters;
        para.dst_comp_rect = rects; // Take only the first one
        para.src_comp_rect = rects;
        para.params.color_bg = &color_bg;
        para.params.composite_blend_flag = 0;
        para.params.composite_blend_filter = NvBufSurfTransformInter_Default;
        para.params.input_buf_count = 2;
        para.params.perform_blending = 0;

        int res = NvBufSurfTransformMultiInputBufCompositeBlend(surfaces, joined_surface, &para);

Sorry for the late response.
Is this still an issue to support? Any result can be shared?

The source code of nvcompositor plugin is public. You may also refer to it:

Jetson Linux | NVIDIA Developer
Driver Package (BSP) Sources

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.