在没有 GPU 的情况下以无头 chrome 渲染 WebGL 图像

Posted

技术标签:

【中文标题】在没有 GPU 的情况下以无头 chrome 渲染 WebGL 图像【英文标题】:Rendering WebGL image in headless chrome without a GPU 【发布时间】:2018-06-09 05:53:54 【问题描述】:

我正在尝试在没有 GPU 的 Linux 服务器上导出使用 WebGL 渲染的图像。为此,我使用的是无头 Chrome,但导出的图像是黑色的(example exported image、taking a screenshot of page shows its just canvas that is black)。我希望有人帮助我弄清楚为什么会发生这种情况。

要导出图像,我将图像渲染到画布中,通过canvas.toDataURL('image/jpeg') 导出数据,然后将数据发布到服务器。我使用 Pixi.js 进行渲染,如果我使用画布渲染器,那么一切都可以在服务器上运行;这是 WebGL 渲染不起作用。值得注意的是,WebGL 渲染在 Macbook 上的 Chrome 63 中运行良好。

为了控制 Chrome,我使用了Puppeteer。我所做的只是打开一个页面,等待一秒钟,然后再次关闭它:

puppeteer
  .launch(
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
    ],
  )
  .then(browser => 
    return browser.newPage().then(page => 
      return page
        .goto(url)
        .then(() => page.waitFor(1000))
        .then(() => browser.close())
        .catch(err => console.error('Failed', err));
    );
  )

这些是 puppeteer 传递给 Chrome 的参数:

[
  '--disable-background-networking',
  '--disable-background-timer-throttling',
  '--disable-client-side-phishing-detection',
  '--disable-default-apps',
  '--disable-extensions',
  '--disable-hang-monitor',
  '--disable-popup-blocking',
  '--disable-prompt-on-repost',
  '--disable-sync',
  '--disable-translate',
  '--metrics-recording-only',
  '--no-first-run',
  '--remote-debugging-port=0',
  '--safebrowsing-disable-auto-update',
  '--enable-automation',
  '--password-store=basic',
  '--use-mock-keychain',
  '--user-data-dir=/tmp/puppeteer_dev_profile-GhEAXZ',
  '--headless',
  '--disable-gpu',
  '--hide-scrollbars',
  '--mute-audio',
  '--no-sandbox',
  '--disable-setuid-sandbox'
]

swiftshader author said in June headless WebGL rendering is possible 似乎是confirmed by this Chromium issue,所以我想我错过了一些东西。有没有人知道我做错了什么?

我尝试过的几件事:

Not passing in --disable-gpu --use-gl=swiftshader-webgl, --use-gl=swiftshader, --use-gl=osmesa 全屏截图看看它是否只是画布。整个屏幕都是黑色的。

版本

Chrome:linux-515411 傀儡师:0.13.0 节点:8.2.1 Linux:CentOS 7

这是我需要在我的服务器上安装才能运行 chrome (Source)

yum install cups-libs dbus-glib libXrandr libXcursor libXinerama cairo cairo-gobject pango ffmpeg
rpm -ivh --nodeps http://mirror.centos.org/centos/7/os/x86_64/Packages/atk-2.22.0-3.el7.x86_64.rpm
rpm -ivh --nodeps http://mirror.centos.org/centos/7/os/x86_64/Packages/at-spi2-atk-2.22.0-2.el7.x86_64.rpm
rpm -ivh --nodeps http://mirror.centos.org/centos/7/os/x86_64/Packages/at-spi2-core-2.22.0-1.el7.x86_64.rpm
rpm -ivh --nodeps http://dl.fedoraproject.org/pub/archive/fedora/linux/releases/20/Fedora/x86_64/os/Packages/g/GConf2-3.2.6-7.fc20.x86_64.rpm
rpm -ivh --nodeps http://dl.fedoraproject.org/pub/archive/fedora/linux/releases/20/Fedora/x86_64/os/Packages/l/libXScrnSaver-1.2.2-6.fc20.x86_64.rpm
rpm -ivh --nodeps http://dl.fedoraproject.org/pub/archive/fedora/linux/releases/20/Fedora/x86_64/os/Packages/l/libxkbcommon-0.3.1-1.fc20.x86_64.rpm
rpm -ivh --nodeps http://dl.fedoraproject.org/pub/archive/fedora/linux/releases/20/Fedora/x86_64/os/Packages/l/libwayland-client-1.2.0-3.fc20.x86_64.rpm
rpm -ivh --nodeps http://dl.fedoraproject.org/pub/archive/fedora/linux/releases/20/Fedora/x86_64/os/Packages/l/libwayland-cursor-1.2.0-3.fc20.x86_64.rpm
rpm -ivh --nodeps http://dl.fedoraproject.org/pub/archive/fedora/linux/releases/20/Fedora/x86_64/os/Packages/g/gtk3-3.10.4-1.fc20.x86_64.rpm
rpm -ivh --nodeps http://dl.fedoraproject.org/pub/archive/fedora/linux/releases/16/Fedora/x86_64/os/Packages/gdk-pixbuf2-2.24.0-1.fc16.x86_64.rpm

【问题讨论】:

你能提供更多关于你的硬件配置的细节吗? AFAIK,WebGL 确实需要 GPU。许多(大多数?)最近的计算机确实包含英特尔“集成图形”形式的 GPU,如果您不过度推动它们,这对于 3D 渲染来说绰绰有余,但是没有 GPU 访问权限的 VM 将是一个问题。 .. 我们的服务器没有 GPU。有很多文档表明它是可能的:“SwiftShader 是基于 CPU 的高性能 OpenGL ES 实现”(github.com/google/swiftshader)blog.chromium.org/2016/06/…。添加 Swiftshader bugs.chromium.org/p/chromium/issues/detail?id=630728 的 Chromium 问题。 Chromium 文档讨论 GPU 不可用时的软件合成器chromium.org/developers/design-documents/… 你真的安装了 Swiftshader 吗?在您的帖子中没有看到任何关于此的内容?另外,你有办法捕获 Chrome 的控制台吗? 将 --disable-gpu 传递给我的 chrome 选项允许我呈现一个 html 画布饼图。非常感谢您的提示! 我运行的服务(无浏览器)似乎没有 WebGL 的问题(除了速度慢,但这完全取决于您分配的资源)。你可以看一个例子here。 【参考方案1】:

我通过添加解决了这个问题

'--use-gl=angle' 

到无头镀铬设置。 我还删除了'--disable-gpu',因为我认为这是修复一些错误的临时解决方法,不再需要。

您可以在 Chrome 源代码中找到与“角度”here 不同的选项(在 Chrome 源代码中找到这个是我最不希望看到的!)

【讨论】:

【参考方案2】:

preserveDrawingBuffer 设置为true 为我解决了这个问题

【讨论】:

【参考方案3】:

有一个未解决的错误会影响没有 X11 库的系统:crbug.com/swiftshader/79。它会阻止 Chrome OS 与 SwiftShader 一起运行,但同样的问题也会发生在不支持 X11 的无头 Linux 系统上。

幸运的是,安装 X11 并运行它应该是可行的。我不能 100% 确定哪些软件包提供了必要的库,但试试这些:xorg xserver-xorg xvfb libx11-dev libxext-dev libxext-dev:i386

最终,SwiftShader 错误将得到修复,因此它不再需要 X11。

【讨论】:

首先,感谢您的帮助!我安装了 deps 并检查了它们是否可以动态加载,但问题仍然存在(gist.github.com/jhollingworth/24c57fe654d5f9b591d577281c7992c4)。我在带有 GPU 日志记录的 chromium 调试版本中运行了一个简单的 WebGL 示例 (gist.github.com/jhollingworth/f9bae6a65be1f61eadc4c538c5ed983c):gist.github.com/jhollingworth/0b1843dc4417fd282d238cb6ef46628b。 GL_RENDERER = Google SwiftShaderGL_VERSION = OpenGL ES 3.0 SwiftShader 3.3.0.2。我假设这意味着 Swiftshader 已加载?对我可以尝试的其他事情有什么想法吗? 我想知道的一件事是,每次调用toDataUrl() 的时间从 30 毫秒到 500 毫秒不等,具体取决于场景的复杂性(例如,加载图像然后转换它比gl.clearColor 花费的时间要长得多)。对我来说,这意味着正在执行 OpenGL 命令(gl.getError 每次都返回 NONE),但无论出于何种原因,WebGL 都没有真正绘制到画布中。我不知道你对此有什么想法? 这方面有更新吗?我面临同样的问题:***.com/questions/61239552/… 只是为了更新:这个例子似乎在 MacOS 下运行良好。同时,我可以通过禁用抗锯齿来解决 unity3D webgl 问题。【参考方案4】:

所以我通过将premultipliedAlpha 设置为false 部分解决了这个问题。当它为真(默认)时,toDataURL 将返回一个空图像。如果为 false,则返回渲染图像。

<!DOCTYPE html>
<html>
<body>
  <canvas id="canvas"  ></canvas>
  <script type="text/javascript">
    var canvas = document.getElementById('canvas');
    var gl = canvas.getContext('webgl', 
        premultipliedAlpha: false
    );

    gl.viewportWidth = canvas.width;
    gl.viewportHeight = canvas.height;
    gl.clearColor(0.99, 0, 1, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    var IMAGE_PREFIX = 'data:image/png;base64,';
    var image = canvas.toDataURL('image/png').substring(IMAGE_PREFIX.length);

    // save(image)
  </script>
</body>
</html>

有趣的是,如果我使用puppeteer 截屏,无论premultipliedAlpha 是真还是假,我都可以看到渲染的图像。

【讨论】:

我还发现了 Headless Chrome 中 Swiftshader 的一个问题,可能与此 bugs.chromium.org/p/swiftshader/issues/detail?id=92 如何在 headless chrome 中将图像(上面的 dataURL)保存到 png 中?【参考方案5】:

如果你想在服务器上运行它并且那里没有可用的 GPU,你需要使用一些东西来代替它。

WebGL 1.0 基于 OpenGL ES 2.0 规范,该规范基于 OpenGL 2.1 规范。有 Mesa 库(https://en.wikipedia.org/wiki/Mesa_(computer_graphics)),它实现了软件渲染器,用于供应商验证 OpenGL 实现。我认为它支持最高 3.1 的 OpenGL,但我可能是错的,现在它支持更高的版本。

可以在 *nix 中安装 Mesa 作为驱动程序,并使用软件实现进行 OpenGL 渲染。

我建议在这里查看接受的答案:how to force chrome to use mesa software driver for webgl 我很确定它会解决您的问题

【讨论】:

Chrome 已经为 CPU 提供了一个 OpenGL ES 实现,称为 SwiftShader,当没有 GPU 或被列入黑名单时,它用作 WebGL 的后备。它在许多情况下都能正常工作,但显然 James 发现了一个影响特定无头设置的错误。【参考方案6】:

我不知道这是否可以帮助您,但是您可以在创建 WebGL 上下文时设置一些选项。根据浏览器的实现,你可以有不同的默认值。

您是否尝试强制 preserveDrawingBuffertrue

var gl = canvas.getContext( "webgl", 
    preserveDrawingBuffer: true
);

MDN 对此选项的评价如下:

preserveDrawingBuffer:如果值为 true,则缓冲区不会被清除,并且会保留其值,直到被作者清除或覆盖。

【讨论】:

感谢您的想法,但遗憾的是没有帮助

以上是关于在没有 GPU 的情况下以无头 chrome 渲染 WebGL 图像的主要内容,如果未能解决你的问题,请参考以下文章

在无头模式下运行 Chrome

Chrome 浏览器无头问题:没有这样的元素:无法在 chrome://downloads/ 找到元素 [重复]

chrome headless 无头浏览器 应用

selenium 无头浏览器

如何在无头 Chrome 中更改纸张尺寸 --print-to-pdf

强制无头铬/铬使用实际 gpu 而不是 Google SwiftShader