Silk.NET/documentation/structure-chaining
Craig Dean 0a5aedec11
Vulkan struct chaining (#706)
* feat: Initial working sample

* Created class library with 3 chainable structs
* Added `IChainable` interface hierarchy
* Added chaining methods `Chain`, `CreateNext`, `SetNext` and `End`
* Added tests

* feat: Now supports limiting allowed structs.

* Added tests to check that invalid structs don't compile
* Minimal additional code required per struct
  - just add an interface for each allowed `PNext` struct; and,
  - add a short static method `Chain` (technically optional), and a short instance method `SetNext`.

* docs: Added Readme.md

* fix: Change __makeref to Unsafe.AsPointer

* chore: Retargeting

Retargeted project to ensure that it only targets the same includes,
etc. as `Silk.Next.Core` and `Silk.Net.Vulkan`

* refactor: Various changes

* Added `IStructureType` for any struct that has a
  `StructureType SType` field.  This is usually added automatically
  by one of the other interfaces; and allows the structure type to
  be automatically corrected and retrieved using the
  `StructureType IStructuredType.StructureType()` method.
* Added `IChainStart` to indicate a type that can form the start of
  a chain.
* `IChainable<...>` was replaced with `IExtendsChain<T>` which matches
  the Vulkan specification more readily.
* The chaining methods now all accept, and return, a reference to an
  `IChainStart`, making it easier to scan a chain for existing items,
  and making use of the auto-generated `IExtendsChain<T>` to validate
  types at compile time.
* `SetNext`, by default, will now replace existing chain entries if
  they match the supplied `SType`.  This behaviour can be overriden with
  the optional `alwaysAdd` parameter.
* `CreateNext` is now called `AddNext` to indicate it always adds to the
  end of a Chain.cs
* `TryAddNext` added to only create a new structure if it is not already
  there.
* `IndexOf` added to return the index of a structure in a chain.
* Updated Readme.md.

* chore: Updated readme.md

Updated `Changes Required` section.

* feat: Added ManagedChain

* ManagedChain holds structures in unmanaged memory, preventing
  their movement, and it can be safely held on the heap itself.
* It allows for easy modification and manipulation of the chain.

* feat: Added static `ManagedChain.Create` example

* feat: ManagedChain uses a single memory block.

* feat: Added T4 template.

`ManagedChain` now supports 2-16 chain items.

* feat: Added `ManagedChain.Append`

Can now easily append an item to an existing `ManagedChain` to
efficiently create a new `ManagedChain`.

* feat: Loading of unmanaged chains

`ManagedChain` now has a constructor that will load an unmanaged chain
allowing it to be safely stored on the heap.

* feat: Added `IReadOnlyList` support to `ManagedChain`

* feat: Added deconstructor to `ManageChain<...>`

* feat: Added static `ManagedChain.Load`

Also improved loading to detect when the unmanaged chain is too long.

* chore: Readme.md updated

* chore: Added Lab projects to Solution

Also added the new blank proposals.

* chore: Fixed issues with previous commit

* docs: Finished initial draft #1

Proposal - Vulkan Struct Chaining - #1 StructureType correction.md

* docs: Embedded code sample directly into Proposal #1

* docs: Updated the Unmanaged Chaining Proposal.

* chore: Minor fixes to lab

* Restored targets for PrototypeStructChaining.csproj to match
  `Silk.Net.Vulkan` targets.
* Upped the generated `ManageChain<T...` to 16.

* docs: Initial work on Managed Chaining Proposal.

* docs: Finished draft proposal for Managed Chains

* feat: Numerous enhancements to ManagedChains

* IChainable now exposes `Chain* PNext` property.
* Added `ManagedChain<TChain>` as smallest chain (just the head)
* All `IntPtr`s are replaced with `nint`s.
* Pointer offsets are calculated once per chain type and stored in
  statics, meaning that a chain contains a single `nint` field
  internally, making it incredibly lightweight.  Getting the sizes once
  may also improve the performance, and has simplified the code.
* Various fixes to ensure tail always has `PNext` set to `null` (0).
* Added `Truncate` instance methods.

* docs: Updated Chaining proposals to match new functionality.

Also cleaned up some tests.

* feat: Added chain metadata extensions.

* Added the `Extensions`, `Extenders`, `ClrTypes` and `StructureTypes`
  dictionaries to `Chain`.
* Added the `ClrType`, `StructureType`, `IsChainStart`, `IsChainable`,
  `CanExtend` and `CanBeExtendedBy` extension methods to
  `ChainExtensions`.
* Finished Proposal #4 on Chaining Metadata extension.

* docs: Added suggestion for specific chain interfaces

* docs: Updated to use `BaseInStructure`

* `Chain` was replaced by `BaseInStructure`, which is supplied by the
  Vulkan Specification already.
* `ChainExtensions` was renamed to `Chain`.

* feat: Implements `IStructuredType`

Full implementation of
[proposal 1](866f2dcdcc/documentation/proposals/Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md).

* Adds `$VKSTRUCTUREDTYPE` intrinsic to indicate that a struct
  implements `IStructuredType`, and includes the default `StructureType`
* Adds `IStructuredType` interface to relevant structs, implementing
  them explicitly.

* feat: Implements Unmanaged Chains

Full implementation of [Proposal 2]
(866f2dcdcc/documentation/proposals/Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md)

* Added `IReadOnlyList<string> Extends` property to
  `StructureDefinition`, to store the `structextends` values.
* Added `string Alias` property to `StructureDefinition`, to store the
  value of the `alias` attribute.
* Added `Clone()` methods to `Struct` and `Attribute`, to make
  alias creation faster and easier.
* `VulkanReader` creates aliases by cloning existing structs, making it
  slightly faster to build.  This speed improvement is then used to
  handle the complex chaining logic which requires alias expansion,
  creating a net even performance.
* Added `$VKCHAINABLE` intrinsic to indicate a structure is
  `IChainable` (a lower bar than a chain start or chain extension).
* Added `$VKALIASOF` intrinsic to indicate a structure is an alias of
  another structure.
* Added `$VKALIASES` intrinsic to indicate which structures are aliases
  of the current structure.
* Added `$VKEXTENDSCHAIN` intrinsic to indicate which structures the
  current structure extends.
* Added `$VKCHAINSTART` intrinsic to indicate which structures the
  current structure can be extended by.
* `StructWriter` uses the intrinsics to annotate the structs.
* Added `Chain` extensions from proposal.
* Added `IChainable`, `IChainStart` and `IExtendsChain` interfaces from
  proposal.
* `ProjectWriter` has `GetFilename` added, which will disambiguate
  filenames whenever case-sensitivity is an issue (hasn't actually
  occurred yet though).

TODOs
* Update `PrototypeStructChaining` projects to remove manually generated
  code and instead link directly to `Silk.NET.Vulkan` project.
* Run tests to confirm functionality.
* Update proposals with any changes (e.g. `IChainable.PNext`)
* Consider what to do with teh 208 structures (out of 739) that
  implement `IChainable` directly (i.e. are not part of a specified
  chain).
* Check in the changes to generated structs in a standalone commit.

* chore: Committing structure changes

Commiting just the auto-generated files to not muddy other commits.

* fix: Fixed capitalization of struct aliases.

* chore: Committing structure changes

* feat: Linked `PrototypeStructChaining` projects to implementation

* Removed the manually generated code that is replaced by the
  auto-generated code now that it is implemented
* Removed the solution.
* Corrected namespace to `Silk.NET.Vulkan`.
* Fixed issue clash of `System.Buffer` and `Silk.NET.Vulkan.Buffer`.

* feat: Added `Any` overloads

As ~30% of Vulkan Structures are purely `IChainable`, that is they are
not included in one of the Vulkan Specification `structextends` chains,
but do implement `SType` and `PNext` correctly, I have added `Any`
versions of each of the unmanaged chain extension methods.  These
methods accept `IChainable` directly for the `chain` and `next`
parameters, making them work with any `IChainable` structure.

Indeed the stricter non-`Any` methods, call the looser `Any` methods
directly and serve merely as more rigorous compile time checks.

Improved the inline documentation of the extensions methods.

* docs: Updated the first two proposals

Added details about PRs and the new `Any` extension methods.

* feat: Added `Any` functionality to `ManagedChain`

* Removed instance methods and converted into static extension methods.
* Added `Any` equivalents with looser constraints.
* Various fixes to make prototype match more closely with current draft
  implementations, and `Silk.NET.Vulkan`.
* Added tests.
* Added efficient equality overloads.
* Added ToString().
* Expose the `HeadPtr` and `Size` in the base class.

* feat: Added `GetHashCode` implementation

This is a proposed implementation that only checks the start of the
payload.  We may change this to check the full payload

Also updated the proposals to match the new `Any` functionality.

* fix: Fixed GetHashCode

Fixed broken pointer arithmetic.  Also changed to hash entire structure
for better separation.

* feat: Moved ManagedChain.gen.tt to Silk.NET.Vulkan

* feat: `IExtendsChain` constraints reviewed.

* `TChain` is constrained to `IChainStart`, it should only be
  constrained to `IChainable` on `*Any` extensions, not the interface.

* refactor: Renamed `ManagedChain` to `Chain`

* All extension methods now in `ChainExtensions`.
* Also corrected Proposal 3, and updated references from `Append` to
  `Add` to match code (and Working Group request).

* refactor: Changed Marshal calls

* Changed all chain constructs to be the tighter `unmanaged` constraint
  (as opposed to `struct`) guaranteeing blittability.
* Replaced `Marshal.StructureToPtr` calls with faster
  `System.Buffer.MemoryCopy` calls (as structs are all `unmanaged`).
* Replaced `Marshal.AllocHGlobal` with `SilkMarshal.Allocate` and
  `Marshal.FreeHGlobal` with `SilkMarshal.Free`.
* Remove `Marshal.DestroyStructure` calls (as structs unmanaged).
* Replaced `Marshal.SizeOf` with `sizeof`.

* feat: Added mutation method to base `Chain`

* Split out non-auto-generated code in `Chain` to `Chain.cs` for easier
  maintenance.
* Added `AddAny`, `DuplicateAny` and `TruncateAny` instance methods to
  `Chain` to allow for easier manipulation of runtime chains.
* Added new `MaximumCount` property to `Chain` to indicate the currently
  supported maximum (16).

* feat: Optimised copy

* Removed unnecessary `MemoryCopy` calls.
* Moved modification extension methods back into instance, this allows
  the return type to be overriden for concrete classes (i.e. `Duplicate`
  on the concrete class will return the concrete type, overriding the
  base class version, which returns `Chain`).
* Removed `DuplicateAny` as you type constraints are checked again on
  duplication.  (Base method also renamed to `Duplicate`).
* `IExtends<TChain>` constraint relaxed back to `IChainable`.  This is
  required as it doesn't really add anything but it prevents loosely
  constrained types checking if a type extends their head.  This became
  an issue when returning the extension methods to the instance.

* chore: Moved tests to `Silk.NET.Vulkan.Test`

* feat: Added `Chain.Clear` method.

* Sets all chain elements (optionally excluding the head) to their
  default value.

* feat: Added implicit conversions to `Chain`

* Implicit conversion added to convert to `nint`, `void*` and
  `BaseInStructure*` to convert to a pointer to the head of the chain,
  for all `Chain` classes, including the abstract base `Chain`.
* Implicit conversion added to convert to `TChain*` for the concrete
  `Chain<TChain...>` classes.
* Added missing license header to interfaces

* docs: Started adding documentation for structure chaining.

* testing: Added tests for casts and Clear

Fixed namespace for `Silk.NET.Vulkan.Test` tests.

* feat: Added `IEquatable<Chain>` to `Chain`

* Also added operator overloads.

* docs: Finished all but structure chaining docs

* Removed implemented proposals
* Renamed Metadata proposal (as this will remain on hold and isn't in
  the scope of this PR)
* Added Chaining UML class diagram
* Updated TOCs
* Documented Managed chaining
* Added correct summary comments to `Chain` equality operator overloads.

* chore: Added license to top of `Chain.gen.cs`

* Update src/Core/Silk.NET.BuildTools/Bind/StructWriter.cs

Co-authored-by: Dylan Perks <11160611+Perksey@users.noreply.github.com>

* Update src/Core/Silk.NET.BuildTools/Bind/StructWriter.cs

Co-authored-by: Dylan Perks <11160611+Perksey@users.noreply.github.com>

* Update src/Core/Silk.NET.BuildTools/Bind/StructWriter.cs

Co-authored-by: Dylan Perks <11160611+Perksey@users.noreply.github.com>

* chore: Removed imported .idea files.

* chore: Renamed `Silk.NET.Vulkan.Test` to `Silk.NET.Vulkan.Tests`

* fix: Full disposal pattern implementation for `Chain`

Added finalizer and `GC.SuppressFinalize(this)` when disposing
explicitly.

* fix: Renamed `Chain.gen.cs` to `Chain.g.cs`

`BuildTools` deletes all `.gen.cs` files which can cause collisions.

* docs: Finished first pass of documentation

* Removed the Unmanaged Chaining proposal as implemented.

* feat: Optimized `Chain.Load(TChain)`

* No longer allocates a `StringBuilder` when no `out string errors` is
  required.
* Added CS0661 suppression to `Chain` base class, as `GetHashCode()` is
  correctly overriden in concrete descendents.

Co-authored-by: Dylan Perks <11160611+Perksey@users.noreply.github.com>
2021-12-03 11:31:39 +00:00
..
chaining.puml Vulkan struct chaining (#706) 2021-12-03 11:31:39 +00:00
chaining.svg Vulkan struct chaining (#706) 2021-12-03 11:31:39 +00:00
managed-chaining.md Vulkan struct chaining (#706) 2021-12-03 11:31:39 +00:00
overview.md Vulkan struct chaining (#706) 2021-12-03 11:31:39 +00:00
raw_chaining.md Vulkan struct chaining (#706) 2021-12-03 11:31:39 +00:00
structure-chaining.md Vulkan struct chaining (#706) 2021-12-03 11:31:39 +00:00
vulkan.md Vulkan struct chaining (#706) 2021-12-03 11:31:39 +00:00