cef icon indicating copy to clipboard operation
cef copied to clipboard

osr: linux: Add cefclient implementation for OnAcceleratedPaint

Open magreenblatt opened this issue 10 months ago • 4 comments

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.

magreenblatt avatar Apr 23 '24 17:04 magreenblatt

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!
}

TwentyPast4 avatar Jul 19 '24 10:07 TwentyPast4

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 :)

reitowo avatar Aug 01 '24 05:08 reitowo

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/

TwentyPast4 avatar Aug 05 '24 16:08 TwentyPast4

Hi!

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

  • CEF 127.3.5 (OnAcceleratedPaint / DMABuf)
  • Vulkan
  • GLFW window on X11
  • Intel graphics

On the small difficulties I encounter, there is:

  • I wanted to use GTK4 for Vulkan support, but there was some conflict with GTK3 that seems to be called in CEF too. So I switched to GLFW.
  • NVIDIA was never working, but it seems that using DMABuf with Vulkan is not really well supported by the driver anyway (it's not related to CEF). Vulkan allows to choose which device can be used for rendering, which make NVIDIA/Intel hell a bit simpler.
  • Vulkan seems to close the passed DMABuf FD, while CEF is still expecting it to be opened. So I had to call dup() on it at the beginning of OnAcceleratedPaint()
  • CEF rendered texture is already in sRGB, so it had to be imported in this color space too in Vulkan.

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

adriannepilleboue avatar Sep 19 '24 09:09 adriannepilleboue