在没有GPU的情况下,在无头Chrome中呈现WebGL图像

39

我正在尝试在没有GPU的Linux服务器上导出使用WebGL渲染的图像。为此,我使用无头Chrome,但导出的图像是黑色的(示例导出图像截取页面屏幕截图显示只有黑色画布)。我希望得到一些帮助,弄清楚这是为什么。

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

为了控制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的作者表示可以进行无头WebGL渲染

这个Chromium问题证实了这一点,所以我想我可能错过了什么。有人有任何想法吗?

我尝试过以下几件事:

  • 不传递--disable-gpu参数
  • --use-gl=swiftshader-webgl--use-gl=swiftshader--use-gl=osmesa
  • 拍摄全屏截图以查看是否只是canvas。整个屏幕都是黑色的。

版本信息:

  • Chrome:linux-515411
  • puppeteer:0.13.0
  • node:8.2.1
  • Linux:CentOS 7

这是我需要在服务器上安装的内容,以使chrome运行(来源

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

你能提供更多有关硬件配置的细节吗?据我所知,WebGL确实需要GPU。许多(大多数?)最近的计算机都包括Intel“集成显卡”形式的GPU,如果你不过度使用它们,它们足以进行3D渲染,但是没有GPU访问权限的虚拟机将会是一个问题... - jcaron
1
我们的服务器没有GPU。有很多文档表明这是可能的:“SwiftShader是OpenGL ES的高性能基于CPU的实现”(https://github.com/google/swiftshader)https://blog.chromium.org/2016/06/universal-rendering-with-swiftshader.html。Chromium问题添加Swiftshader https://bugs.chromium.org/p/chromium/issues/detail?id=630728。Chromium文档讨论了当GPU不可用时的软件合成器http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome#TOC-Appendix-B:-The-Software-Compositor - James Hollingworth
你是否真正安装了Swiftshader?在你的帖子中没有看到任何相关内容。此外,你有捕获Chrome控制台的方法吗? - jcaron
将“--disable-gpu”传递到我的Chrome选项中,使我能够呈现HTML画布饼图。非常感谢您的提示! - Mark Gargan
我运行的服务(browserless)似乎没有WebGL问题(除了速度慢,但这完全取决于您分配的资源)。 您可以在此处查看示例(https://chrome.browserless.io/?script=await%20page.goto(%27http%3A%2F%2Fdavid.li%2Fwaves%2F%27)%3B)。 - browserless
6个回答

13

有一个开放的漏洞会影响没有安装X11库的系统:crbug.com/swiftshader/79。它阻止了Chrome OS使用SwiftShader,但是同样的问题也可能发生在没有X11支持的无头Linux系统上。

幸运的是,安装X11并让事情正常运行应该是可行的。我不确定哪些软件包提供必要的库,但可以尝试这些:xorg xserver-xorg xvfb libx11-dev libxext-dev libxext-dev:i386

最终,SwiftShader的漏洞将被修复,因此不再需要X11。


首先,感谢您的帮助!我安装了依赖项并检查了它们是否可以动态加载,但问题仍然存在(https://gist.github.com/jhollingworth/24c57fe654d5f9b591d577281c7992c4)。我在带有GPU日志记录的Chromium调试版本中运行了一个简单的WebGL示例(https://gist.github.com/jhollingworth/f9bae6a65be1f61eadc4c538c5ed983c):https://gist.github.com/jhollingworth/0b1843dc4417fd282d238cb6ef46628b。 GL_RENDERER = Google SwiftShaderGL_VERSION = OpenGL ES 3.0 SwiftShader 3.3.0.2。我假设这意味着Swiftshader已加载?您有其他尝试的想法吗? - James Hollingworth
有一件事我想知道,每次调用 toDataUrl() 的时间范围在30毫秒到500毫秒之间,这取决于场景的复杂性(例如,加载图像并对其进行转换比 gl.clearColor 要花费更长的时间)。对我来说,这意味着OpenGL命令正在被执行(gl.getError 每次都返回 NONE),但由于某种原因WebGL实际上没有绘制到画布中。不知道你有没有任何想法? - James Hollingworth
这个问题有任何更新吗?我也遇到了同样的问题:https://dev59.com/n7roa4cB1Zd3GeqPjWRT - Apidcloud
1
只是更新一下:这个例子在 MacOS 下似乎运行良好。同时,我通过禁用抗锯齿解决了 unity3D webgl 的问题。 - Apidcloud

10

我通过将premultipliedAlpha设置为false,部分解决了这个问题。当它为true(默认值)时,toDataURL会返回一个空图像。当为false时,它将返回渲染后的图像。

<!DOCTYPE html>
<html>
<body>
  <canvas id="canvas" width="1080" height="1080"></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 是 true 还是 false,我都可以看到呈现出来的图像。


我还发现了一个Swiftshader在Headless Chrome中的问题,这可能与https://bugs.chromium.org/p/swiftshader/issues/detail?id=92有关。 - James Hollingworth
如何在无头Chrome中将图像(上述DataURL)保存为png? - lorraine

5

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

'--use-gl=angle' 

针对无头模式的Chrome设置,我删除了'--disable-gpu'选项,因为我认为这只是一个临时解决方案用于修复一些错误,现在不再需要使用。

您可以在Chrome源代码中找到比'angle'更多的选项,在这里(在Chrome源代码中找到这个真的是我最后想到的事情!)


1
如果您想在服务器上运行它,但没有可用的GPU,则需要使用其他替代方法。
WebGL 1.0基于OpenGL ES 2.0规范,该规范基于OpenGL 2.1规范。有一个名为Mesa库(https://en.wikipedia.org/wiki/Mesa_(computer_graphics)),它实现了软件渲染器,并由供应商用于验证OpenGL实现。我认为它支持OpenGL高达3.1版本,但我可能错了,现在它甚至支持更高版本。
可以在*nix中将Mesa安装为驱动程序,并使用软件实现进行OpenGL渲染。
我建议在这里检查已接受的答案:how to force chrome to use mesa software driver for webgl 我很确定它会解决您的问题。

2
Chrome已经自带了一个OpenGL ES实现的CPU版本,名为SwiftShader,当没有GPU或者GPU被列入黑名单时,它会作为WebGL的备选方案。在许多情况下,它可以正常工作,但显然James发现了一个影响特定无头设置的错误。 - Nicolas Capens

1
我不知道这是否能帮到您,但在创建WebGL上下文时,您可以设置选项。根据浏览器实现的不同,您可能会有不同的默认值。
您尝试过将preserveDrawingBuffer强制设置为true吗?
var gl = canvas.getContext( "webgl", {
    preserveDrawingBuffer: true
});

这里是MDN关于该选项的说明:

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


谢谢你的建议,但遗憾地没有帮助到我。 - James Hollingworth

0

preserveDrawingBuffer设置为true,问题得到了解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接