Skip to content

Commit

Permalink
[GTK] Minibrowser does not render any content
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=254807

Reviewed by Žan Doberšek.

This might happen in systems with multiple GPUs enabled. The problem is that
we might end up using a different GPU than the one used by the
application in the UI process. This is because both GBMDevice and mesa
surfaceless platform use always the first device having a render node
returned by drmGetDevices2(). To make sure we use the right GPU
everywhere we need to get the GPU used by the UI process and send it
to the web process. Mesa surfaceless platform doesn't allow to change the
device, so we need to use GBM platform that receives the device as the
native display when initializing the EGL display. Surfaceless platform
is still used for swrast, because GBM requires a GPU device.

* Source/WebCore/PlatformGTK.cmake:
* Source/WebCore/SourcesGTK.txt:
* Source/WebCore/platform/graphics/PlatformDisplay.cpp:
(WebCore::PlatformDisplay::~PlatformDisplay):
(WebCore::PlatformDisplay::eglDevice):
(WebCore::PlatformDisplay::drmDeviceFile):
(WebCore::drmRenderNodeFromPrimaryDeviceFile):
(WebCore::PlatformDisplay::drmRenderNodeFile):
(WebCore::PlatformDisplay::gbmDevice):
* Source/WebCore/platform/graphics/PlatformDisplay.h:
* Source/WebCore/platform/graphics/egl/GLContext.cpp:
(WebCore::GLContext::getEGLConfig):
(WebCore::GLContext::createWindowContext):
(WebCore::GLContext::create):
(WebCore::GLContext::createSharing):
* Source/WebCore/platform/graphics/egl/PlatformDisplaySurfaceless.cpp: Renamed from Source/WebCore/platform/graphics/egl/PlatformDisplayHeadless.cpp.
* Source/WebCore/platform/graphics/egl/PlatformDisplaySurfaceless.h: Renamed from Source/WebCore/platform/graphics/egl/PlatformDisplayHeadless.h.
* Source/WebCore/platform/graphics/gbm/PlatformDisplayGBM.cpp: Added.
(WebCore::PlatformDisplayGBM::create):
(WebCore::PlatformDisplayGBM::PlatformDisplayGBM):
(WebCore::PlatformDisplayGBM::~PlatformDisplayGBM):
* Source/WebCore/platform/graphics/gbm/PlatformDisplayGBM.h: Added.
* Source/WebKit/Shared/WebProcessCreationParameters.cpp:
(WebKit::WebProcessCreationParameters::encode const):
(WebKit::WebProcessCreationParameters::decode):
* Source/WebKit/Shared/WebProcessCreationParameters.h:
* Source/WebKit/UIProcess/API/glib/WebKitProtocolHandler.cpp:
(WebKit::WebKitProtocolHandler::handleGPU):
* Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp:
(WebKit::WebProcessPool::platformInitializeWebProcess):
* Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp:
(WebKit::AcceleratedBackingStoreDMABuf::Surface::Surface):
* Source/WebKit/WebProcess/WebPage/AcceleratedSurface.cpp:
(WebKit::AcceleratedSurface::create):
* Source/WebKit/WebProcess/WebPage/gtk/AcceleratedSurfaceDMABuf.cpp:
(WebKit::AcceleratedSurfaceDMABuf::AcceleratedSurfaceDMABuf):
(WebKit::AcceleratedSurfaceDMABuf::RenderTargetEGLImage::create):
* Source/WebKit/WebProcess/glib/WebProcessGLib.cpp:
(WebKit::WebProcess::platformInitializeWebProcess):

Canonical link: https://commits.webkit.org/263061@main
  • Loading branch information
carlosgcampos committed Apr 18, 2023
1 parent 73d191b commit 5fa2966
Show file tree
Hide file tree
Showing 17 changed files with 341 additions and 51 deletions.
4 changes: 3 additions & 1 deletion Source/WebCore/PlatformGTK.cmake
Expand Up @@ -47,7 +47,9 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS

platform/glib/ApplicationGLib.h

platform/graphics/egl/PlatformDisplayHeadless.h
platform/graphics/egl/PlatformDisplaySurfaceless.h

platform/graphics/gbm/PlatformDisplayGBM.h

platform/graphics/gtk/GdkCairoUtilities.h

Expand Down
3 changes: 2 additions & 1 deletion Source/WebCore/SourcesGTK.txt
Expand Up @@ -74,14 +74,15 @@ platform/graphics/egl/GLContext.cpp @no-unify
platform/graphics/egl/GLContextLibWPE.cpp @no-unify
platform/graphics/egl/GLContextWayland.cpp @no-unify
platform/graphics/egl/GLContextX11.cpp @no-unify
platform/graphics/egl/PlatformDisplayHeadless.cpp
platform/graphics/egl/PlatformDisplaySurfaceless.cpp

platform/graphics/gbm/GBMBufferSwapchain.cpp
platform/graphics/gbm/GBMDevice.cpp
platform/graphics/gbm/GraphicsContextGLANGLELinux.cpp
platform/graphics/gbm/GraphicsContextGLFallback.cpp
platform/graphics/gbm/GraphicsContextGLGBM.cpp
platform/graphics/gbm/GraphicsContextGLGBMTextureMapper.cpp
platform/graphics/gbm/PlatformDisplayGBM.cpp

platform/graphics/gtk/ColorGtk.cpp
platform/graphics/gtk/DisplayRefreshMonitorGtk.cpp
Expand Down
117 changes: 117 additions & 0 deletions Source/WebCore/platform/graphics/PlatformDisplay.cpp
Expand Up @@ -80,6 +80,18 @@
#include <wtf/NeverDestroyed.h>
#endif

#if USE(EGL) && USE(GBM)
#include <fcntl.h>
#include <gbm.h>
#include <unistd.h>
#include <wtf/SafeStrerror.h>
#include <wtf/StdLibExtras.h>
#include <xf86drm.h>
#ifndef EGL_DRM_RENDER_NODE_FILE_EXT
#define EGL_DRM_RENDER_NODE_FILE_EXT 0x3377
#endif
#endif

#if USE(ATSPI)
#include <wtf/glib/GUniquePtr.h>
#endif
Expand Down Expand Up @@ -221,6 +233,10 @@ PlatformDisplay::~PlatformDisplay()
#if PLATFORM(GTK)
if (m_sharedDisplay)
g_signal_handlers_disconnect_by_data(m_sharedDisplay.get(), this);
#endif
#if USE(EGL) && USE(GBM)
if (m_gbm.device.has_value() && m_gbm.device.value())
gbm_device_destroy(m_gbm.device.value());
#endif
if (s_sharedDisplayForCompositing == this)
s_sharedDisplayForCompositing = nullptr;
Expand Down Expand Up @@ -402,6 +418,107 @@ bool PlatformDisplay::destroyEGLImage(EGLImage image) const
#endif
}

#if USE(GBM)
EGLDeviceEXT PlatformDisplay::eglDevice()
{
if (!GLContext::isExtensionSupported(eglQueryString(nullptr, EGL_EXTENSIONS), "EGL_EXT_device_query"))
return nullptr;

if (!m_eglDisplayInitialized)
const_cast<PlatformDisplay*>(this)->initializeEGLDisplay();

EGLDeviceEXT eglDevice;
if (eglQueryDisplayAttribEXT(m_eglDisplay, EGL_DEVICE_EXT, reinterpret_cast<EGLAttrib*>(&eglDevice)))
return eglDevice;

return nullptr;
}

const String& PlatformDisplay::drmDeviceFile()
{
if (!m_drmDeviceFile.has_value()) {
if (EGLDeviceEXT device = eglDevice()) {
if (GLContext::isExtensionSupported(eglQueryDeviceStringEXT(device, EGL_EXTENSIONS), "EGL_EXT_device_drm")) {
m_drmDeviceFile = String::fromUTF8(eglQueryDeviceStringEXT(device, EGL_DRM_DEVICE_FILE_EXT));
return m_drmDeviceFile.value();
}
}
m_drmDeviceFile = String();
}

return m_drmDeviceFile.value();
}

static String drmRenderNodeFromPrimaryDeviceFile(const String& primaryDeviceFile)
{
if (primaryDeviceFile.isEmpty())
return { };

drmDevicePtr devices[64];
memset(devices, 0, sizeof(devices));

int numDevices = drmGetDevices2(0, devices, std::size(devices));
if (numDevices <= 0)
return { };

String renderNodeDeviceFile;
for (int i = 0; i < numDevices; ++i) {
drmDevice* device = devices[i];
if (!(device->available_nodes & (1 << DRM_NODE_PRIMARY | 1 << DRM_NODE_RENDER)))
continue;

if (String::fromUTF8(device->nodes[DRM_NODE_PRIMARY]) == primaryDeviceFile) {
renderNodeDeviceFile = String::fromUTF8(device->nodes[DRM_NODE_RENDER]);
break;
}
}
drmFreeDevices(devices, numDevices);

return renderNodeDeviceFile;
}

const String& PlatformDisplay::drmRenderNodeFile()
{
if (!m_drmRenderNodeFile.has_value()) {
if (EGLDeviceEXT device = eglDevice()) {
if (GLContext::isExtensionSupported(eglQueryDeviceStringEXT(device, EGL_EXTENSIONS), "EGL_EXT_device_drm_render_node")) {
m_drmRenderNodeFile = String::fromUTF8(eglQueryDeviceStringEXT(device, EGL_DRM_RENDER_NODE_FILE_EXT));
return m_drmRenderNodeFile.value();
}

// If EGL_EXT_device_drm_render_node is not present, try to get the render node using DRM API.
m_drmRenderNodeFile = drmRenderNodeFromPrimaryDeviceFile(drmDeviceFile());
} else
m_drmRenderNodeFile = String();
}

return m_drmRenderNodeFile.value();
}

struct gbm_device* PlatformDisplay::gbmDevice()
{
if (!m_gbm.device.has_value()) {
const char* envDeviceFile = getenv("WEBKIT_WEB_RENDER_DEVICE_FILE");
String deviceFile = envDeviceFile && *envDeviceFile ? String::fromUTF8(envDeviceFile) : drmRenderNodeFile();
if (!deviceFile.isEmpty()) {
m_gbm.deviceFD = UnixFileDescriptor { open(deviceFile.utf8().data(), O_RDWR | O_CLOEXEC), UnixFileDescriptor::Adopt };
if (m_gbm.deviceFD) {
m_gbm.device = gbm_create_device(m_gbm.deviceFD.value());
if (m_gbm.device.value())
return m_gbm.device.value();

WTFLogAlways("Failed to create GBM device for render device: %s: %s", deviceFile.utf8().data(), safeStrerror(errno).data());
m_gbm.deviceFD = { };
} else
WTFLogAlways("Failed to open DRM render device %s: %s", deviceFile.utf8().data(), safeStrerror(errno).data());
}
m_gbm.device = nullptr;
}

return m_gbm.device.value();
}
#endif

#endif // USE(EGL)

#if USE(LCMS)
Expand Down
30 changes: 26 additions & 4 deletions Source/WebCore/platform/graphics/PlatformDisplay.h
Expand Up @@ -36,6 +36,11 @@ typedef void *EGLContext;
typedef void *EGLDisplay;
typedef void *EGLImage;
typedef unsigned EGLenum;
#if USE(GBM)
#include <wtf/unix/UnixFileDescriptor.h>
typedef void *EGLDeviceEXT;
struct gbm_device;
#endif
#endif

#if PLATFORM(GTK)
Expand Down Expand Up @@ -80,7 +85,10 @@ class PlatformDisplay {
WPE,
#endif
#if USE(EGL)
Headless,
Surfaceless,
#if USE(GBM)
GBM,
#endif
#endif
};

Expand All @@ -105,6 +113,11 @@ class PlatformDisplay {

EGLImage createEGLImage(EGLContext, EGLenum target, EGLClientBuffer, const Vector<EGLAttrib>&) const;
bool destroyEGLImage(EGLImage) const;
#if USE(GBM)
const String& drmDeviceFile();
const String& drmRenderNodeFile();
struct gbm_device* gbmDevice();
#endif
#endif

#if ENABLE(VIDEO) && USE(GSTREAMER_GL)
Expand Down Expand Up @@ -138,10 +151,16 @@ class PlatformDisplay {
virtual void initializeEGLDisplay();

EGLDisplay m_eglDisplay;
#endif

#if USE(EGL)
std::unique_ptr<GLContext> m_sharingGLContext;

#if USE(GBM)
std::optional<String> m_drmDeviceFile;
std::optional<String> m_drmRenderNodeFile;
struct {
WTF::UnixFileDescriptor deviceFD;
std::optional<struct gbm_device*> device;
} m_gbm;
#endif
#endif

#if USE(LCMS)
Expand All @@ -159,6 +178,9 @@ class PlatformDisplay {

#if USE(EGL)
void terminateEGLDisplay();
#if USE(GBM)
EGLDeviceEXT eglDevice();
#endif

bool m_eglDisplayInitialized { false };
int m_eglMajorVersion { 0 };
Expand Down
19 changes: 14 additions & 5 deletions Source/WebCore/platform/graphics/egl/GLContext.cpp
Expand Up @@ -146,7 +146,7 @@ bool GLContext::getEGLConfig(PlatformDisplay& platformDisplay, EGLConfig* config

switch (surfaceType) {
case GLContext::Surfaceless:
if (platformDisplay.type() == PlatformDisplay::Type::Headless)
if (platformDisplay.type() == PlatformDisplay::Type::Surfaceless)
attributeList[13] = EGL_PBUFFER_BIT;
else
attributeList[13] = EGL_WINDOW_BIT;
Expand Down Expand Up @@ -270,7 +270,10 @@ std::unique_ptr<GLContext> GLContext::createWindowContext(GLNativeWindowType win
surface = createWindowSurfaceWPE(display, config, window);
break;
#endif // USE(WPE_RENDERER)
case PlatformDisplay::Type::Headless:
#if USE(GBM)
case PlatformDisplay::Type::GBM:
#endif
case PlatformDisplay::Type::Surfaceless:
RELEASE_ASSERT_NOT_REACHED();
}

Expand Down Expand Up @@ -359,7 +362,7 @@ std::unique_ptr<GLContext> GLContext::create(GLNativeWindowType window, Platform
}

EGLContext eglSharingContext = platformDisplay.sharingGLContext() ? static_cast<GLContext*>(platformDisplay.sharingGLContext())->m_context : EGL_NO_CONTEXT;
if (platformDisplay.type() == PlatformDisplay::Type::Headless) {
if (platformDisplay.type() == PlatformDisplay::Type::Surfaceless) {
auto context = createSurfacelessContext(platformDisplay, eglSharingContext);
if (!context)
WTFLogAlways("Could not create EGL surfaceless context: %s.", lastErrorString());
Expand All @@ -386,7 +389,10 @@ std::unique_ptr<GLContext> GLContext::create(GLNativeWindowType window, Platform
context = createWPEContext(platformDisplay, eglSharingContext);
break;
#endif
case PlatformDisplay::Type::Headless:
#if USE(GBM)
case PlatformDisplay::Type::GBM:
#endif
case PlatformDisplay::Type::Surfaceless:
RELEASE_ASSERT_NOT_REACHED();
}
}
Expand Down Expand Up @@ -443,7 +449,10 @@ std::unique_ptr<GLContext> GLContext::createSharing(PlatformDisplay& platformDis
context = createWPEContext(platformDisplay);
break;
#endif
case PlatformDisplay::Type::Headless:
#if USE(GBM)
case PlatformDisplay::Type::GBM:
#endif
case PlatformDisplay::Type::Surfaceless:
break;
}
}
Expand Down
Expand Up @@ -24,20 +24,20 @@
*/

#include "config.h"
#include "PlatformDisplayHeadless.h"
#include "PlatformDisplaySurfaceless.h"

#if USE(EGL)
#include "GLContext.h"
#include <epoxy/egl.h>

namespace WebCore {

std::unique_ptr<PlatformDisplayHeadless> PlatformDisplayHeadless::create()
std::unique_ptr<PlatformDisplaySurfaceless> PlatformDisplaySurfaceless::create()
{
return std::unique_ptr<PlatformDisplayHeadless>(new PlatformDisplayHeadless());
return std::unique_ptr<PlatformDisplaySurfaceless>(new PlatformDisplaySurfaceless());
}

PlatformDisplayHeadless::PlatformDisplayHeadless()
PlatformDisplaySurfaceless::PlatformDisplaySurfaceless()
{
#if PLATFORM(GTK)
PlatformDisplay::setSharedDisplayForCompositing(*this);
Expand All @@ -52,7 +52,7 @@ PlatformDisplayHeadless::PlatformDisplayHeadless()
PlatformDisplay::initializeEGLDisplay();
}

PlatformDisplayHeadless::~PlatformDisplayHeadless()
PlatformDisplaySurfaceless::~PlatformDisplaySurfaceless()
{
}

Expand Down
Expand Up @@ -30,15 +30,15 @@

namespace WebCore {

class PlatformDisplayHeadless final : public PlatformDisplay {
class PlatformDisplaySurfaceless final : public PlatformDisplay {
public:
static std::unique_ptr<PlatformDisplayHeadless> create();
static std::unique_ptr<PlatformDisplaySurfaceless> create();

virtual ~PlatformDisplayHeadless();
virtual ~PlatformDisplaySurfaceless();
private:
PlatformDisplayHeadless();
PlatformDisplaySurfaceless();

Type type() const override { return PlatformDisplay::Type::Headless; }
Type type() const override { return PlatformDisplay::Type::Surfaceless; }
};

} // namespace WebCore
Expand Down

0 comments on commit 5fa2966

Please sign in to comment.