Rust Development Thread

I'll let Donald chime in but from memory there was a main path of Lua and duplicate draw functions for each SDK. Obviously this was easier as both use Lua.

If I understand correctly, it sounds like Donald wrote a custom wrapper that serves as an adaptor for platform specific IO calls. That is not an unreasonable general approach.

Contemporary platforms seem to be split into x86_64 (Playstation, Xbox, most PC-systems) and AArch64 (Switch, mobile devices, M1 Macs). If pure no_std Rust is used, it might be possible for the same two 32-bit .o object files to be used on all platforms (compatibility mode).

Another note is that I want the option to mix non-inline ASM into projects if need be. As long as all object files expose functions that use the C ABI, it should be possible to mix code written in all sorts of languages into the same binary. I only want to write code in Rust and ASM, but some platforms may assume main() is written in one language or another (C++, Swift, etc.). Furthermore, all sorts of libraries are theoretically useful, but my understanding is that in practice many good libraries have already been written in C and C++.

Finally, I seem to recall that @carols10cents is bot interested in Rust development for Playdate, and has opinions. Any discussion that can be generated on the topic is good.

@carols10cents spoilers ahead, don't read if you want to suffer like I have.

The architecture of crankstart was driven by the fact that Playdate C_API games do not have access to a C standard library. As such, they have to be no_std, Rust's term for binaries that run without a C standard library.

C_API games remind me a lot of 1990's Photoshop plugins. They have a single entry point, which the hosting environment calls, passing it a structure filled with pointers to everything else the game needs to operate. Cranstart defines this entry point here..

The additional interesting wrinkle is that the Playdate simulator expects to find games packaged as a dynamic shared libraries. Rust is very uninterested in building a no_std desktop dynamic shared library, so much hackery is required to produce one.

Luckily, one of the things the C_API provides is a function to allocate memory. This allows crankstart to implement a custom allocator and crankstart games to use the alloc crate and allowing crankstart to provide a much more ergonomic API.

Another challenge in providing decent Rust wrappers around the Playdate C_API is how callback-driven it is. It was hard for me to figure out how satisfy Rust's ownership rules in a callback which could be called in response to a call into the C_API. I'm kinda playing fast and loose with it to make the sprite collision stuff work.

A third challenge is that the main stack on Playdate is very small. In a non-public game I was working on, that used serde to read a JSON tile map file, I could easily exhaust it. I think this is due to Panic mapping the stack to some fast RAM on the chip, which makes sense, but it does mean one needs to be very careful about stack use. Were I to return to that game, I'd preprocess the JSON files on the host to something that the Crankstart game could read without serde.

On the question of portability, one should be able to use any Rust crate that can function in no_std with alloc. I was very happy to discover that Euclid worked in such an environment. The klondike crate is a half-assed example of that, since it links to the solver binary as a std crate, and the game itself in no_std.

Some small portions of SDL2 might work that way, but since both Playdate and SDL2 want to be in control of the game loop, I'm not sure how much use it would be.

5 Likes

Many crates function with no_std+alloc, but a lot of useful crates do not. hecs is a no_std ECS library, but not a game engine per se. Additionally, Rhai looks promising for no_std scripting.

In theory, some sort of C standard library could be provided that runs on the Playdate. A version of the Rust standard library could then be built on top of it. Someone would need to do the porting work, but an executive decision was probably made to exclude the C standard library in the first place. Furthermore, the issue of the small main stack indicates that the Playdate is probably the wrong platform of "heavy" (or maybe even standard) libraries.

For what it is worth, it will be great if the Playdate encourages no_std Rust game development because that means more portable code that runs anywhere. My understanding is that the Playdate has a relatively beefy processor for the screen and RAM, leading to an interesting set of constraints- preprocess data so the stack does not overflow, but also use lean data structures do as much as possible at runtime so RAM does not run out. Code written for the Playdate may need optimizations that are useful but unnecessary on other platforms.

I suspect that the Playdate entry point (event handler) could live alongside a main() function without hurting anything. It could probably also be conditionally removed. This leads to an architecture where the same update function is used on all platforms, with an adaptor for the right signature, if necessary.

I tried to do some Rust work on an NDA protected closed platform where stub functions were needed to generate symbols in the resulting binary. I wonder if it does not make sense to split the no_std desktop dynamic shared library "hackery" out into a separate file. For what it is worth, systems like the Playdate probably break a lot of the standard assumptions most programmers make about the execution environment- it is kind of embedded and kind of unix.

If the current alloc solution works, it is probably good enough. Just to throw something on the table, could it make sense for Rust to get the whole heap from the Playdate API so a custom allocation can be used?

In theory, it is possible to write 100% safe Rust code. In practice, unsafe Rust exists for a reason- hardware and external software may not conform to a conceptual model that cleanly maps to Rust's ownership rules. Is the callback problem more complicated than memory just being owned by caller. If so, is it really compatible with Rust's notions of "not your memory"?

My understanding is that SDL2 expects the programmer to write their own game loop. Obviously much of SDL2 does not make sense on Playdate. Multiple player controllers is one example.

@rob While skimming the crank source code, my first reaction was "I wish this was a makefile." If I want to write ASM and compile it into an object file, is there currently a way to link it to the binary using crank? My old lang_interop example uses rustc instead of cargo, so it looks like I never figured out a good solution. The Embedonomicon has a section .s files. Maybe the global_asm.s solution laid out in this post will just work? I can try to make a simple test project.

There has never been a time when I've been writing in Rust and wished I was writing in Make. :smile:

I think the new inline assembly stuff just got stabilized. If that's not enough for your ASM desires, a build.rs file should work with crank, it's just shelling out to cargo for the build.

2 Likes

:joy: On a quick skim that I will immediately forget, it looks like you're lots farther than me :slight_smile: I've only spent a few evenings, and I don't have my device yet. I'm mostly just drawing rectangles in the simulator, having fun designing a Rust API that I like, learning more about game dev and FFI, and remembering that graphics involves so much math :sweat_smile:

2 Likes

I recently summarized Getting Started with Rust on Playdate in a blog post. It may be easier to follow for anyone who is looking for a tutorial.

4 Likes

Has anyone started looking into the 1.13.0 SDK with crankstart? It's a bigger set of changes than most previous updates.

No. Have you tried building the Klondike solitaire project? It worked last time I tried building it.

I'm getting there - I'm currently trying to get a Playdate development setup working on Linux, since the simulator makes some unfortunate assumptions about the distribution it's running on.

But crankstart was just updated to SDK 1.13.0, so Klondike will probably work. :slight_smile:

For what it is worth, I have had no trouble running on macOS in the relatively recent past.

Klondike builds and appears to run fine on MacOS with 1.13.0 SDK. I did not play through a complete game. My own project also appears to build and run fine.

1 Like

Have you tried it on real hardware? I'm willing to try if you are unable.

It works on hardware for prior versions. My device is currently 1.12.3 with no update available. I suspect it will just work on hardware, but feel free to give it a shot and report back if you feeling motivated!

Tested and working on hardware with Playdate SDK 1.13.1.

1 Like

It looks like you have already figured out an effective solution for developing games for the Playdate using the Rust language. Have you tried the other examples in the C_API folder? If so, do you have any tips or advice on how to get them up and running? Additionally, I recommend checking out the official Playdate SDK Documentation for more information and resources related to MLSDev - software development company

I wrote a "Getting Started with Playdate" blog post that covers the following. Last time I checked, the information can be used to run all of the C and Lua examples.

  • Pulp. Running downloaded PDX files in the simulator.
  • Lua. Running project-based Lua examples.
  • Lua. Running single-file Lua examples.
  • C API. Running examples.
  • Links to documentation.

Although none of the information is specifically related to Rust, it is useful in practice. crankstart provides Rust bindings to the C API, so it is important to be familiar with the C API when developing in Rust. Furthermore, last time I checked, the C API documentation was written with the assumption the reader is familiar with the Lua documentation. Understanding development with Pulp is not important when working in Rust.

I have also written related articles on getting started with Playdate development in Rust, Fortran, and ASM. The Rust post summarizes this thread, but it is written in a tutorial format. There is also a post on "Using cc-rs to Mix Rust with C, C++, and ASM", if you want to do mixed language development.

1 Like

@sgeos Great posts!
In near future, I hope, will see updated tooling for development in Rust, and so you probably update thus part about complexity. It because all goes to outer simplicity. I working on it. Look at videos in attached post.

1 Like

Thanks for doing the OS/Sim v2.0 update work Alex! I've been following along on forum threads and GitHub. Am I right in thinking that it's probably best to wait for the next SDK release before trying to get started with Rust on Playdate?

1 Like

Rust tooling was broken when I last tried to build for the latest SDK. My guess is that this is still true?