Commit graph

543 commits

Author SHA1 Message Date
Stephen Gutekanst
f16836fc37 gpu-dawn: binary releases are only for macos-x86_64 for now
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
bd749af96e gpu-dawn: utilize binary release by default
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
df61d34811 gpu-dawn: CI: remove debug steps
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
43c4795e48 gpu-dawn: CI: correct triple format in release uploads
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
7bc8a6ac57 gpu-dawn: use "release-<SHA>" not "<SHA>" for release tags
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
5e4bff902b gpu-dawn: disable aarch64-macos / x86_64-linux CI runners for now
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
c396c27b2b gpu-dawn: update CI to latest Zig nightly
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
97048a58de gpu-dawn: upload gzip binaries properly
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
a432f3a878 gpu-dawn: remove incorrect CI workflow dependencies
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
c370e007fd gpu-dawn: checkout repo so we can use git rev-parse
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
b93dc4a207 gpu-dawn: authenticate the GH CLI
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
1807e7b2f3 gpu-dawn: begin publishing prebuilt binaries
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
485d82899a gpu-dawn: remove dependency loop
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
882e876666 dev: cleanup push-subrepos.sh
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
40d896e711 gpu-dawn: add Dawn submodule to subrepository
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
38eb708614 gpu-dawn: remove symlink before cloning mach-glfw
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
c0901d4006 gpu-dawn: move mach-glfw cloning to CI script for now
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
8035e30ad8 gpu-dawn: clone mach-glfw if needed (temporary)
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
e6e5c7f14a gpu-dawn: have CI build gpu-dawn for Linux & macOS
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
db86678809 gpu-dawn: clarify README
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
ec1a332853 dev: add gpu-dawn subrepository
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
7a4895d62c gpu-dawn: initialize subrepository
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
d12bd1daa7 gpu-dawn: prepare to have binary release option
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
48bbf627fb gpu-dawn: add option to build single static library
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
943a5af48b gpu-dawn: ensure submodules are initialized as part of zig build
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
225109ec7b gpu-dawn: make build system a single file
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 15:21:16 -07:00
Stephen Gutekanst
be35c4cf85 glfw: CI: M1: skip sudo when cleaning up git submodules
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 00:37:45 -07:00
Stephen Gutekanst
3f0eeadede CI: M1: skip sudo when cleaning up git submodules
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-12 00:36:05 -07:00
Stephen Gutekanst
1018f299d8 CI: cleanup git submodules in M1 runner
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-11 22:51:56 -07:00
Stephen Gutekanst
505909486b glfw: CI: cleanup git submodules in M1 runner
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-11 22:51:35 -07:00
Stephen Gutekanst
6a5e5c10c4 CI: cleanup git submodules in M1 runner
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-11 22:06:40 -07:00
Stephen Gutekanst
e718919be5 glfw: CI: cleanup git submodules in M1 runner
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-11 22:05:09 -07:00
Stephen Gutekanst
46bb995164 CI: upgrade to latest Zig nightly
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-11 17:24:41 -07:00
Stephen Gutekanst
bca3c80504 glfw: CI: upgrade to latest Zig nightly
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-11 17:24:32 -07:00
Lee Cannon
6f32a338c0 glfw: use comptime magic to remove InternalUserPointer and associated overhead 2022-02-11 15:13:58 -07:00
Lee Cannon
8d2a4cd8d2 glfw: glfwGetMonitors can return null to signify no monitors 2022-02-11 15:09:09 -07:00
Lee Cannon
bc8ce57e53 glfw: document why unreachable is valid 2022-02-11 15:09:09 -07:00
Stephen Gutekanst
0cdac6c68a Fix minor regressions introduced in 3e79a12
3e79a12f3d

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-02-08 20:21:56 -07:00
Lee Cannon
2e9347399d glfw: dont use @errSetCast 2022-02-08 19:58:52 -07:00
Lee Cannon
3e79a12f3d glfw: dont call getError unless we need to 2022-02-08 19:57:20 -07:00
Lee Cannon
746b0dd1f0 glfw: improve setErrorCallback 2022-02-08 19:54:00 -07:00
Stephen Gutekanst
c2c4335ff2 ecs: major rethink & database-aligned design
:: Limitations of our ECS

Previously, we had thought about our ECS in terms of archetypes defined at compile time (effectively arrays
of archetype structs with comptime defined fields as components.) I believe that this is likely *the most
efficient* way that one could ever represent entities. However, it comes with many limitations, namely that:

You have to define which components your entity will have _at compile time_: with our implementation,
adding/removing components to an entity at runtime was not possible (although declaring components at comptime
that had optional _values_ at runtime was). This is contradictory with some goals that we have:

* The ability to add/remove components at runtime:
    * In an editor for the game engine, e.g. adding a Physics component or similar to see how it behaves.
    * In a code file as part of Zig hot code swapping in the future, adding an arbitrary component to an entity
      while your game is running.
    * In more obscure cases: adding components at runtime as part of loading a config file, in response to network
      operations, etc.

:: Investigating sparse sets

To find the best way to solve this, I did begin to investigate sparse sets which I saw mentioned in various contexts
with ECS implementations. My understanding is that many ECS implementations utilize sparse sets to store a relation
between an entity ID and the dense arrays of components associated with it. My understanding is that sparse sets
often imply storing components as distinct dense arrays (e.g. an array of physics component values, an array of weapon
component values, etc.) and then using the sparse set to map entity IDs -> indexes within those dense component arrays,
`weapon_components[weapons_sparse_set[entityID]]` is effectively used to lookup an entity's weapon component value,
because not every entity is guaranteed to have the same components and so `weapon_components[entityID]` is not possible.

This of course introduces overhead, not only due to two arrays needed to lookup a component's value, but also because
you may now be accessing `weapon_components` values non-sequentially which can easily introduce CPU cache misses. And
so I began to think about how to reconcile the comptime-component-definition archetype approach I had written before
and this sparse set approach that seems to be popular among other ECS implementations.

:: Thinking in terms of databases

What helped me was thinking about an ECS in terms of databases, where tables represent a rather arbitrary "type" of
entity, rows represent entities (of that type) themselves, and the columns represent component values. This makes a lot
of sense to me, and can be implemented at runtime easily to allow adding/removing "columns" (components) to an entity.

The drawback of this database model made the benefit of sparse sets obvious: If I have a table representing monster
entities, and add a Weapon component to one monster - every monster must now pay the cost of storing such a component
as we've introduced a column, whether they intend to store a value there or not. In this context, having a way to
separately store components and associate them with an entity via a sparse set is nice: you pay a bit more to iterate
over such components (because they are not stored as dense arrays), but you only pay the cost of storing them for
entities that actually intend to use them. In fact, iteration could be faster due to not having to skip over "empty"
column values.

So this was the approach I implemented here:

* `Entities` is a database of tables.
    * It's a hashmap of table names (entity type names) to tables (`EntityTypeStorage`).
    * An "entity type" is some arbitrary type of entity _likely to have the same components_. It's optimized for that.
      But unlike an "archetype", adding/removing ocmponents does not change the type - it just adds/removes a new column
      (array) of data.
    * You would use just one set of these for any entities that would pass through the same system. e.g. one of these
      for all 3D objects, one for all 2D objects, one for UI components. Or one for all three.
* `EntityTypeStorage` is a table, whose rows are entities and columns are components.
    * It's a hashmap of component names -> `ComponentStorage(T)`
    * Adding/removing a component is as simple as adding/removing a hashmap entry.
* `ComponentStorage(T)` is one of two things:
    * (default) a dense array of component values, making it quite optimal for iterating over.
    * (optional) a sparsely stored map of (row ID) -> (component value).
* `EntityID` thus becomes a simple 32-bit row ID + a 16-bit table ID, and it's globally unique within a set of `Entities`.
    * Also enables O(1) entity ID lookups, effectively `entities.tables[tableID].rows[rowID]`

:: Benefits

::: Faster "give me all entities with components (T, U, V) queries"

One nice thing about this approach is that to answer a query like "give me all entities with a 'weapon' component", we can
reduce the search space dramatically right off the bat due to the entity types: an `EntityTypeStorage` has fast access to
the set of components all entities within it may have set. Now, not all of them will have such a component, but _most of
them will_. We just "know" that without doing any computations, our data is structured to hint this to us. And this makes
sense logically, because most entities are similar: buttons, ogre monsters, players, etc. are often minor variations of
something, not a truly unique type of entity with 100% random components.

::: Shared component values

In addition to having sparse storage for `entity ID -> component value` relations, we can _also_ offer a third type of
storage: shared storage. Because we allow the user to arbitrarily define entity types, we can offer to store components
at the entity type (table) level: pay to store the component only once, not per-entity. This seems quite useful (and perhaps
even unique to our ECS? I'd be curious to hear if others offer this!)

For example, if you want to have all entities of type "monster" share the same `Renderer` component value for example,
we simply elevate the storage of that component value to the `EntityTypeStorage` / as part of the table itself, not as a column
or sparse relation. This is a mere `component name -> component value` map. There is no `entity ID -> component value`
relationship involved here, we just "know" that every entity of the "monster" entity type has that component value.

::: Runtime/editor introspection

This is not a benefit of thinking in terms of databases, but this implementation opens the possibility for runtime (future editor)
manipulation & introspection:

* Adding/removing components to an entity at runtime
* Iterating all entity types within a world
    * Iterating all entities of a given type
        * Iterating all possibly-stored components for entities of this type
        * Iterating all entities of this type
            * Iterating all components of this entity (future)
* Converting from sparse -> dense storage at runtime

:: A note about Bevy/EnTT

After writing this, and the above commit message, I got curious how Bevy/EnTT handle this. Do they do something similar?

I found [Bevy has hybrid component storage (pick between dense and sparse)](https://bevyengine.org/news/bevy-0-5/#hybrid-component-storage-the-solution)
which appears to be more clearly specified in [this linked PR](https://github.com/bevyengine/bevy/pull/1525) which also indicates:

> hecs, legion, flec, and Unity DOTS are all "archetypal ecs-es".
> Shipyard and EnTT are "sparse set ecs-es".

:: Is our archetypal memory layout better than other ECS implementations?

One notable difference is that Bevy states about Archetypal ECS:

> Comes at the cost of more expensive add/remove operations for an Entity's components, because all components need
> to be copied to the new archetype's "table"

I've seen this stated elsewhere, outside of Bevy, too. I've had folks tell me that archetypal ECS implementations
use an AoS memory layout in order to make iteration faster (where `A`, `B`, and `C` are component values):

```
ABCABCABCABC
```

I have no doubt a sparse set is worse for iteration, as it involves accessing non-sequentially into the underlying dense
arrays of the sparse set (from what I understand.) However, I find the archetypal storage pattern most have settled on
(AoS memory layout) to be a strange choice. The other choice is an SoA memory layout:

```
AAAA
BBBB
CCCC
```

My understanding from data oriented design (primarily from Andrew Kelley's talk) is that due to struct padding and alignment
SoA is in fact better as it reduces the size of data (up to nearly half, IIRC) and that ensures more actually ends up in CPU
cache despite accessing distinct arrays (which apparently CPUs are quite efficient at.)

Obviously, I have no benchmarks, and so making such a claim is super naive. However, if true, it means that our memory layout
is not just more CPU cache efficient but also largely eliminates the typically increased cost of adding/removing components
with archetypal storage: others pay to copy every single entity when adding/removing a component, we don't. We only pay to
allocate space for the new component. We don't pay to copy anything. Of course, in our case adding/removing a component to
sparse storage is still cheaper: effectively a hashmap insert for affected entities only, rather than allocating an entire
array of size `len(entities)`.

An additional advantage of this, is that even when iterating over every entity your intent is often not to access every component.
For example, a physics system may access multiple components but will not be interested in rendering/game-logic components and
those will "push" data we care about out of the limited cache space.

:: Future

Major things still not implemented here include:

* Multi-threading
* Querying, iterating
* "Indexes"
    * Graph relations index: e.g. parent-child entity relations for a DOM / UI / scene graph.
    * Spatial index: "give me all entities within 5 units distance from (x, y, z)"
    * Generic index: "give me all entities where arbitraryFunction(e) returns true"

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-01-27 22:54:26 -07:00
Stephen Gutekanst
a75b599279 ecs: add very early-stages entity component system
This is the very, _very_, early stages of an entity component system for Mach. It's not ready
for any real use, but rather is a starting point for further development.

This spawned after [this research issue](https://github.com/hexops/mach/issues/127) in which I got
tons of great information, tips, etc. and much more research that I did after the discussion in that
issue. The idea is to start with this, and continue moulding it into what we want.

As development continues..

* I've created [a room in the Matrix server for anyone who wants to chat](https://matrix.to/#/#ecs:matrix.org)
* I'll be maintaining a blog detailing eerything I've learned and how I'm approaching development of this (as I plan to do for all key parts of Mach.)

The first article in the series:

[Let's build an Entity Component System from scatch (part 1)](https://devlog.hexops.com/2022/lets-build-ecs-part-1)

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-01-16 19:15:02 -07:00
InKryption
3d392c8c74 glfw: Use anyopaque instead of opaque {}
Update other two instances of `opaque {}`
2022-01-12 18:58:49 -07:00
InKryption
d651d25903 glfw: Use anyopaque instead of opaque{}
Using an inline `opaque{}` type forces the use of `@typeInfo` to cast to the specific type of the parameter.
2022-01-12 18:58:49 -07:00
Alex G Rice
abe9475d6e
gpu-dawn: update to latest glfw get/setUserPointer API (#154)
Updates gpu-dawn to use the latest glfw get/setUserPointer API introduced in hexops/mach#152

Helps hexops/mach#153
2022-01-09 20:58:18 -07:00
InKryption
786da94468 glfw: Tidy up UserPointer access
This change both restricts and clarifies the mutability/nullability of the pointers, and replaces the explicitly-typed pointer usage in setUserPointer with ?*anyopaque, since it now, as of being renamed from c_void, more simply communicates the intent of taking any pointer type.
2022-01-02 18:17:27 -07:00
Ali Chraghi
1f748d1be8
glfw: repatch undefined behavior in X11 keypress handling (#150)
repatch undefined behavior in GLFW which did not land yet and was accidentally removed when updating GLFW in #136 

See glfw/glfw#1989

Fixes hexops/mach#149
2021-12-28 03:57:08 -07:00
iddev5
dc2f2b2a12 glfw: improve documentation for native.zig
- Added hidden error returns
- Improved return types
- Updated docs to glfw 3.3.6
2021-12-28 03:52:22 -07:00
Ali Chraghi
494eb81b56
glfw: expose glfwSetErrorCallback for retrieving optional error descriptions 2021-12-25 11:32:12 -07:00