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

我正在尝试在没有 GPU 的 Linux 服务器上导出使用 WebGL 渲染的图像。为此,我使用的是无头 Chrome,但导出的图像是黑色的(example exported imagetaking 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

标签: javascript google-chrome webgl pixi.js puppeteer


【解决方案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/0b1843dc4417fd282d238cb6ef46628bGL_RENDERER = Google SwiftShaderGL_VERSION = OpenGL ES 3.0 SwiftShader 3.3.0.2。我假设这意味着 Swiftshader 已加载?对我可以尝试的其他事情有什么想法吗?
      • 我想知道的一件事是,每次调用toDataUrl() 的时间从 30 毫秒到 500 毫秒不等,具体取决于场景的复杂性(例如,加载图像然后转换它比gl.clearColor 花费的时间要长得多)。对我来说,这意味着正在执行 OpenGL 命令(gl.getError 每次都返回 NONE),但无论出于何种原因,WebGL 都没有真正绘制到画布中。我不知道你对此有什么想法?
      • 这方面有更新吗?我面临同样的问题:stackoverflow.com/questions/61239552/…
      • 只是为了更新:这个例子似乎在 MacOS 下运行良好。同时,我可以通过禁用抗锯齿来解决 unity3D webgl 问题。
      【解决方案4】:

      所以我通过将premultipliedAlpha 设置为false 部分解决了这个问题。当它为真(默认)时,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 是真还是假,我都可以看到渲染的图像。

      【讨论】:

      【解决方案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,则缓冲区不会被清除,并且会保留其值,直到被作者清除或覆盖。

      【讨论】:

      • 感谢您的想法,但遗憾的是没有帮助
      猜你喜欢
      • 2016-01-30
      • 2011-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-19
      • 2018-05-14
      • 2018-06-04
      相关资源
      最近更新 更多