chromiumembedded / cef

Chromium Embedded Framework (CEF). A simple framework for embedding Chromium-based browsers in other applications.
https://bitbucket.org/chromiumembedded/cef/
Other
3.27k stars 456 forks source link

osr: linux: Add cefclient implementation for OnAcceleratedPaint #3687

Open magreenblatt opened 5 months ago

magreenblatt commented 5 months ago

Is your feature request related to a problem? Please describe. OnAcceleratedPaint support was added in this PR (issue #2575). It does not include a cefclient implementation for Linux.

Describe the solution you'd like Add cefclient implementation for OnAcceleratedPaint on Linux.

TwentyPast4 commented 2 months ago

Would really appreciate this as well. Here is a snippet of what I'm doing right now, which looks like it might work, but it doesn't. The way the EGL display is created is x11 specific, but OnAcceleratedPaint is not, it's window manager agnostic. I get EGL_BAD_MATCH at eglCreateImage, which makes me think the gl display I'm creating is no good. I don't know what else I should be doing though - there is no way for me to get the same EGL display that the renderer process of chrome is using. Here's my code for what it's worth:

Window getWindowHandle() {
// code to get the x11 window handle
}

Display* getDisplayHandle() {
// code to get the x11 Display the app is running in
}

LinuxBrowserWindow::LinuxBrowserWindow() {

        CefWindowInfo window_info;
    window_info.SetAsWindowless(getWindowHandle()); // set parent window to the window I'm drawing to
    window_info.shared_texture_enabled = true; // enable OnAcceleratedPaint

    // ... create egl display and initialize it, using the x11 display, so that I can use it in OnAcceleratedPaint
    egl_display = eglGetPlatformDisplay(EGL_PLATFORM_X11_KHR, getDisplayHandle(), NULL);

    // initialize the EGL display connection
    eglInitialize(egl_display, NULL, NULL);

    // browser =  CefBrowserHost::CreateBrowserSync(.....)
}

constexpr EGLint kPlaneFDAttrs[] = {
    EGL_DMA_BUF_PLANE0_FD_EXT,
    EGL_DMA_BUF_PLANE1_FD_EXT,
    EGL_DMA_BUF_PLANE2_FD_EXT,
    EGL_DMA_BUF_PLANE3_FD_EXT,
};
constexpr EGLint kPlaneOffsetAttrs[] = {
    EGL_DMA_BUF_PLANE0_OFFSET_EXT,
    EGL_DMA_BUF_PLANE1_OFFSET_EXT,
    EGL_DMA_BUF_PLANE2_OFFSET_EXT,
    EGL_DMA_BUF_PLANE3_OFFSET_EXT,
};

constexpr EGLint kPlanePitchAttrs[] = {
    EGL_DMA_BUF_PLANE0_PITCH_EXT,
    EGL_DMA_BUF_PLANE1_PITCH_EXT,
    EGL_DMA_BUF_PLANE2_PITCH_EXT,
    EGL_DMA_BUF_PLANE3_PITCH_EXT,
};

constexpr EGLint kPlaneLoModifierAttrs[] = {
    EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
    EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
    EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
    EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
};

constexpr EGLint kPlaneHiModifierAttrs[] = {
    EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
    EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
    EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
    EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
};

void LinuxBrowserWindow::OnAcceleratedPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const CefAcceleratedPaintInfo& info)
{
    int fourcc = 0;
        // the format is reversed in cef, so I think this swap is correct
        // see https://github.com/chromiumembedded/cef/blob/master/libcef/browser/osr/video_consumer_osr.cc#L111
    switch (info.format)
    {
        case CEF_COLOR_TYPE_RGBA_8888: fourcc = DRM_FORMAT_ABGR8888; break;
        case CEF_COLOR_TYPE_BGRA_8888: fourcc = DRM_FORMAT_BGRA8888; break;
    }

    if (!fourcc || dirtyRects.size() != 1)
        return;

    const CefRect& rect = dirtyRects.front();
    std::vector<EGLAttrib> attribute_list = { EGL_WIDTH, rect.width, EGL_HEIGHT, rect.height, EGL_LINUX_DRM_FOURCC_EXT, fourcc };

    for (int i = 0; i < info.plane_count; ++i)
    {
        attribute_list.insert(attribute_list.end(), { kPlaneFDAttrs[i], info.planes[i].fd, kPlaneOffsetAttrs[i], (EGLint)info.planes[i].offset, kPlanePitchAttrs[i],
                                                      (EGLint)info.planes[i].stride });
        if (info.modifier != DRM_FORMAT_MOD_INVALID)
        {
            attribute_list.insert(attribute_list.end(), { kPlaneLoModifierAttrs[i], static_cast<uint32_t>(info.modifier & 0xffffffff), kPlaneHiModifierAttrs[i],
                                                          static_cast<uint32_t>(info.modifier >> 32) });
        }
    }
    attribute_list.push_back(EGL_NONE);

    EGLImage image = eglCreateImage(egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, (EGLClientBuffer) nullptr, attribute_list.data());
    if (image == EGL_NO_IMAGE)
    {
        printf("Failed to create EGLImage from DMA buffer (0x%x).\n", eglGetError());
        return;
    }

    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);

    // the 'texture' should be good to use from here!
}
reitowo commented 2 months ago

It was a mess when we test around linux support when implementing that PR. The linux desktop backend X11 and Wayland and all multi Intel + nVidia hybrid graphic card driver support was just a mess. So we just leave it to the next hero :)

TwentyPast4 commented 1 month ago

It was a mess when we test around linux support when implementing that PR. The linux desktop backend X11 and Wayland and all multi Intel + nVidia hybrid graphic card driver support was just a mess. So we just leave it to the next hero :)

Aye that be true... Hope such a hero can be found. I'll try to debug what I have to figure out what exactly is preventing it from working, but there's not much further to go, as the driver isn't that keen to tell me what's going wrong. This is what I used as a reference for my solution, if such a hero is born to take next steps: https://blaztinn.gitlab.io/post/dmabuf-texture-sharing/

adriannepilleboue commented 1 week ago

Hi!

I just wanted to give some feedback on this topic. I made it work on Linux for my project, using :

On the small difficulties I encounter, there is:

Anyways, thanks a lot for the OnAcceleratedPaint PR, it works very well in my case!