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

New unmanaged API, with infallible options for certain parts #57

Merged
merged 11 commits into from
Nov 8, 2024

Conversation

vancluever
Copy link
Owner

This merges our long-running feature branch that re-tools the API under our new architecture. With this setup:

  • Surface is now unmanaged, with an option to use an infallible version through the use of initBuffer,
  • Pattern is now infallible, simply through the use of a simple single-pixel source for the time being, although the intention is to ensure this continues to be the case as we add more complex patterns,
  • Path is now unmanaged, with an option to use an infallible version through StaticPath,
  • Internal painter methods have been prompted to public API through the painter package, with a purely unmanaged interface (but not infallible unfortunately, see below),
  • Finally, Context is now the only remaining managed interface, which pulls all the above components together.

This completes #44 for the time being, leaving only drawing (e.g., z2d.painter.fill() and z2d.painter.stroke()) as being the only functionality that remains memory fallible with no option to make it infallible. This is due to the fairly large and indeterminate amount of memory required during these operations - polygons currently are a bit too large size-wise and there can be any number of them during a particular operation, which makes me hesitant to make a FixedBufferAllocator for them. We additionally need surfaces for compositing, which require memory, although arguably much less after #50, (although #53 re-introduced the allocator for a fallback on edge finding to make the FBA much more reasonably sized as well).

I'm expecting that plotting and rasterization will continue to be improved upon in further releases, and that through this, we could possibly get to a truly infallible model here as well.

This moves Surface and ImageSurface to an unmanaged, infallible design:

* Allocators are no longer stored in the surface.
* Anything that needs an allocator (e.g., init, deinit, and downsample)
  requires the same allocator to be used across the lifetime of the
  surface, as you would expect with unmanaged patterns within Zig.
* The only function that returns an error now is init. Every other
  function has a well-defined failure mode. Particularly, getPixel will
  return null on out-of-bounds requests, and setPixel will no-op.
  Additionally every pixel is valid on a surface for setPixel and
  paintPixel, using copySrc now instead of fromPixel (essentially making
  mismatched pixel types a cast).

Additionally, ImageSurface has gotten an initBuffer initializer. Using
this function, the only sanity checking that's done is that you're using
non-negative values for width and height; negative values cause a panic
instead of an error. Otherwise, you are expected to have supplied the
appropriately sized buffer for the appropriate type. There is a
counterpart downsampleBuffer to use when you use this
bring-your-own-buffer approach, so you don't have to supply an allocator
to anything else (as if you did, it would be an illegal operation).

Note that due to the current state of the language and ptrCast-ing
between slices of different alignments, initBuffer is currently not
exposed in the union interface. As such, if you want to use initBuffer,
you have to call the type function directly and then use
asSurfaceInterface.
Surface: move to unmanaged and infallible design
This commit changes Path to be a fully unmanaged struct, which
essentially means changing its backing ArrayList to ArrayListUnmanaged.
All general calls to Path now require an allocator, which is then passed
to the ArrayListUnmanaged calls.

In addition to this work, however, we have broken off a number of the
calls to have AssumeCapacity counterparts, and also added initBuffer.
Most of these calls are completely infallible (not just memory
infallible, since they no longer require checking for allocation
errors); the only fallible calls that remain are the ones that require a
current point.

This also does a couple of other things:

* arc has now been split into arc and arcNegative, similar to Cairo -
  one draws clockwise, the other draws counter-clockwise.

* tolerance for arc calculations have now been removed from the arc
  calls., instead being a setting in the Path itself.

Both of these things vastly simplifies the use of the arc calls, and
sets the stage for further refactoring (specifically, the Context will
be managing synchronizing tolerance between it and its embedded Path).

Additionally, Path.close has had an ineffectual check for an initial
point moved to an assert. We had this put in an else clause when
capturing the optional before, but since the refactor and a move to
including the AssumeCapacity counterparts, this has proven unnecessary.
This makes closeAssumeCapacity completely infallible.

Finally, we have introduced a *completely infallible* interface to Path
called StaticPath. This type function wraps a buffer of a comptime-known
node length, with functions that call out to the AssumeCapacity
counterparts. Any of the calls that do require a current point are
safety-checked undefined behavior when they are called without a current
point.
Path: move to unmanaged design, introduce StaticPath
This makes the public painter interfaces public, and setting them up so
that they can be used in an unmanaged way.

The idioms of the new "fill" and "stroke" operations are set up so that
take take a required allocator, surface, pattern, and nodes to plot.
Additionally, an options struct is supplied to both which contain
optional arguments for both operations, with defaults that are in line
with what is currently available to both in the Context. This allows for
default behavior of these various operations should the user wish to do
so.
This is a pretty minimal change that brings Pattern idioms in line with
Surface idioms.

Since we have not implemented anything else other than single-pixel
surfaces yet, this is a pretty simple change; OpaquePattern is already
not a reference, so all that's needed adjusting is the args in the
painter functions, and setting getPixel to not return an error.

The getPixel API may eventually change depending on what the expectation
will be for patterns for returning pixels potentially out of bound from
a pattern that represents something with boundaries, such as a surface.
painter: public interface and small pattern tweaks
This commit is the final piece of the current API overhaul - the managed
Context.

This is now the place where all managed drawing operations are expected
to take place. It pulls together all of our umnanaged components -
surfaces, patterns, paths, and painter operations, and provides a
managed frontend to these operations, doing things such as holding an
allocator for said unmanaged operations (that need one), and providing
synchronization of settings such as transformation matrices and
tolerance.

Helpers have been added to get and set every setting within the context;
it's now considered unsupported behavior for a consumer to set a field
directly on a context (or need to set one directly, for that matter,
which should help steer further updates).

If someone requires functionality that the Context is incapable of
providing or would be considered unsuitable for the context, the
recommendation is to now use the individual components in an unmanaged
way. For this, the Context serves as an example for how this can be
done.
@vancluever vancluever changed the title Unmanaged infallible New unmanaged API, with infallible options for certain parts Nov 8, 2024
@vancluever vancluever merged commit 80c5d00 into main Nov 8, 2024
2 checks passed
@vancluever vancluever deleted the unmanaged-infallible branch November 8, 2024 22:48
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

Successfully merging this pull request may close these issues.

1 participant