Skip to content
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

OS Agnostic Platform #442

Closed
2 of 5 tasks
Kethku opened this issue Feb 9, 2022 · 9 comments
Closed
2 of 5 tasks

OS Agnostic Platform #442

Kethku opened this issue Feb 9, 2022 · 9 comments

Comments

@Kethku
Copy link
Contributor

Kethku commented Feb 9, 2022

Let me know if you would prefer this in an email or other thread. I don't know what tracking processes yall are using yet, but figured it would be good to start the conversation and document what I've uncovered so far.

I've started digging into the Zed codebase and have set a (likely unrealistic in the short run) goal of getting some form of gpui working on windows as a way of becoming more familiar with how stuff works. For demo/experiment purposes, I'm looking at using Winit and Wgpu as os agnostic replacements for the cocoa and metal dependencies.

These library choices are an arbitrary decision on my part just to try to get something up and running. It's quite likely that that one or both of those will be missing some important pieces, but I figure better to find that out than to assume platform specific code will be necessary. I also thought to go this route because winit and wgpu are what I'm most familiar with so I figured it would be a quick way to make some progress exploring. I'd be very interested in understanding the decision to go platform specific on macos cause that would help me know where the sticking points are.

Most of the platform code as far as I can tell will be a pretty direct translation, but these are the blocking pieces that require more research to solve. I will add to this list as I uncover more.

  • Wgpu doesn't have a way to easily update a portion of a gpu texture which is necessary for the atlas code. Referencing the learn-wgpu book, it looks like using an encoder and temporary buffer enables updating a portion of an image, but its not clear to me if some manual fiddling with the texture data would be needed.

Edit: according to https://www.w3.org/TR/webgpu/#dom-gpuqueue-writetexture the write_texture function does allow for specifying where in the gpu texture the buffer data should be written. So this is a non issue.

  • need some way to dispatch a Runnable to the main thread. I think this can be achieved by maintaining a queue of runnables that gets burned down in the MainEventsCleared event, but to be honest I don't understand the APIs used here very well as I still need to ramp up on mac specific event loops. Any ideas or details here would be great!
  • font rendering seems to have a fair bit of macos specific details in it. I've yet to dig in fully, but my initial reaction is to rely on swash which I've used extensively in neovide with great success. I'll need to dig in more once I get to this point.
  • The renderer is obviously very metal specific. However, wgpu and metal (as far as I know) are very similar and a quick scan over the pipelines and shader says that there's not anything SUPER complicated going on here. So, I'm confident this could be translated pretty easily. I'd be interested to know if something stands out that I'm missing though.

One option I've considered is using rust-gpu to write the shader translation in rust directly which helps with testing. I've used rust-gpu in the past with pretty good success, but I'm nervous about stability concerns beyond simple pixel shaders, so my first attempt is probably going to be in wgsl just to be safe.

  • As far as I know, winit does not wrap File open dialogs, so platform specific ones (or some wrapper crate) will need to be used to replace the macos modal apis used in prompt_for_paths and prompt_for_new_paths
@Kethku
Copy link
Contributor Author

Kethku commented Feb 9, 2022

I've started digging into the Zed codebase and have set a (likely unrealistic in the short run) goal of getting some form of gpui working on windows as a way of becoming more familiar with how stuff works. For demo/experiment purposes, I'm looking at using Winit and Wgpu as os agnostic replacements for the cocoa and metal dependencies.

Just highlighting this. I'm using this exercise as a forcing function to become more familiar with the codebase especially since I don't yet have access to a Mac machine to actually test Zed on. I'm happy to work on whatever is needed more urgently when I start in March :)

@bzm3r
Copy link

bzm3r commented Feb 9, 2022

Made a comment re: Direct2D, but deleted it, as you're going for full on OS agnostic! I got caught distracted by your mention of Windows.

@maxbrunsfeld
Copy link
Collaborator

I do think it's worthwhile to at least explore a platform based on wgpu and winit. If it works out, it'd be great to be able to add support for multiple platforms with less work. It may end up being usable for a web-based build of Zed, since wgpu recently added a WebGL2 backend, and Safari finally added WebGL2 support last year.

@nathansobo
Copy link
Contributor

I just wanted to provide some context on why I hand-rolled the platform-specific bits for what we have so far.

I made this decision very early in Zed's life, and my big concern was being able to interface with the underlying operating system in exactly the ways that I needed to and having full control. At the time, I looked at winit and remember feeling like they introduced some abstractions that didn't feel like a great fit, especially around interfacing with the OS event loop. I have PTSD from jQuery wrapping the DOM APIs and for years being afraid of the DOM APIs as a young engineer, and then finally using them and realizing I had wasted so much time screwing around with jQuery.

So in general my philosophy is this: If I can use a library and it solves my problem cleanly without a leaky abstraction that I don't really need, then I'm on board. The more a library "almost works" the more inclined I am to bypass it and build something exactly to purpose that gives me full control.

That philosophy can cause me to re-invent things sometimes. I'm open to using pre-existing components where it's appropriate, but I want to make sure we don't pull in unnecessary complexity in the event that any of these libraries introduce abstractions we don't quite need or that don't fully cover our needs. For whatever reason, winit triggered my spidey sense of being something to avoid, but I'm happy to explore ways we can maintain less code, especially around interfacing with the graphics APIs.

@as-cii
Copy link
Member

as-cii commented Feb 10, 2022

Pretty awesome to see you diving into the codebase already, @Kethku! ✨

Back when I looked into winit I also felt some of that weirdness around their integration with the operating system but things might have changed since then. Assuming their platform integration story still doesn't feel quite right for our purposes, I could also see a world where we only use wgpu as our agnostic renderer but otherwise write our own custom platform integration code.

Basically replace only the Metal-specific parts of rendering by using wgpu's rendering facilities and platform-agnostic shading. It looks like we could do that pretty easily by integrating with their create_surface API and passing in a RawWindowHandle that we create in a platform-specific way.

@Kethku
Copy link
Contributor Author

Kethku commented Feb 10, 2022

I just wanted to provide some context on why I hand-rolled the platform-specific bits for what we have so far.

I made this decision very early in Zed's life, and my big concern was being able to interface with the underlying operating system in exactly the ways that I needed to and having full control. At the time, I looked at winit and remember feeling like they introduced some abstractions that didn't feel like a great fit, especially around interfacing with the OS event loop. I have PTSD from jQuery wrapping the DOM APIs and for years being afraid of the DOM APIs as a young engineer, and then finally using them and realizing I had wasted so much time screwing around with jQuery.

So in general my philosophy is this: If I can use a library and it solves my problem cleanly without a leaky abstraction that I don't really need, then I'm on board. The more a library "almost works" the more inclined I am to bypass it and build something exactly to purpose that gives me full control.

That philosophy can cause me to re-invent things sometimes. I'm open to using pre-existing components where it's appropriate, but I want to make sure we don't pull in unnecessary complexity in the event that any of these libraries introduce abstractions we don't quite need or that don't fully cover our needs. For whatever reason, winit triggered my spidey sense of being something to avoid, but I'm happy to explore ways we can maintain less code, especially around interfacing with the graphics APIs.

This resonates with me and makes good sense. Winit does have some significant issues (I believe possibly inherent to creating a consistent interface across divergent operating system constraints). Specifically, I've run into endless problems in Neovide around precise keyboard handling. However, it is possibly the fastest way to get something running without some pretty gnarly interop code on windows as far as I know. So for now, I'm going to barrel on through with winit. HOWEVER, this is not a design decision on my part, but rather a short term practical one. If a windows build were to be supported officially, I completely agree with the above points that a careful look should be given at just implementing the windowing/event loop ourselves.

Basically replace only the Metal-specific parts of rendering by using wgpu's rendering facilities and platform-agnostic shading. It looks like we could do that pretty easily by integrating with their create_surface API and passing in a RawWindowHandle that we create in a platform-specific way.

This is very close to what I am going for :) Winit is an incidental choice that gets something up quickly. But wgpu seems very promising to me as a way to share as much rendering code between the operating systems as possible. Especially if we can share shaders, that seems like a pretty unqualified win as debugging subtle shader differences seems miserable. I'm hopeful this exploration can be positive, but make no promises on how far I will get before starting full time.

@Kethku
Copy link
Contributor Author

Kethku commented Feb 10, 2022

A significant point in favor of using something other than winit is that Druid and Wezterm both had the option to use winit and chose to use their own. If I remember correctly, Druid's choice was around responsive window resizing and accessibility/IME text input. I don't know what went into Wezterm's decision though.

@Kethku
Copy link
Contributor Author

Kethku commented Feb 19, 2022

Just updating on progress.

I have implemented the atlas support and have example tests that prove it can at least layout images into the atlas. I have also created a basic font system using swash. I attempted to use the font-kit apis, but found that the windows implementation is not send + sync, so I had to reimplement more than I would have liked.

Basic images from an old project used for testing the image atlas.
image
Using the sprite_cache and the swash font renderer to render glyphs to an atlas.
image

Both of these components likely have issues that will be revealed after more of the renderer is implemented, but for now, this is good enough to move on.

Next step is to implement the renderer. I'm going to tackle it piecemeal and have started implementing the quad renderer pipeline. This exercise has been great for fleshing out my understanding of graphics apis. I will update here when I have more progress to report.

@maxbrunsfeld
Copy link
Collaborator

That’s really exciting progress!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants