adieuadieu / serverless-chrome

🌐 Run headless Chrome/Chromium on AWS Lambda
MIT License
2.86k stars 280 forks source link

Add WebGL Support #108

Open anvaka opened 6 years ago

anvaka commented 6 years ago

Hello,

I spent all day experimenting and got WebGL working with headless shell. See the thumbnails here: https://www.reddit.com/r/pplay/ - they are rendered by lambda function from webgl scene.

To enable WebGL:

  1. I built osmesa using this script: https://github.com/devernay/osmesa-install . I changed disable_shared to enable_shared (line 534) to create libOSMesa32.so file). On EC2 instance, then final file was called libMangledOSMesa32 - just copy it next to the headless chrome binary as libosmesa.so.
  2. Remove disable-gpu flag, and tweak serverless-plugin-chrome, so that libosmesa.so is included into distribution.

PS: I don't remember whether I used headless_shell from this repository.It might be from https://github.com/universalbasket/aws-lambda-chrome But still - the WebGL in AWS lambda is possible, and I'm very happy to share it :).

adieuadieu commented 6 years ago

Hi @anvaka — That's interesting. When building chromium from source, it also produces a libosmesa.so shared library. I just don't include it as it was my understanding that WebGL wasn't yet supported by the headless_shell. But, perhaps this is no longer the case!

vsantosu commented 6 years ago

@anvaka do you have a repo containing a working setup for running webgl on AWS lambda? I'm trying to do the same thing without luck :(

pjsier commented 6 years ago

I just got this running using the steps @anvaka provided. Not sure if it's enough to just include a libosmesa.so binary in the repo or if you'd want to build that at the same time as the Chrome binary, but I'm happy to try and put together a pull request with a little guidance.

vsantosu commented 6 years ago

Yep, I can confirm, I got it working as well. The best option is to get the headless_shell binary and the libOSMesa.so in the AWS redHat distro and ship them together to the lambda. Note that all data paths needs to point to /tmp, otherwise it will crash because of write permissions. The webgl version Mesa provides is wegbl1 but it does the work, pretty slow but works.

cammanderson commented 6 years ago

Hi Guys,

I'm still having trouble, so I'm hoping someone could point me in the right direction.

Deploying it I still can't see rendered webgl content. Is there a step I am missing?

Cheers Cam

vsantosu commented 6 years ago

To anyone looking for a working combination of Mesa and Headless shell for AWS, these are the binaries, it provides pretty slow webgl V1, but it works. Hope it helps!

Headless Shell Mesa AWS Lambda

Remember to put in your flags:

[ '--use-gl=osmesa', '--enable-webgl', '--ignore-gpu-blacklist', '--homedir=/tmp', '--single-process', '--data-path=/tmp/data-path', '--disk-cache-dir=/tmp/cache-dir' ]

Otherwise it will crash due to write permissions.

mvoropaiev commented 6 years ago

Hello, @vsantosu can you please share binaries again (the link is 404 at the moment)? Also after playing around I think I got chromium to render webgl content with screenshot function, but when printing to PDF WebGL areas appears to be blank (found a similar issue https://github.com/GoogleChrome/puppeteer/issues/1731 but nothing helps), does anyone faced this issue? Thanks.

mvoropaiev commented 6 years ago

If anyone had the same PDF issue, rolling back to 64.0.3282.167 (instead of latest stable 67.0.3396.79 or dev 69.0.3452.0) solved it for me.

whyvez commented 6 years ago

Has anyone had experience using swiftshader instead of mesa when no GPU available?

rthomps7 commented 6 years ago

@vsantosu

I was hoping you still had that build somewhere. @mvoropaiev pointed out the link doesn't work.

I tried what @anvaka suggested without any luck. I have a zip with both headless_shell and libosmesa.so in there. The headless_shell works, but things fail with webgl.

Here are my CLI args:

args: [
              '--use-gl=osmesa',
              '--enable-webgl',
              '--hide-scrollbars',
              '--mute-audio',
              '--no-sandbox',
              '--single-process',
              '--disable-breakpad',
              '--ignore-gpu-blacklist',
              '--homedir=/tmp',
              '--data-path=/tmp/data-path',
              '--disk-cache-dir=/tmp/cache-dir'
]

I'm actually firing this up with Puppeteer. The same command works locally, but I get errors on the lambda. My lambda works fine for non-webgl stuff.

vsantosu commented 6 years ago

Sorry for the broken link guys. I re-uploaded the zip here:

It has the libosmesa.so already in the directory, just point Puppeteer to it and everything should work fine.

Dropbox Link

Disclaimer: I ended up using Software Based Rendering using array buffers(Threejs) because Mesa rendering is slow as a asphalt serum. Lambda CPU is pretty fast, so my rendering time went down from minutes to seconds(30 or less).

rthomps7 commented 6 years ago

@vsantosu

Thanks!. This is helpful

On a sidenote, do you have any idea how to get swiftshader-webgl on a lambda? Or if it's possible?

I'm trying to render a mapbox map on a lambda, and I'm really not having luck.

vsantosu commented 6 years ago

@rthomps7 I haven't deal with swiftshader yet, but if you get it working let me know! What I do is launch a Lambda EC2 image instance, compile everything there with static linking, and then try to get a screenshot of some Webgl render. To double check I try to use the static compiled library in a fresh CentOS VM locally.

vsantosu commented 6 years ago

@rthomps7 did you had any luck trying swift shader? I'm searching online but without luck. I think it is possible to build headless chrome with swiftshader enabled.

vsantosu commented 6 years ago

What about adding the following line after: build flags?

echo 'enable_swiftshader = true' >> out/Headless/args.gn && \

Afterwards a quick test can be done by adding:

--use-gl=swiftshader

In chromium command line arguments.

rthomps7 commented 6 years ago

I have not been able to dedicate the time to it, but I'd love to have it figured out.

On Mon, Aug 20, 2018 at 8:48 AM Victor O. Santos Uceta < notifications@github.com> wrote:

What about adding the following line after: build flags https://github.com/adieuadieu/serverless-chrome/blob/master/packages/lambda/builds/chromium/build/build.sh#L90 ?

echo 'enable_swiftshader = true' >> out/Headless/args.gn && \

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/adieuadieu/serverless-chrome/issues/108#issuecomment-414322407, or mute the thread https://github.com/notifications/unsubscribe-auth/ABOMZKC8R7Q92IPwbZQhBq4-j8SyoHBUks5uSr4pgaJpZM4R5F2- .

--

Bobby Thompson / Co-Founder 913.314.2520 <javascript:void(0);> / bobby@uhray.com www.uhray.com

adieuadieu commented 6 years ago

I can try doing a build with enable_swiftshader if someone else can help test the resulting binary on aws lambda.

apalchys commented 6 years ago

if someone else can help test the resulting binary on aws lambda

@adieuadieu I could easily to do it tomorrow morning my time

vsantosu commented 6 years ago

@adieuadieu I volunteer to that. I already have some experiments setup there, I just need the binary to replace.

adieuadieu commented 6 years ago

Thank you! I've started a build. If it builds successfully, I'll provide a link to the binary in the morning (UTC+2).

adieuadieu commented 6 years ago

OK; binary is available here. It's also available in a Docker image: adieuadieu/headless-chromium-for-aws-lambda:experimental-swiftshader

apalchys commented 6 years ago

@adieuadieu it seems WebGL doesn't work with the provided binary in my case.

vsantosu commented 6 years ago

@adieuadieu it does not seems like it is working for me either... I have not build headless chrome for Unix yet, but in Windows, chromium comes with a directory called swiftshader with two binaries:

I guess that for a lambda build will be something like:

If you can find some files like those in the build directory, we need to provide those in the same directory as headless_chrome binary at the time of launching with:

--use-gl=swiftshader

Which is the case with MESA lib.

adieuadieu commented 6 years ago

@vsantosu ah shoot. you're right. I'll get you those library binaries, as well. Need to do another build, though. The EC2 instance I built on was terminated.

apalchys commented 6 years ago

i've built Chromium using this instruction

Here are the output files: headless_shell swiftshader/libEGL.so swiftshader/libGLESv2.so

They works for me and WebGL renders on the page. Unfortunately I didn't notice any benefits in comparison with osmesa - almost the same rendering time.

cammanderson commented 6 years ago

Look forward to seeing this in action. On Wed, 22 Aug 2018 at 7:16 am, Andrei notifications@github.com wrote:

i've built Chromium using this instruction https://github.com/adieuadieu/serverless-chrome/blob/master/docs/chrome.md

Here are the output files: headless_shell https://s3-eu-west-1.amazonaws.com/apalchys-public/headless_shell swiftshader/libEGL.so https://s3-eu-west-1.amazonaws.com/apalchys-public/swiftshader/libEGL.so swiftshader/libGLESv2.so https://s3-eu-west-1.amazonaws.com/apalchys-public/swiftshader/libGLESv2.so

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/adieuadieu/serverless-chrome/issues/108#issuecomment-414824452, or mute the thread https://github.com/notifications/unsubscribe-auth/AAjVHvuPP_fhORSGC5gtCYYO77eMl6hrks5uTHiogaJpZM4R5F2- .

vsantosu commented 6 years ago

Great! Thanks,

I will try some benchmarks tonight as well. Last time I tried MESA it took about 3 minutes to render some Threejs scene with lights. We also need to check if swiftshader takes advantage of parallelism, if so in AWS lambda 1 core environment there will be not much difference.

rthomps7 commented 6 years ago

@vsantosu - any luck?

vsantosu commented 6 years ago

@rthomps7 unfortunately not :(... I tried to setup the provided build by @apalchys but it does not seems to work for me in AWS Lambda...

@apalchys , did you got to tried in an actual AWS lambda function or just docker? If so, what is your directory organization(do you leave the .o files for swiftshader in the /swiftshader directory or next to the headless chrome binary?). Also, can you provide your command line flags?

Whenever I try to launch it, it does not even load the page. The build provided by @adieuadieu works for me and is pretty lightweight but I don't have the swiftshader binaries, I don't dare to mix them with the ones provided by @apalchys. I'm curious what version of WebGL is reported when using swiftshader....

apalchys commented 6 years ago

@vsantosu actual AWS lambda. I will try to create a simple working repo for AWS Lambda by tomorrow

vsantosu commented 6 years ago

Thanks so much, @apalchys !

apalchys commented 6 years ago

@vsantosu

I've created a repo: https://github.com/apalchys/lambda-puppeteer-webgl-swiftshader

Also here is you can find zipped lambda code (please note it is over 50mb and you need to use s3 to upload): https://s3-eu-west-1.amazonaws.com/apalchys-public/lambda-puppeteer-webgl-swiftshader.zip

and here is a working demo which returns a screenshot of https://get.webgl.org/ page https://jkkpu18gue.execute-api.eu-west-1.amazonaws.com/demo/lambda-puppeteer-webgl-swiftshader-demo

vsantosu commented 6 years ago

Thanks so much @apalchys, I will be testing and uploading some benchmarks tonight!

apalchys commented 6 years ago

Btw, this issue was marked as “Fixed” yesterday: https://bugs.chromium.org/p/chromium/issues/detail?id=873321

vsantosu commented 6 years ago

Ok guys, first of all thanks so much @apalchys for providing the binaries, I got the results we where looking for.

First, the benchmark in rendering one scene using the BabylonJS library(uses WebGL v1 and WebGL 2 when available).

The scene I'm rendering is one like this, which consists of:

1- Launching Puppeteer with the following flags:

"--headless",
"--no-sandbox",
"--mute-audio",
"--hide-scrollbars",
"--disable-web-security"
"--use-gl=swiftshader",
"--enable-webgl",
"--single-process",
"--ignore-gpu-blacklist",
"--data-path=/tmp/data-path",
"--disk-cache-dir=/tmp/cache-dir"

2- Load the HTML page with the BabylonJS library, which will make a network call to load a 3D model. 3- Render the 3D model into a scene and do 6 resizings which I take screenshots from:

4096x4096.png
2048x2048.png
1024x1024.png
512x512.png
256x256.png
128x128.png
64x64.png

The following are the results:

Lib Mesa: WebGL V1 supported

Scene rendered...
Taking scene screenshots.
Image 4096x4096.png extracting took 160523.815 ms.
Image 2048x2048.png extracting took 166938.935 ms.
Image 1024x1024.png extracting took 168854.40000000002 ms.
Image 512x512.png extracting took 169493.98500000002 ms.
Image 256x256.png extracting took 169769.535 ms.
Image 128x128.png extracting took 169993.46000000002 ms.
Image 64x64.png extracting took 170196.14500000002 ms.
Extracting all images from Webgl buffer took 170196.72000000003 ms.

Total 170.2 seconds

SwiftShader: WebGL V2 supported

Scene rendered...
Taking scene screenshots.
Image 4096x4096.png extracting took 1141.299999999319 ms.
Image 2048x2048.png extracting took 1243.9999999987776 ms.
Image 1024x1024.png extracting took 1273.1999999996333 ms.
Image 512x512.png extracting took 1281.8000000006577 ms.
Image 256x256.png extracting took 1284.800000001269 ms.
Image 128x128.png extracting took 1286.10000000117 ms.
Image 64x64.png extracting took 1286.8999999991502 ms.
Extracting all images from Webgl buffer took 1287.1999999988475 ms.

Total 1.29 seconds

SwiftShader is 131 times faster!

Also, the resulting render with swiftshader is higher quality, pay attention to details:

LibMesa Render SwiftShader Render

So yea guys, swiftshader is pretty performant. So why there is so slow renders some times? Well, doing the benchmark, I think i found the real issue here...

The 3D model for the Babylon Scene is about 30MB, but thats not problem, after all I do downloads of more than 100MB in seconds before launching chromium... But lets look at this logs of the download progress inside the Chromium....

52:45  Loading scene file...
52:45  downloading: 0%
52:47  downloading: 0%
53:03  downloading: 10%
53:29  downloading: 20%
53:30  downloading: 20%
53:44  downloading: 30%
53:45  downloading: 30%
53:55  downloading: 40%
54:06  downloading: 50%
54:23  downloading: 60%
54:23  downloading: 60%
54:37  downloading: 70%
54:54  downloading: 80%
55:08  downloading: 90%
55:09  downloading: 90%
55:31  downloading: 100%
55:42  Loading scene file took 176974.40000000005 ms.

2min 56s total download time!

3 minutes to download 30MB?? Something is off... In my local machine with a slower connection it does not take even 5 seconds... So after researching a bit, it seems that the flag that is killing performance is:

"--single-process"

Which it seems there are issues around.

My theory is that when a download starts as a single process, it hugs all operations in the browser, therefore is extremely slow.

If I take this flag out, the browser fails to launch...

dukuo commented 6 years ago

@vsantosu that's awesome indeed! Could you share the code to get it working? somehow I get this error when trying to run the sample provided by @apalchys:

(node:14668) UnhandledPromiseRejectionWarning: Error: Failed to launch chrome! spawn ./headless_chromium/headless_shell ENOENT

TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

    at onClose (C:\work\dev\lambda-puppeteer-webgl-swiftshader\node_modules\puppeteer\lib\Launcher.js:299:14)
    at ChildProcess.helper.addEventListener.error (C:\work\dev\lambda-puppeteer-webgl-swiftshader\node_modules\puppeteer\lib\Launcher.js:290:64)
    at emitOne (events.js:116:13)
    at ChildProcess.emit (events.js:211:7)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:196:12)
    at onErrorNT (internal/child_process.js:372:16)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
(node:14668) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:14668) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Also, do you think it could be suitable to run with THREE.js + animations?

vsantosu commented 6 years ago

Hello @dukuo ,

Are you running the binaries in AWS lambda? Otherwise it won't launch in other environment which is not AWS lambda, their EC2 redhat instance, and probably a CentOS 7 OS. It was compiled to run in that distro.

"do you think it could be suitable to run with THREE.js + animations?"

Absolutely! You could definitively render a scene, and create a 360 degree rotation gif or video from the canvas.

vsantosu commented 6 years ago

@dukuo I'm using the same code settings provided by @apalchys in his repo.

apalchys commented 6 years ago

@dukuo Usually ENOENT code means that file or directory is not found. Please check your files/directory structure and make sure you unzipped the archive with the binaries (see README https://github.com/apalchys/lambda-puppeteer-webgl-swiftshader)

python1981 commented 6 years ago

The solution by @vsantosu is great for screenshots with Page.captureScreenshot() but when I tried to create a pdf with Page.printToPdf() the WebGL disappears.

I worked around this by reverting to the earlier version with osmesa instead of swiftshader but unfortunately it's much older and other things break as a result.

Refs: https://bugs.chromium.org/p/chromium/issues/detail?id=809065 & https://github.com/GoogleChrome/puppeteer/issues/1731

ghost commented 2 years ago

WebGL should work with the precompiled Chromium binaries available here.

escully27 commented 2 years ago

@vsantosu

I've created a repo: https://github.com/apalchys/lambda-puppeteer-webgl-swiftshader

Also here is you can find zipped lambda code (please note it is over 50mb and you need to use s3 to upload): https://s3-eu-west-1.amazonaws.com/apalchys-public/lambda-puppeteer-webgl-swiftshader.zip

and here is a working demo which returns a screenshot of https://get.webgl.org/ page https://jkkpu18gue.execute-api.eu-west-1.amazonaws.com/demo/lambda-puppeteer-webgl-swiftshader-demo

Would you please be able to share the config for your AWS lambda deployment for your example? Have been trying everything with no success. Simply trying to duplicate your demo on my own lambda function.

Here's my latest error:

"{
  "errorType": "Error",
  "errorMessage": "Failed to launch chrome!\n./headless_chromium/headless_shell: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory\n\n\nTROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md\n",
  "trace": [
    "Error: Failed to launch chrome!",
    "./headless_chromium/headless_shell: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory",
    "",
    "",
    "TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md",
    "",
    "    at onClose (/var/task/node_modules/puppeteer/lib/Launcher.js:299:14)",
    "    at Interface.<anonymous> (/var/task/node_modules/puppeteer/lib/Launcher.js:288:50)",
    "    at Interface.emit (node:events:539:35)",
    "    at Interface.close (node:readline:586:8)",
    "    at Socket.onend (node:readline:277:10)",
    "    at Socket.emit (node:events:539:35)",
    "    at endReadableNT (node:internal/streams/readable:1345:12)",
    "    at processTicksAndRejections (node:internal/process/task_queues:83:21)"
  ]
}
"

I understand there's an issue location libnss3.so but it's no where to be found in your repo either. Many thanks.