-
Notifications
You must be signed in to change notification settings - Fork 32.8k
WebGPU-based renderer for the editor #221145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Update on my end for last week. WIP branch #225413 General
RasterizationTexture atlas
Explorations
|
Hope this become default soon. |
@faheemstepsharp I suspect it's going to be a long road to be the default (6 months, 1 year+?). We did eventually switch the terminal to default to GPU rendering, it'll be really bad if we ship an editor that breaks text rendering though. |
Update for @hediet and myself for last week. WIP PR #225413 ArchitectureWe came up with a better approach for where to stick the implementation. GPU parts are now regular "view parts" instead of being more tightly tied to the view. vscode/src/vs/editor/browser/view.ts Line 161 in bd21f3c
A new vscode/src/vs/editor/browser/view.ts Lines 146 to 148 in bd21f3c
❔ The term "context" is becoming a little overloaded (ViewContext, ViewGpuContext, GPUContext). Maybe there's a better name for Drawing shapesBuilt out the
This object isn't hooked up yet, just the data structure and tests are mostly done. General
Texture atlas
Debugging |
This may be a silly question but how do you draw glyphs on WebGPU? Are you drawing the glyph map with canvas or render the font manually? |
@vincentdchan fonts are rasterized to a texture atlas using a 2d canvas context (mostly on CPU), then the texture atlas pages are uploaded and drawn by the shader where each cell is a texture mapped to 2 triangles. So we're leveraging the browser's font rendering stack and can avoid getting into that. |
Some feedback from VSCode Insiders:
|
Update:
|
I’m currently unable to reproduce the issue. I’m encountering a critical bug. When I attempt to open certain files within a project, the editor crashes. ![]() |
I tested It was due to webgpu being disabled. So, by using / adding these two flags to
ps: any other feature you try to enable, must be with a comma in the same line, a new enable-features line would overwrite the previous. Even though it gives some warns, it works. Confirmed with I am using a Arch Linux based distro. Edit1: One issue I found after, once I open a file and start selecting text randomly fast, it lags, not vscode, but the selection. After a bit, it stabilizes, till I open another file and do the same. And same thing with the minimap if you have it enabled. Edit2: After, I added these other flags to check, I dont which, but at least one helped with the issue.
It can happen in bigger files, but stops much faster, then it's all fast. Edit3: I did more testing, I also tested other flags not mentioned here. Besides the slow effects mentioned already, when it's happening if you select with the keyboard word per word or hover with mouse the files tree, all are slower, till all stops being slow all at once. It's one thing for everything. Sometimes, when you open the editor, the slow effect are there. Sometimes after opening, all are very fast, but after a while bit the slow appears. If you are able to fix the issue, overall it would be an improvement. Edit4: I will share all the flags I used in attempt to fix the issue and more. That slow effect are still random, be on big or small file. Sometimes only on the minimap, sometimes on other parts too. But again, once it stop in one part, it seem to stop in others too. Though it can come back after.
If you try to use these flags, know that not all commands will work with the same end result in all systems, you must test and find any potential issue, and remove the cause. Ideally there should be a way to easily test them or someone do them, individually comparing potential ms differences. Update: I added more flags in the list, I dont see the slow happening anymore, I wonder if the
I might edit this comment again if any issue appears, but so far, everything have been responsive and with no issues. Those additional flags really made a difference, at least here. I dont know which ones are working and giving improvements, and which are not, but as long as they dont worsen things, it's not a problem. Flags list are now complete. I noticed slows when writing and selecting text, not as the slowdowns from before, but still not being snappy / responsive. Same slow behavior when selecting through the keyboard, though with mouse are very fast. Also randomly some text that I started writing had the behavior of being invisible, just like without setting those flags. When activating the gpuacceleration. But this time was only for what was being written. I found that To not use the WebGPU and stop vscode from using GPU completely. Comment or remove all flags and use these two.
On 1.98, |
I apologize for the possible offtopic. I have a home PC-celeron on a 4K Benq 3840x2560. Those 2 options
are OK, and the code can be used normally (without |
Confirmed. Enabling webgpu using flag along with Vulkan solves the empy screen issue. |
This comment has been minimized.
This comment has been minimized.
There is an issue that seem related to GPU accel, that can happen in all places in vscode, it would be nice to have it fixed when webgpu feature are stabilized and released. That is, random text overlap, I've seen in the editor, and i've seen others reporting happening in the file tree and terminal. |
Just a question from someone who is just getting into the internals of VSCode, and thinks his issue is related. I have a Jupyter Widget that uses 3D rendering with PyThreeJS (and then of course Three.JS). This is an interface to WebGL. On my current VSCode 1.97.2 (Apple Silicon, this commit) and since about summer 2024 (though I wouldn't able to pinpoint a version number), this widget stopped working when executing notebooks directly in VSCode (though they work when launching a kernel from VSCode and going to Safari/FireFox/Chrome). I had a bit of a dive into it recently and found that when the widget gets created, it fails while trying to create a WebGL context. I checked out a few releases (I think as early as October 2024) of VSCode over the past few months, and MacOS flavours (Intel, Universal), but no joy. I also don't want to regress too far just for this widget, as I'm a happy user of new features. VSCode's GPU Info shows specifically the following:
Additionally, I've tried most of the Electron command line flags to try and enable this, but also no succes. I think I am not sure what to expect on enabling WebGL at all for version 1.97.2. It seems that on the Insiders Release (1.98.0-insider), WebGL is at least supported, but the widget still crashes. I guess this is expected then right? I'm not knowledgeable on the difference between terminal versus editor GPU rendering, so I am also not sure where the "Interactive - ..." window for Jupytext files or the Jupyter Notebook editor directly falls, but in general, on my MacOS Apple Silicon system, this is what VSCode Developer Tools tell me after trying to get a WebGL context. ![]() Just verifying this is directly related to this issue, otherwise happy to document and write up in a new issue. |
@larsgeb Chromium maintains a blacklist of hardware to disable webgl on and you might just have a setup that hits that. You could create a new issue and ping @deepak1556 on it since it's not directly related to this one. |
From my testings on the gpu acceleration. Unless you can make webgpu as responsive as with GPU disabled, I dont really see the point in using it. I included the information in my first comment here. In fact, could you tell the actual benefits of using gpu acceleration in a text editor other than taking load off the cpu? |
@dougg0k of course, this is a WIP and the focus is on feature parity not performance currently.
The goal is to minimize input latency and scroll latency by reduce the time it takes to render a frame as much as possible. This is mostly done by removing the need for browser-based layouts and dealing with DOM nodes which are expensive on the CPU side. |
When the layout changes, re-rendering can cause page content to flicker 2025-03-07.00.03.37.mov |
Update on this: I was busy with terminal intellisense last month (which is now in preview!) and will be mostly improving terminal in copilot reliability and internal security stuff this month. |
Update: I'll be out for a while soon, I don't expect work to pick back up on this until July at the earliest |
|
Uh oh!
There was an error while loading. Please reload this page.
We're finally starting to look at implementing a WebGPU-based rendering in monaco, similar to what xterm.js uses. This issue is used to track all the work which is expected to take several months.
Project: VS Code Editor GPU Renderer (view)
Related issues
Here are some historical links that might be useful:
Below copied from https://github.com/microsoft/vscode-internalbacklog/issues/4906
GPU-based rendering
branch: tyriar/gpu_exploration
How GPU rendering works
It works by assembling array buffers which represent commands to run on the GPU, these are filled on the CPU with information like the texture to use (chracter, fg, bg), location, offset, etc. xterm.js for example allocates a cols x rows array buffer that represents the viewport only and updates it on every frame where the viewport changes.
There are 2 types of shaders:
How the prototype works
The WebGPU prototype works by pre-allocating a buffer that represents up to 3000 lines in a file with a maximum column length of 200. The buffers* are lazily filled in based on what's the viewport. Meaning once a line is loaded, it doesn't need to be modified again. I think it updates more aggressively currently than needed due to my lack of knowledge around finding dirty lines in Monaco.
Texture atlas
Glyphs are rendered on the CPU using the browser's canvas 2d context to draw the characters into a texture atlas. The texture atlas can have multiple pages, this is an optimization problem as uploading images is relative expensive. xterm.js creates multiple small texture atlas pages, allocates using a shelf allocator and eventually merged them into larger immutable pages as they're more expensive to upload.
Currently the prototype uses a single large texture atlas page, but it warms it up in idle callbacks for the current font and all theme token colors in the background (using the
TaskQueue
xterm.js util).Memory usage
In the above, each text_data_buffer cell is 12 bytes (3x 32-bit floats), so 3000x200 would be:
This is pretty insignificant for a modern GPU.
* Double buffering is used as the GPU locks array buffers until it's done with it.
Scrolling
The prototype currently scrolls extremely smoothly as at most a viewport worth of data is filled but often no viewport data will change. Then we just need to update the scroll offset so the shadow knows which cells to render.
Input
So far, the above is highly optimized for readonly scrolling. For input/file changes there are a few cases we need to target. We essentially want to get these updates to take as little CPU time as possible, even if that means leaving stale and no-longer referenced data in the fixed buffers.
Adding new lines or deleting lines
This could be supported by uploading a map whose job is to map line numbers with the index in the fixed buffer:
That way we only need to update indexes, not the whole line data.
Inserting characters
Simple O(n) solution is to just update the entire line. We could do tricks to make this faster but it might not be worth the effort if line length is fixed.
Fixed buffers and long lines
My plan for how the characters will be send to the GPU is to have 1 or more fixed width buffers (eg. 80, 200?) with maps that point to indexes dynamically as described in the input section and then another more dynamic buffer which supports lines of arbitrary length. This dynamic buffer will be a little less optimized as it's the edge case when coding. The fixed buffers could also be dynamically allocated based on the file to save some memory.
Other things we could do
┌───┘
. Whether this looks good in monaco is up to the font settings. Letter spacing and line height will always mess with theseTest results
These were done on terminalInstance.ts. Particularly slow frames of the test are showed.
The
tyriar/gpu_exploration
tests disabled all dom rendering (lines, sticky scroll, etc.) to get an idea of how fast things could be without needed to perform layouts on each frame. It's safe to assume that rendering other components would be less than or equal to the time of the most complex component (minimap is similar, but could potentially share data as well).Scroll to top command
M2 Pro Macbook main
M2 Pro Macbook tyriar/gpu_exploration (all dom rendering disabled)
Windows gaming PC main
Windows gaming PC tyriar/gpu_exploration (all dom rendering disabled)
Scrolling with small text on a huge viewport
fontSize 6, zoomLevel -4
M2 Pro Macbook main
M2 Pro Macbook tyriar/gpu_exploration (all dom rendering disabled)
Windows gaming PC main
Windows gaming PC tyriar/gpu_exploration (all dom rendering disabled)
Very long line
Long lines aren't supported in the gpu renderer currently
Shaders run in parallel to microtasks and layout
The sample below from the Windows scroll to top test above demonstrates how the shaders execute in parallel with layout, as opposed to all after layout.
Before:
After:
Harfbuzz shaping engine is used by lots of programs including Chromium to determine various things about text rendering. This might be needed for good RTL/ligature/grapheme rendering.
The text was updated successfully, but these errors were encountered: