feat: import external shared texture into VideoFrame#46811
feat: import external shared texture into VideoFrame#46811reitowo wants to merge 1 commit intoelectron:mainfrom
VideoFrame#46811Conversation
31f918d to
38f7428
Compare
|
I have wrapped the shared texture handle to VideoFrame object successfully. However, several major issue blocks:
|
|
Update: I now got the SharedImageInterface from SharedGpuContext, but when I'm trying to call CreateSharedImage, the Renderer Process crashed without any debug message. Trying to use a debug build with symbol_level 2 to check again. |
f2ef828 to
d05c338
Compare
|
😞 Bad news: SharedImage doesn't work well with this hack. It requires taking ownership of handles, and the renderer process seems having some issue with duplication. 😄 Good news: Works with WebGPU (with hack) It becomes more tricky, because the HANDLE on Windows has some internal design at Chromium: When passing through ipcz, it DuplicateHandle automatically for target process. However it seems causing some error for D3D12 to import (mojo\core\ipcz_driver\transport.cc:221) |
|
I love the good news 😄 ! What do you mean by 'hack'? |
fe33cf9 to
4fb45cb
Compare
|
😄 Good news: I found hacking WebGPU also very ugly, so I truned my route back to VideoFrame. After days of debugging, I found managing the handle on Windows very tricky, for example, when an FrameSinkVideoCapturer's output is first CreateSharedHandle on GPU process, and when it pass through IPC, the ipcz automatically DuplicateHandle for target process. Now we are at Main process, we need to pass the handle to Renderer process, but this time, we have no ipcz does the DuplicateHandle thing for us. I then add a extra param to let user tell the handle's owner process id, and DuplicateHandle it internally to Renderer process. Later, the ipcz will clone the handle for us when passing it back to GPU Process. That's also the reason why Renderer process was crashing before (without any debugging message!), the handle belongs to Main process and it failed to duplicate the handle, making ipc serialization failure. For other shared handle, user needs either use deprecated GetSharedHandle to create a non-NT handle, or pass the handle owner's pid, in order to successfully import handle on Windows. At this step, I successfully imported as a VideoFrame, and successfully call WebGPU's importExternalTexture and get a valid object. But I found the rendering has some problem (full black). After some debugging, I found If you're interested, here's a working sample: https://github.com/reitowo/electron-test-import-texture |
3bc7bc1 to
53d52ad
Compare
56c41a1 to
7fc2466
Compare
VideoFrame from a external shared texture.VideoFrame
|
That's huge! Thank you @reitowo |
|
This now works like a charm in Windows. The macOS's IOSurface also needs to pass by mach_port across processes. https://source.chromium.org/chromium/chromium/src/+/main:mojo/core/channel_mac.cc;drc=c7beb80e1c9ed11289a501218de27681143b9ba9;l=388 Passing mach_port is much more complicated than I thought. Maybe still need to think twice about the API. I think the best option is to import at Main process, and use Mailbox to pass between processes in Chromium, which is same pattern in Chromium anyway. |
cf19e36 to
b071e0f
Compare
7cca532 to
c3db1c6
Compare
|
I've done everything to make it work on Windows and macOS! Due to lack of development environment I choose drop Linux support for now. Test also included, run I'm also happy about current API design, especially zero upstream patch. Looking forward to hear your advice! @codebytere @nikwen @MarshallOfSound Binary for testing: https://github.com/reitowo/electron/releases/download/import-texture-v1/dist.zip Working sample: https://github.com/reitowo/electron-test-import-texture output.mp4 |
f00fd29 to
18ffb47
Compare
|
I found a bug when writing test on macOS that nativeImage was not able to compare pixel data correctly #46949. So I changed the compare method in test. |
|
This is extremely cool @reitowo! The API looks great and should match my use case perfectly - I'll try this out soon |
8323f59 to
25099da
Compare
|
About performance: I created 16 browser 720P OSR send to 1 renderer process, and tested both use 16 canvas or 1 combined canvas render at and the results are same (16x 50fps). On my 3070 we can achieve: The GPU process's CPU usage is high, I don't know how to optimize further, the GPU usage is not high. @RenaudRohlinger Could you share more links to the reports by community? Sounds interesting. |
|
Is it possible the video frame is going through the same path people are having issues with in https://issues.chromium.org/issues/406357270 for recent AMD GPUs? You could try passing the flags mentioned in that issue to check if it helps. |
|
The OSR relies on the VideoCapture path, so this bug affected us. I think since we can import external texture as a SharedImage we may someday no more rely on VideoConsumer and make our own OSR host (in the future) |
|
I see. In the meantime, do you have a patch in mind for AMD, or is there nothing Electron can do here? |
|
No, I have no AMD GPU on hand. And I think FrameSinkVideoCapturer doesn't involve video encode/decode, if it does, probably it is the oracle's bad again. It will be helpful if you can run with --no-sandbox and get some detailed log files to see if there's more error message. |
|
Only error I have when logging with Related source code: |
|
Hello @reitowo, I did some extensive investigation on this issue, I even went as far as purchasing an RTX GPU to confirm whether the problem was related to AMD. To my surprise, it turns out the issue wasn't GPU-related at all, but display-related. My current physical display is limited to a resolution of 1920x1080 with a device pixel ratio (DPR) of 1. Because of this, the capture API appears to be constrained by the physical resolution of the display, meaning it cannot exceed what the screen supports. This limitation seems to be the root cause of the problem. I believe you haven’t encountered this issue because your display likely supports a higher resolution than mine. Here are some improved logs that highlight the limitation: |
|
Oh, it suddenly become reasonable if electron somehow limits the width and height to the working area, and the Yes, can be verified if you try calling |
|
Indeed it now works! Thank you for finding this. I think it would be worth it mentioning this detail in the documentation. |
|
Hi, guys. This PR will be seperated for several minor PRs, and the PR is converted to an RFC for better outcome. electron/rfcs#17. I'll link all minor PRs in this PR for reference. Let's continue keep discussion here! |
3420c42 to
20ca326
Compare
Hi @reitowo Thank you for your work. It’s exactly what we need! I would like to try your test project, but I encountered a 'not found' error with the download link. Could you please provide the latest compiled binary so that we can run the example? Thank you! |
|
Close this in favor of the last piece of the PR. |
|
16x1080p@35fps
16x720p@54fps
When use with new managed API, testing with offscreen rendering's output, we can still archive 16x1080p@35fps, 16x720p@54fps rendered by WebGPU, which is actually better than before. The performance could be better if we can elinimate the copy when creating ExternalTexture from VideoFrame. However I leave that for future works. (However, I don't see that will help as I think the limit might be CPU side, too much events). |














Description of Change
Added a new API
sharedTextureto import external shared texture as VideoFrame.Closes #46779 #46901
Split PRs
This PR is closed for the following PRs:
Note these PR dependent on each other in order, so we have to merge it one by one.
ColorSpace#47314paintevent move texture data tohandle, addcolorSpace#47315sharedTexturemodule to import shared texture #47317Release Notes
Notes: none