diff --git a/.github/workflows/publish-site.yml b/.github/workflows/publish-site.yml new file mode 100644 index 0000000000..af72957721 --- /dev/null +++ b/.github/workflows/publish-site.yml @@ -0,0 +1,41 @@ +name: Website Build +on: + push: + branches: + - 'develop/3.0' + pull_request: +permissions: + contents: read + pages: write + id-token: write + +jobs: + Build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Build Website + run: | + git submodule update --init eng/submodules/silk.net-2.x + cd eng/submodules/silk.net-2.x + git fetch --all + cd ../../.. + ./build.sh website + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload artifact + if: ${{ github.repository == 'dotnet/Silk.NET' && github.ref == 'refs/heads/develop/3.0' }} + uses: actions/upload-pages-artifact@v3 + with: + path: "artifacts/docs/Silk.NET" + Deploy: + if: ${{ github.repository == 'dotnet/Silk.NET' && github.ref == 'refs/heads/develop/3.0' }} + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: Build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 75f2abc969..5dc51027a7 100644 --- a/.gitignore +++ b/.gitignore @@ -479,6 +479,7 @@ excluded-platforms.txt #/docs/ src/Website/Silk.NET.Statiq/temp src/Website/Silk.NET.Statiq/cache +.nuke/temp # SilkTouch configs !eng/silktouch/**/*.rsp diff --git a/.gitmodules b/.gitmodules index d85455309c..9482c62aa0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "eng/submodules/sdl"] path = eng/submodules/sdl url = https://github.com/libsdl-org/SDL +[submodule "eng/submodules/silk.net-2.x"] + path = eng/submodules/silk.net-2.x + url = https://github.com/dotnet/Silk.NET diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index 442ad86962..a0081d478f 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -34,7 +34,8 @@ "PushToNuGet", "RegenerateBindings", "ShipApi", - "SignPackages" + "SignPackages", + "Website" ] }, "Verbosity": { @@ -181,6 +182,10 @@ "type": "string" } }, + "SkipContributorsScrape": { + "type": "boolean", + "description": "If enabled, skips scraping the contributors for the authors.yml file of the blog" + }, "Solution": { "type": "string", "description": "Path to a solution file that is automatically loaded" diff --git a/docs/for-contributors/README.md b/docs/for-contributors/README.mdx similarity index 92% rename from docs/for-contributors/README.md rename to docs/for-contributors/README.mdx index f681d2a239..c2567035cc 100644 --- a/docs/for-contributors/README.md +++ b/docs/for-contributors/README.mdx @@ -1,3 +1,10 @@ +--- +title: "Overview" +--- + +import DocCardList from '@theme/DocCardList'; +import { useCurrentSidebarCategory } from '@docusaurus/theme-common'; + # The Silk.NET Contributors Guide Welcome to the Silk.NET project! We're so glad you want to help us create the best native interoperation experience that @@ -9,9 +16,9 @@ the codebase and hit the ground running. ## Table of Contents - [Getting Started (you are here!)](#getting-started) +- [Contribution Process](../CONTRIBUTING.md) - [Build System](build-system.md) - ## Getting Started ### Prerequisites @@ -55,3 +62,4 @@ where the values for the `-s` arguments are replaced with the job names (the key For more information on SilkTocuh arguments, consult the [SilkTouch User Guide](../silktouch) or use `dotnet run --project sources/SilkTouch/SilkTouch/Silk.NET.SilkTouch.csproj -- --help`. + e.label != "Overview")} /> diff --git a/docs/for-contributors/generators/README.md b/docs/for-contributors/generators/README.md deleted file mode 100644 index c5b04edb01..0000000000 --- a/docs/for-contributors/generators/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# SilkTouch - -SilkTouch is the Silk.NET project's C# native interoperability code generation stack. It contains useful generators which together generate the majority of the library's codebase. - -It does this by centering all parts around a [common symbol layer](./symbol-layer/README.md), which allows other parts to be used in any configuration deemed useful, parts don't have a way other then the symbol layer to exchange data, enforcing interoperability. - -Learn more about each individual cornerstone of the SilkTouch Stack: - -- [Symbol Layer](./symbol-layer/README.md) -- [Emitter](emitter.md) -- [Scraper](scraper.md) - -TODO: Add a link to the original proposal once the proposals folder has been reorganised according to the Software Development Plan. diff --git a/docs/for-contributors/generators/emitter/README.md b/docs/for-contributors/generators/emitter/README.md deleted file mode 100644 index fe733a1755..0000000000 --- a/docs/for-contributors/generators/emitter/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Emitter - -The emitter is responsible for creating Roslyn C# Code Symbols from our symbol layer. - -See [here](./about%20formatting.md) for how formatting works, and [here](./visitor.md) for details on the visitor implementation. - -In general the emitter tries it's best to be very basic doing only the job of 1:1 translating shared symbol layer into C# roslyn symbols. diff --git a/docs/for-contributors/generators/emitter/about formatting.md b/docs/for-contributors/generators/emitter/about formatting.md deleted file mode 100644 index c0c08aaa45..0000000000 --- a/docs/for-contributors/generators/emitter/about formatting.md +++ /dev/null @@ -1,38 +0,0 @@ -# About Formatting - -This document is just a sink for all things related formatting. -If your code is acting up and spitting out unreadable garbage, or you want to improve code style - READ THIS FRIST! - -## Indentation - -The emitter implements a very basic system based on 4 members: `Indent()`, `Outdent()`, `NewLine`, `Indentation` - -- `Indent()`: After this call indentation will be more -- `Outdent()`: After this call indentation will be less -- `NewLine`: Put this when you want to go to the next line. It automatically handles putting the right amount of spaces after. -- `Indentation`: only use this if absolutely necessary. It's only there as a safety net - -The common pattern is something like this: - -```cs -Indent() -var members = memberSymbols.Select(s => { - VisitSomething(s); - if (_syntax is not SomeSyntax memberSyntax) - throw Something; - ClearState(); - memberSyntax = memberSyntax.WithLeadingTrivia(NewLine); - return memberSyntax; -}).ToArray(); -Outdent(); - -// use members somehow -``` - -Note the `.ToArray()` this forces execution to happen during the indent/outdent scope. - -## On Trivia - -Prefer using leading trivia over trailing trivia. This is because leading trivia is impossible to leak outside of the symbol you are working on, while trailing trivia easily does this. While sometimes inconvinient because the parent symbol you have no control over leaks it's trivia into your symbol, it's still preferable - had the parent symbol followed this advice it couldn't leak into your symbol right now. Do us all a favor. - -Similar things apply at the micro level too - use leading trivia on braces over trailing trivia on identifiers. This improves the editing experience when adding extra things later and massively improves the reviewers understanding, as there are simply fewer changes. diff --git a/docs/for-contributors/generators/emitter/visitor.md b/docs/for-contributors/generators/emitter/visitor.md deleted file mode 100644 index 83e6fba60d..0000000000 --- a/docs/for-contributors/generators/emitter/visitor.md +++ /dev/null @@ -1,39 +0,0 @@ -# Visitor - -See [here](../symbol-layer/symbol-visitor.md) for details on how the base symbol visitor works. - -To Transform our internal symbol layer to C# code a visitor (`CSharpEmitter.Visitor`) is used. - -## State - -To communicate produced syntax nodes with the levels above the current one the state variables are used. -Therefore its important to enshure that this state is clear at all times. (Using `AssertClearState` & `ClearState`) - -## Depth First - -In general we try to push symbols down as far as possible to avoid code duplication and increase testable surface area. -The best example of this that instead of creating identifier tokens / identifier name syntax nodes inline (which would be very easy) we visit the identifier, letting the `VisitIdentifier` function create those, and then take what we need, using a pattern like - -```cs -VisitIdentifier(structSymbol.Identifier); -if (_syntaxToken is not { } identifierToken) - throw new InvalidOperationException("Some Identifier was not visited correctly"); -ClearState(); -``` - -when a token is required, or - -```cs -VisitIdentifier(fieldSymbol.Type.Identifier); -if (_syntax is not IdentifierNameSyntax typeIdentifierSyntax) - throw new InvalidOperationException("Some Identifier was not visited correctly"); -ClearState(); -``` - -when a syntax node is required. - -## Trivia - -The visitor is intended to produce "valid" code, that means it can be formatted using .ToFullString and the resulting code is valid and can be parsed back by roslyn. -In addition we try to avoid elastic trivia wherever possible. For performance reasons we don't want to normalize our trivia / syntax internally, but elastic trivia would be thrown away when doing so, therefore we try to avoid generating elastic trivia in the first place. -Integration tests should test for elastic trivia, although their primary purpose is to check the resulting formatted string. diff --git a/docs/for-contributors/generators/scraper.md b/docs/for-contributors/generators/scraper.md deleted file mode 100644 index 5fba76f0c0..0000000000 --- a/docs/for-contributors/generators/scraper.md +++ /dev/null @@ -1,16 +0,0 @@ -# Scraper - -The Scraper will call into ClangSharp to generate XML from the given C headers (`GenerateXML`), and then convert the output produced by ClangSharp into symbols defined by the [Symbol Layer](./symbol-layer/README.md) (`ScrapeXML`). - -The Scraper should stay quite small and easy to use, as it is also the window to all the complexity that comes from C++, Clang, header, etc. It should only bridge the XML output into the symbol layer. - -## Scraping XML - -To scrape XML there is a visitor that visits each XML node and outputs several symbols per node. -This is what happens in `XmlVisitor.cs`, called from `ScrapeXML`. - -## Generating XML using ClangSharp - -This is what happens in `ClangScraper.cs`, which is configured using `ClangScraperConfiguration.cs`. -The XML is generated by the `ClangSharp.PInvokeGenerator` see [dotnet/ClangSharp](https://github.com/dotnet/ClangSharp) and the [PInvokeGenerator file](https://github.com/dotnet/ClangSharp/blob/main/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs). -Check XML docs for details on what methods do. diff --git a/docs/for-contributors/generators/symbol-layer/README.md b/docs/for-contributors/generators/symbol-layer/README.md deleted file mode 100644 index 028353bce1..0000000000 --- a/docs/for-contributors/generators/symbol-layer/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Symbol Layer - -The symbol layer is a set of types in the Silk.NET.SilkTouch.Symbols, all inheriting from the central Silk.NET.SilkTouch.Symbols.Symbol type. - -The symbol layer is intended as a way to represent data passed between components of SilkTouch and is entirely immutable, with the only exception being the [Type Store](./type-store.md). - -The way to update & iterate symbols is using a [Symbol Visitor](./symbol-visitor.md). - -See [symbols](./symbols/README.md) for a list of all symbols, their visitor method, test details, etc. - -See [type references](./type-references.md) for an explanation of type references. diff --git a/docs/for-contributors/generators/symbol-layer/symbol-visitor.md b/docs/for-contributors/generators/symbol-layer/symbol-visitor.md deleted file mode 100644 index a1c3b97d58..0000000000 --- a/docs/for-contributors/generators/symbol-layer/symbol-visitor.md +++ /dev/null @@ -1,19 +0,0 @@ -# Symbol Visitor - -A symbol visitor visits each symbol and then calls the appropriate methods to recursively visit all parts. -Each symbol visitor has access to a [type store](./type-store.md). It has to be provided in the constructor of every symbol visitor. -It's generally adviced to simply bubble up this constructor parameter to users of your type. - -## Updating Symbols - -Each method returns the same type it gets as parameter, so prefer to override the most specific method possible. -For example, if you wish to rename all `TypeSymbol`s, override `VisitTypeSymbol`. But if you want to add a field to every struct, override `VisitStructSymbol`. If you want to rewrite the type of a symbol, for example generate a class for every struct, again, override the most specific method that is compatible with both (in this case `VisitTypeSymbol`) and do type checks as necessary. - -### Type IDs - -See [type store](./type-store.md) for details on what type Ids are. -**Do not change type IDs when visiting symbols. This breaks all references to that type.** - -## Managing State - -While the base `SymbolVisitor` is stateless, derived types are free to introduce (mutable) state. This allow propagating state other then the new symbol up the tree. diff --git a/docs/for-contributors/generators/symbol-layer/symbols/README.md b/docs/for-contributors/generators/symbol-layer/symbols/README.md deleted file mode 100644 index 6cd34caa64..0000000000 --- a/docs/for-contributors/generators/symbol-layer/symbols/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Symbols - -This document / folder is for tracking all the available symbols, and documenting what creation of one entails. - -## Relation to SymbolVisitor - -In general each symbol listed below should have a corresponding method `VisitMySymbol` the only exception being `UnresolvedTypeReference` as only few visitors should ever interact with it. - -## List - -(Order alphabetically please!) - -Parent Symbols (Unlisted, abstract): -| Name | See Also | -| ---- | -------- | -| MemberSymbol | | -| Symbol | | -| TypeReference | [here](../type-references.md) | -| TypeSymbol | | -| MethodSymbol | - -| Name | Symbol Layer File | Symbol Layer Tests | Emitter Tests | -| ---------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -| ClassSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/ClassSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/ClassSymbolTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/ClassSymbolTests.cs) | -| ExternalTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/ExternalTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/ExternalTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/ExternalTypeReferenceTests.cs) | -| FunctionPointerTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/FunctionPointerTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/FunctionPointerTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/FunctionPointerTypeReferenceTests.cs) | -| FieldSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/FieldSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/FieldTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterFieldTests.cs) | -| IdentifierSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/IdentifierSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/IdentifierTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/IdentifierSymbolTests.cs) | -| InternalTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/InternalTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/InternalTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/InternalTypeReferenceTests.cs) | -| NamespaceSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/NamespaceSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/NamespaceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterNamespaceTests.cs) | -| PointerTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/PointerTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/PointerTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/PointerTypeReferenceTests.cs) | -| StaticExternalMethodSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/StaticExternalMethodSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/StaticExternalMethodSymbolTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/StaticExternalMethodSymbolTests.cs) | -| StructSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/StructSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/StructTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterStructTests.cs) | -| UnresolvedTypeReference | [here](src/generators/Silk.NET.SilkTouch.Symbols/UnresolvedTypeReference.cs) | [here](tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/UnresolvedTypeReferenceTests.cs) | - | - -## How to create a symbol - -Checklist: - -- [ ] Write a short description of what this symbol does in the above list. -- [ ] Add the symbol to Silk.NET.SilkTouch.Symbols -- [ ] Add a partial of SymbolVisitor to below the definition, and add visiting method in there. -- [ ] Call the new visiting method either from - - The root Visit(Symbol) method, this should rarely be needed - - The parent's visit method -- [ ] Add Tests to Silk.NET.SilkTouch.Symbols.Tests for - - [ ] The type being visited with it's own visiting method - - [ ] The type being visited with it's parent (not needed if this is a new root type, with no parent) - - [ ] Each part being visited correctly. Only shallowly check this, don't check parts of parts. -- [ ] Handle symbol in Silk.NET.SilkTouch.Emitter -- [ ] Add Tests to Silk.NET.SilkTouch.Emitter.Tests - - [ ] Transforming a sample Symbol matching a specific string - - [ ] Other tests, this is highly dependend on how complex the C# output looks like - - [ ] More is better! -- [ ] You're done. Feel free to use the symbol wherever needed. Prefer to add usages in a separate PR. diff --git a/docs/for-contributors/generators/symbol-layer/type-references.md b/docs/for-contributors/generators/symbol-layer/type-references.md deleted file mode 100644 index a17f3c482d..0000000000 --- a/docs/for-contributors/generators/symbol-layer/type-references.md +++ /dev/null @@ -1,14 +0,0 @@ -# Type References - -Type references are a special kind of symbol used to reference types. - -There are several kinds of type references. -During scraping (see [scraper](../scraper.md)) `UnresolvedTypeReference`s are created. -These should be resolved right after, in a process called [type resolution](../type-resolution.md). - -Type resolution leads to a variety of more specialized type references, with the two base ones being - -- `InternalTypeReference`, referencing another newly defined type somewhere in the tree. (Note that it's generally not adviced to define types this way, they should already occur somewhere higher up in the tree) -- `ExternalTypeReference`, referencing some external type, usually well known types from the standard library - -There are several other type reference types, but they are wrappers around other references, for example `PointerTypeReference`. diff --git a/docs/for-contributors/generators/symbol-layer/type-store.md b/docs/for-contributors/generators/symbol-layer/type-store.md deleted file mode 100644 index 1f63fc658b..0000000000 --- a/docs/for-contributors/generators/symbol-layer/type-store.md +++ /dev/null @@ -1,15 +0,0 @@ -# Type Store - -The type store is a simple helper to resolve type identifier to the latest instance. -It's available from inside every [Symbol Visitor](./symbol-visitor.md). - -## Type IDs - -`TypeId`s are a small `struct` intended to help reference types across trees. -This is useful because all symbols are immutable, and this makes it impossible to have loops in the symbol tree. -To allow loops, the type store is mutable and resolves each type id to the latest immutable version. - -## Updating - -The type store needs updating when changing a type. Usually [Symbol Visitors](./symbol-visitor) will do this automatically after visiting a type (`VisitType`), but inheritors overriding this should do this manually using -`Store(TypeSymbol)`. diff --git a/docs/for-contributors/generators/testing.md b/docs/for-contributors/generators/testing.md deleted file mode 100644 index 7c8fa690aa..0000000000 --- a/docs/for-contributors/generators/testing.md +++ /dev/null @@ -1,32 +0,0 @@ -# Testing - -SilkTouch Generators should be extensively Tested. - -## Unit Tests - -See also [symbol creation instructions](./symbol-layer/symbols/README.md) for details on symbol unit tests. - -### Traits - -All Unit & Integration tests should be flagged with the appropriate Category (Emitter, Scraper, Symbols, Integration) using `Trait("Category", "MyCategory")`. -Additionally the following Traits should be applied where appropriate: - -- `Target Language` this should be applied wherever a specific target language is tested (valid Values: `C#`) -- `Source Language` this should be applied wherever a specific source language is tested (valid Values: `C++`) -- `Feature` this should be applied wherever a specific feature is covered, ie `Structs`, `Fields`, `Namespaces`, etc. These at the same time are used as Feature Flags (toggled in Silk.NET.SilkTouch.TestFramework). Tests with features that are not yet implemeneted may be created and simply turned off via these feature flags. (valid Values: not tracked. check `tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFramework.cs`) - -### Symbol Layer - -Unit Tests need to be written for all symbols AND the Symbol Visitor. They should cover that the symbol visitor visits these symbols and their children correctly and any functionality the symbols themselves might implement - -### Scraper - -Tests should be written covering XML -> Symbol conversion. No C(++) -> XML tests are needed as this is the job of clang (sharp). - -### Emitter - -Tests should be written covering Symbol -> C# conversion. - -## Integration Tests - -Integration Tests should exist to cover most if not all areas of the generator. These are simply a sanity check & samples of what the generator can do. Unit Tests are still required. diff --git a/docs/for-contributors/generators/type-resolution.md b/docs/for-contributors/generators/type-resolution.md deleted file mode 100644 index 6f8cbd3840..0000000000 --- a/docs/for-contributors/generators/type-resolution.md +++ /dev/null @@ -1,5 +0,0 @@ -# Type Resolution - -The resolution code lives in Silk.NET.SilkTouch.TypeResolution and is concerned with resolving `UnresolvedTypeReference` to actual `TypeReference`s. - -As the individual parts are only loosely connected and aren't generally dependent on each other, we do not document the individual parts here, please check the XML docs of each of the classes. diff --git a/docs/index.mdx b/docs/index.mdx new file mode 100644 index 0000000000..15f1cd7c66 --- /dev/null +++ b/docs/index.mdx @@ -0,0 +1,77 @@ +--- +title: "Welcome" +id: "index" +description: 'Get Started with Silk.NET' +slug: '/' +--- + +import DocCardList from '@theme/DocCardList'; +import { useDocsSidebar } from '@docusaurus/plugin-content-docs/client' + +# Welcome to Silk.NET! + +## Getting Started + +To get started, install the relevant NuGet packages. They all start with `Silk.NET`, and the next inner namespace after +that indicates the binding or High-Level Utility (HLU, e.g. Windowing or Input) that package belongs. Here' some example +commands to install such NuGet packages: + +```bash +dotnet add package Silk.NET.Assimp +dotnet add package Silk.NET.Input +dotnet add package Silk.NET.Maths +dotnet add package Silk.NET.Direct2D +dotnet add package Silk.NET.Direct3D.Compilers +dotnet add package Silk.NET.Direct3D9 +dotnet add package Silk.NET.Direct3D11 +dotnet add package Silk.NET.Direct3D12 +dotnet add package Silk.NET.DirectComposition +dotnet add package Silk.NET.DirectStorage +dotnet add package Silk.NET.DXGI +dotnet add package Silk.NET.DXVA +dotnet add package Silk.NET.XAudio +dotnet add package Silk.NET.XInput +dotnet add package Silk.NET.OpenAL +dotnet add package Silk.NET.OpenCL +dotnet add package Silk.NET.OpenGL +dotnet add package Silk.NET.OpenGL.Legacy +dotnet add package Silk.NET.OpenGLES +dotnet add package Silk.NET.OpenXR +dotnet add package Silk.NET.Shaderc +dotnet add package Silk.NET.SPIRV.Cross +dotnet add package Silk.NET.SPIRV.Reflect +dotnet add package Silk.NET.Vulkan +dotnet add package Silk.NET.WebGPU +dotnet add package Silk.NET.Windowing +``` + +If you don't know which API you'd like to start with, try OpenGL if you'd like to draw graphics - it's an old but tested +API that has universal compatibility on most platforms. It is succeeded by Vulkan, but there is a large jump in +difficulty thereafter. Alternatively, if you only care about Microsoft platforms, try Direct3D 11! Note that the same +caveat for Vulkan vs OpenGL applies to Direct3D 12 vs Direct3D 11. + +If you can't decide on one for now, we maintain a "metapackage" that pulls in most of Silk.NET's core packages from all +bindings and High-Level Utilities (HLUs). You can install that as follows: + +```bash +dotnet add package Silk.NET +``` + +As always, we're happy to help in our Discord server with whatever questions you have, no matter how far along you are! + +## Find Documentation + +Now that you've pulled in the APIs you would like to use, it's time to find documentation to follow. Most Silk.NET APIs +(other than our High-Level Utilities) map 1:1 directly into a native API signature that should be easily searchable by +its API name (e.g. `glGetString` becomes `GL.GetString` in Silk.NET). Note that these rules are not consistent and it is expected +that you have at least some familiarity with how the native API is structured. + +Of course, there are some bindings for which we have our own introductory documentation for, which presents a good +jumping-off point for new users to Silk.NET - regardless of whether you've used the native API before (e.g. with C/C++) +or you've never seen anything about it before! To that end, you can find our own documentation indexed below or +throughout this site. + + e.label != "Welcome")} /> + +Have fun! We always look forward to seeing what people can create with Silk.NET and would love to hear how you get on in +[our Discord server](https://discord.gg/DTHHXRt). diff --git a/docs/proposals/(Rejected) Proposal - Better Strings.md b/docs/proposals/(Rejected) Proposal - Better Strings.md deleted file mode 100644 index f9bd655589..0000000000 --- a/docs/proposals/(Rejected) Proposal - Better Strings.md +++ /dev/null @@ -1,102 +0,0 @@ -# Summary -A rich, more well-defined native string API. - -- Written against Silk.NET **1.0.2**. -- Slated for Silk.NET **2.0.0**. - -# Contributors -- Dylan P, Ultz Limited - -# Current Status -- [x] Proposed -- [ ] Discussed with API Review Board (ARB) -- [ ] Approved -- [ ] Implemented - -# Design Decisions -Currently, the representation of native strings in Silk.NET (and C# as a whole) is an utter mess. -At the moment we're using `char*` everywhere which isn't technically correct, as a number of users -have pointed out. This discussion aims to create a richer set of native string APIs to combine -technical correctness, ease of marshalling, and ease of use. - -This is in the form of Char8, Char16, and Char32 which represent the various lengths of characters -in various encodings. These CharXXs can be combined into a StringXX. All types can be implicitly -converted to and from their existing C#/.NET types, so that the user doesn't have to deal with much - -# Proposed API -Proposed Silk.NET.Core additions: -```cs -public struct Char8 -{ - private byte _value; // 8-bit character - public Char8(byte v) => _value = v; - public static explicit operator Char8(char c); - public static implicit operator Char8(byte c); - // and vice versa - public char ToChar(); - public byte ToByte(); - public uint ToUInt32(); -} - -public struct Char16 -{ - private char _value; // 16-bit character - public Char16(char v) => _value = v; - // insert appropriate operators and methods here as seen in Char8 -} - -public struct Char32 -{ - private uint _value; // 32-bit character - public Char32(char hi, char lo) => _value = unchecked((uint) char.ConvertToUtf32(hi, lo)); - // insert appropriate operators and methods here as seen in Char8 -} - -public ref struct String8 -{ - private Span _value; - public String8(Span v) => _value = v; - public static implicit operator String8(Span v); - public static implicit operator String8(string x); // not recommended for use, as we'll have to assume the encoding the user wants is UTF8. - public static implicit operator String8(Char8* v); // treat the Char8* as null-terminated - public static implicit operator String8(byte* v); // cast to Char8*, pass to the above. - public static explicit operator String8(char* v); // cast to byte*, pass to the above. for maintaining back-compat with Silk.NET 1.0. - // and vice versa - public override string ToString(); - public ref readonly Char8 GetPinnableReference(); -} - -public ref struct String16 -{ - private Span _value; - public String16(Span v) => _value = v; - // insert appropriate methods and operators here as seen in String8 - public override string ToString(); - public ref readonly Char16 GetPinnableReference(); -} - -public ref struct String32 -{ - private Span _value; - public String16(Span v) => _value = v; - // insert appropriate methods and operators here as seen in String8 - public override string ToString(); - public ref readonly Char32 GetPinnableReference(); -} -``` - -Proposed binder output: -```cs -delegate cdecl* _glGetString; -public String8 GetString(GLEnum name) => (String8) _glGetString(name); -// No need for a string overload, as you can implicitly cast String8 to string. -// Users migrating to 2.0 will simply have to cast the String8 to string (better than them having to marshal it!) -``` - -Proposed GLFW changes: -```cs -delegate cdecl* _glfwSetWindowTitle; -public void SetWindowTitle(WindowHandle* h, String8 t); -``` - -You kinda get the gist from here... diff --git a/docs/proposals/(Rejected) Proposal - Load overrides.md b/docs/proposals/(Rejected) Proposal - Load overrides.md deleted file mode 100644 index d298a058e0..0000000000 --- a/docs/proposals/(Rejected) Proposal - Load overrides.md +++ /dev/null @@ -1,158 +0,0 @@ -# Summary -Load overrides mean a way to override loading native addresses. -This is useful in the following scenarios: -- P/Invoke / statically linked scenarios, mobile. -- Advanced Performance scenarios, such as pre-loading to improve AOT / linking / R2R - -While this API can be used by Hand, and is available for public use it is not designed to be particularly user friendly. -It is designed with SilkTouch as the primary user. (See `PInvokeTableAttribute`) - -This proposal also somewhat defines the currently loose timeline of how addresses are loaded. - - -# Contributors -- Kai Jellinghaus, Maintainer (at time of writing), open source community. - -# Current Status -- [x] Proposed -- [ ] Discussed with API Review Board (ARB) -- [ ] Approved -- [ ] Implemented - -# Design Decisions -There are two separate interfaces to allow maximum flexibility, but also to define exactly at which point slot information is lost. - -# Proposed API -Note that this API may be changed in the future to use function pointers directly instead of IntPtrs. -This deliberately doesn't use nint. -```cs -/// -/// Defines a Load override, capable of loading some entrypoints by name. -/// -/// -/// Load overrides may not cache loads. -/// Load overrides have to be thread safe. -/// -public interface INameLoadOverride -{ - /// - /// The used for loading - /// - INativeContext Context { set; } - - /// - /// Attempt to load an entrypoint by name. - /// - /// The entrypoint name to load - /// The address that was loaded - /// - /// Whether the load was successful. - /// - bool TryLoad(string entrypoint, out IntPtr address); -} - -/// -/// Defines a Load override, capable of loading some entrypoints by slot. -/// -/// -/// Load overrides may not cache loads. -/// Load overrides have to be thread safe. -/// -public interface ISlotLoadOverride -{ - /// - /// The used for loading - /// - INativeContext Context { set; } - - /// - /// Attempt to load an entrypoint by name. - /// - /// The slot to load - /// The address that was loaded - /// - /// Whether the load was successful. - /// This will flush the cache / VTable. - /// - bool TryLoad(int slot, out IntPtr address); -} -``` - -Not a critical change, but would make sense to make the core easier to understand, because Context, to me, implies some kind of state, which this does not provide. -This simply provides a mecanism to load an address, not access to some kind of native state. -```diff -- public interface INativeContext -+ public interface IAddressLoader - : IDisposable -{ -- IntPtr GetProcAddress(string proc); -+ IntPtr GetProcAddress(string entrypoint); -} -``` - -```cs -public abstract class NativeApiContainer -{ - /// - /// Registers an to participate in loading. - /// - /// - /// This method is thread safe. - /// This will flush the cache / VTable. - /// - void RegisterOverride(INameLoadOverride override); - /// - /// Registers an to participate in loading. - /// - /// - /// This method is thread safe. - /// This will flush the cache / VTable. - /// - void RegisterOverride(ISlotLoadOverride override); - /// - /// Registers multiple s to participate in loading. - /// - /// - /// This method is thread safe. - /// This will flush the cache / VTable. - /// - void RegisterOverrides(IEnumerable overrides); - /// - /// Registers multiple s to participate in loading. - /// - /// - /// This method is thread safe. - /// This will flush the cache / VTable. - /// - void RegisterOverrides(IEnumerable overrides); - - // override address loader is thread safe. - private sealed class OverrideAddressLoader - { - // this is loader falls back to the normal _loader, but first calls into overrides. - // an instance is kept around, and recreated whenever a new override is registered. - // for performance reasons it may make sense to defer the creation of this to a Lazy - - public IntPtr Load(int slot, string entrypoint); - } -} -``` - -Load overrides MAY NOT cache addresses. - -These APIs work together with the IVTable, which is the caching solution. - -# Address loading timeline -- NativeApiContainer.Load(int, string) - - VTable - - if cached, return cached result - - otherwise - - OverrideAddressLoader.Load(int, string) - - calls slot overrides in order, returning the first result. - - if none were able to resolve the slot, calls entrypoint overrides in order, returning the first result. - - if none were able to resolve the entrypoint, calls down to the given fallback loader. - - result cached. - -# Open Questions -- it's unclear how this would work with VTable preoloading, we don't use that in Silk.NET right now, so not a problem (for now). -- it's unclear how a user that manually swaps VTables (think Vulkan) would handle it if another user registered an override. there is no way to detect this. It's likely such a user would just not handle this. \ No newline at end of file diff --git a/docs/proposals/(Rejected) Proposal - Platform Hints.md b/docs/proposals/(Rejected) Proposal - Platform Hints.md deleted file mode 100644 index ee97039a56..0000000000 --- a/docs/proposals/(Rejected) Proposal - Platform Hints.md +++ /dev/null @@ -1,86 +0,0 @@ -# Summary -Proposal API for specifying platform-specific window creation hints. - -- Written against Silk.NET **1.0.1**. -- Slated for Silk.NET **1.0.3**. - -# Contributors -- Dylan P, Ultz Limited - -# Current Status -- [x] Proposed -- [ ] Discussed with API Review Board (ARB) -- [ ] Approved -- [ ] Implemented - -# Design Decisions -If Silk.NET's windowing API doesn't expose functionality that the underlying window backend does, we should provide way to allow the user to access this functionality in a semi-dirty if Silk.NET doesn't provide a proper, clean way. - -Officially specified behaviour is as follows -- If the Hint's HintName is not supported on a given windowing platform, the Hint should be silently discarded. -- If the Hint's Value is not of the correct type or format, the Hint should be silently discarded. -- There should be no case where the platform hint API will throw an exception or abort the window creation process. - -# Proposed API - -```cs -public readonly struct Hint -{ - public HintName Name { get; } - public object Value { get; } -} - -public enum HintName -{ - // The format for new hints is for example EglBoolFlugenschlafen - GlfwBoolFocused = 131073, - GlfwBoolIconified = 131074, - GlfwBoolResizable = 131075, - GlfwBoolVisible = 131076, - GlfwBoolDecorated = 131077, - GlfwBoolAutoIconify = 131078, - GlfwBoolFloating = 131079, - GlfwBoolMaximized = 131080, - GlfwBoolCenterCursor = 131081, - GlfwBoolTransparentFramebuffer = 131082, - GlfwBoolHovered = 131083, - GlfwBoolFocusOnShow = 131084, - GlfwBoolStereo = 135180, - GlfwBoolSrgbCapable = 135182, - GlfwBoolDoubleBuffer = 135184, - GlfwBoolOpenGLForwardCompat = 139270, - GlfwBoolOpenGLDebugContext = 139271, - GlfwBoolContextNoError = 139274, - GlfwIntRedBits = 135169, - GlfwIntGreenBits = 135170, - GlfwIntBlueBits = 135171, - GlfwIntAlphaBits = 135172, - GlfwIntDepthBits = 135173, - GlfwIntStencilBits = 135174, - GlfwIntAccumRedBits = 135175, - GlfwIntAccumGreenBits = 135176, - GlfwIntAccumBlueBits = 135177, - GlfwIntAccumAlphaBits = 135178, - GlfwIntAuxBuffers = 135179, - GlfwIntSamples = 135181, - GlfwIntRefreshRate = 135183, - GlfwIntContextVersionMajor = 139266, - GlfwIntContextVersionMinor = 139267, - GlfwIntContextRevision = 139268, - GlfwRobustnessContextRobustness = 139269, - GlfwStringCocoaFrameName = 143362, - GlfwStringX11ClassName = 147457, - GlfwStringX11InstanceName = 147458, - GlfwClientApi = 139265, - GlfwContextCreationApi = 139275, - GlfwContextReleaseBehavior = 139273, - GlfwOpenGlProfile = 139272 -} -``` - -```diff -public struct WindowOptions -{ -+ public Hint[] PlatformSpecificHints { get; set; } // Can be null - we haven't discussed use of ? in the codebase yet -} -``` diff --git a/docs/proposals/(Rejected) Proposal - Region Specific Key Input.md b/docs/proposals/(Rejected) Proposal - Region Specific Key Input.md deleted file mode 100644 index 043a32149a..0000000000 --- a/docs/proposals/(Rejected) Proposal - Region Specific Key Input.md +++ /dev/null @@ -1,141 +0,0 @@ -# Summary -- Make the windowing API return the key actually pressed, or any other key for that matter, instead of the key that is at -the same location on a US-Keyboard. - -# Contributors -- Matija Brown, None - -# Current Status -- [x] Proposed -- [ ] Discussed with API Review Board (ARB) -- [ ] Approved -- [ ] Implemented - -# Design Decissions -- The main aspect is to change the original API as little as possible and also make the region-adapting -toggleable / add the abillity to manually set a keyboard layout. To achieve this diversity, -new layouts can be imported from an external file, but the included ones are hard coded. This way one can easilly switch between -layouts and / or import a new, custome one while the rest of the input API remains unchanged. Due to the fact this is toggleable, -it will also work the same way as before. The layout is saved in the IInputContext, as it is not possible to have different -keyboard layouts on different keyboards at the same time, so it needn't be saved in every keyboard instance. If writing custom layouts -turns out to be a common thing, there will be a layout generator created as well. For now key modifiers such as SHIFT will not be -considered, but that might be implemented at a later time. - -# Proposed API - -## IKeyboardLayout -```cs -internal interface IKeyboardLayout -{ - - /// - /// Gets the name from an instance. - /// - string Name { get; } - - /// - /// Called from GlfwKeyboard.ConvertKey, easy place to get the keys, - /// and no use converting to Silk.NET keys and then swap them arround again. - /// - Key MapKey(Keys glfwKey); - -} -``` - -## QWERTYLayout -```cs -/// -/// Example class for all layouts. -/// -public sealed class QWERTYLayout : IKeyboardLayout -{ - - /// - /// The name of the layout. - /// - public const string NAME = "QWERTY"; - - /// - /// Non-Static name. - /// - public string Name { get } = NAME; - -} -``` - -## CustomLayout -```cs -/// -/// The implementation of custom, file-read layouts. -/// -public sealed class CustomLayout : IKeyboardLayout -{ - - /// - /// Get the name. No static name here because it changes with each file. - /// - public string Name { get => _name } - - /// - /// Loads the file and uses the contained layout as the keyboard layout. - /// - public CustomLayout(string file); - -} -``` - -## KeyboardLayout -```cs -public static class LayoutManager -{ - - /// - /// The QWERTY layout. - /// - public static readonly IKeyboardLayout QWERTY; - ... - - /// - /// Automatically gets the keyboard layout set on the device. - /// - public static IKeyboardLayout GetDeviceLayout(); - -} -``` - -## IInputContext -```diff -+ IKeyboardLayout Layout { get; set } = LayoutManager.GetDeviceLayout(); -``` - -## Layout File -``` -// Original Value In QWERTY -> New Value In Your Layout -// Obviously this is only done for the keys included in GLFW, but as they -// are close to ASCII it should be simple to write. No lowercase letters -// as they only exist on the char callbacks, not the key callbacks. -// The line in double quotes in the beginning of the file is the name. -"ExampleLayout" -65->68 // A will be D -// alternatively, as char and int are interchangeable in c# :) : -A->D -``` - -## Example Usage -```cs -class ExampleUsage -{ - // ... the hello window example here ... - private static void OnLoad() - { - var input = window.CreateInput(); - input.Layout = LayoutManager.QWERTY; - // alternatively: input.Layout = new CustomLayout("exampleLayout.layout"); - foreach (var keyboard in input.Keyboards) - { - keyboard.KeyDown += KeyDown; - } - } - // ... goes on here ... -} -``` \ No newline at end of file diff --git a/docs/proposals/(Superseded) Proposal - Enhanced Input Events.md b/docs/proposals/(Superseded) Proposal - Enhanced Input Events.md deleted file mode 100644 index 05f4aef453..0000000000 --- a/docs/proposals/(Superseded) Proposal - Enhanced Input Events.md +++ /dev/null @@ -1,168 +0,0 @@ -# Summary -Proposal for adding important missing functionality to input, as well as other enhancements. - -# Contributors -- ThomasMiz - -# Current Status -- [x] Proposed -- [x] Discussed with API Review Board (ARB) -- [ ] Approved -- [ ] Implemented - -# Design Decisions -- Event parameters will be turned into readonly structures to prevent long parameter lists in some cases and allow more parameters (such as deltas) to be added in the future without breaking. - -# Proposed API -The only API changes will be to the events presented by IMouse, IKeyboard and possibly other device interfaces. - -## Enums - -#### KeyModifiers -Based on [the modifier keys flag from GLFW](https://www.glfw.org/docs/latest/group__mods.html). -```cs -[Flags] -public enum KeyModifiers -{ - Shift = 1 << 0, - Control = 1 << 1, - Alt = 1 << 2, - Super = 1 << 3, - CapsLock = 1 << 4, - NumLock = 1 << 5 -} -``` - -## Structs - -#### KeyDownEvent -```cs -public readonly struct KeyDownEvent -{ - public IKeyboard Keyboard { get; } - public Key Key { get; } - public int KeyCode { get; } - public KeyModifiers Modifiers { get; } - public bool IsRepeat { get; } - - public KeyDownEvent(IKeyboard keyboard, Key key, int keyCode, KeyModifiers modifiers, bool isRepeat); -} -``` - -#### KeyUpEvent -```cs -public readonly struct KeyUpEvent -{ - public IKeyboard Keyboard { get; } - public Key Key { get; } - public int KeyCode { get; } - public KeyModifiers Modifiers { get; } - - public KeyUpEvent(IKeyboard keyboard, Key key, int keyCode, KeyModifiers modifiers); -} -``` - -#### KeyCharEvent -```cs -public readonly struct KeyCharEvent -{ - public IKeyboard Keyboard { get; } - public char Character { get; } - public int KeyCode { get; } - - public KeyCharEvent(IKeyboard keyboard, char character, int keyCode); -} -``` - -#### MouseMoveEvent -```cs -public readonly struct MouseMoveEvent -{ - public IMouse Mouse { get; } - public Vector2 Position { get; } - public Vector2 Delta { get; } - - public MouseMoveEvent(IMouse mouse, Vector2 position, Vector2 delta); -} -``` - -#### MouseButtonEvent -```cs -public readonly struct MouseButtonEvent -{ - public IMouse Mouse { get; } - public Vector2 Position { get; } - public MouseButton Button { get; } - public KeyModifiers Modifiers { get; } - - public MouseButtonEvent(IMouse mouse, Vector2 position, MouseButton button, KeyModifiers modifiers); -} -``` - -#### MouseScrollEvent -```cs -public readonly struct MouseScrollEvent -{ - public IMouse Mouse { get; } - public Vector2 Position { get; } - public Vector2 WheelPosition { get; } - public Vector2 Delta { get; } - - public MouseScrollEvent(IMouse mouse, Vector2 position, Vector2 wheelPosition, Vector2 delta); -} -``` - -#### MouseClickEvent -```cs -public readonly struct MouseClickEvent -{ - public IMouse Mouse { get; } - public Vector2 Position { get; } - public MouseButton Button { get; } - public KeyModifiers Modifiers { get; } - - public MouseClickEvent(IMouse mouse, Vector2 position, MouseButton button, KeyModifiers modifiers) -} -``` - -## Interface changes - -#### IKeyboard -```cs -public interface IKeyboard : IInputDevice -{ - // The old events get removed: - // event Action KeyDown; - // event Action KeyUp; - // event Action KeyChar; - - // KeyDown reports key down and key repeats - event Action KeyDown; - event Action KeyUp; - - event Action KeyChar; -} -``` - -#### IMouse -```cs -public interface IMouse : IInputDevice -{ - // The old events get removed: - // event Action MouseMove; - // event Action MouseDown; - // event Action MouseUp; - // event Action Scroll; - // event Action Click; - // event Action DoubleClick; - - event Action MouseMove; - event Action MouseDown; - event Action MouseUp; - event Action Scroll; - event Action Click; - event Action DoubleClick; -} -``` - -These changes can also be applied to other IDevices to keep consistency across our API. diff --git a/docs/proposals/(WIP) Proposal - SIMD (Revision).md b/docs/proposals/(WIP) Proposal - SIMD (Revision).md deleted file mode 100644 index 1085bd293f..0000000000 --- a/docs/proposals/(WIP) Proposal - SIMD (Revision).md +++ /dev/null @@ -1,125 +0,0 @@ -# Summary -That will bring a number of minor fixes to the [SIMD Proposal](Proposal%20-%20Vectorization%20-%20SIMD.md). - -# Contributors -- WhiteBlackGoose - -# Current Status -- [x] Proposed -- [x] Discussed with API Review Board (ARB) -- [ ] Approved -- [ ] Implemented - - -# API changes - -`Avx` and `AdvSimd` offer us shifting by a vector, so there is no reason to limit to a fixed amount. Rotation here for consistency with shift. - -`Sign` has been decided to return the sign of the values. So I also suggest `CopySign` method, which would work similarly to Avx's `Sign`. - -Finally, `IsInteger`, `IsFloat`, `IsUnsignedInteger` and `IsSignedInteger` are shorthands for checking if the type is of a certain "class". - -```cs -static Silk.NET.Maths.Simd128.ShiftLeft(Vector128 x, Vector128 amount) -> Vector128 -static Silk.NET.Maths.Simd128.ShiftRight(Vector128 x, Vector128 amount) -> Vector128 -static Silk.NET.Maths.Simd128.RotateLeft(Vector128 x, Vector128 amount) -> Vector128 -static Silk.NET.Maths.Simd128.RotateRight(Vector128 x, Vector128 amount) -> Vector128 -static Silk.NET.Maths.Simd128.CopySign(Vector128 source, Vector128 destination) -> Vector128 - -static Silk.NET.Maths.Simd256.ShiftLeft(Vector256 x, Vector256 amount) -> Vector256 -static Silk.NET.Maths.Simd256.ShiftRight(Vector256 x, Vector256 amount) -> Vector256 -static Silk.NET.Maths.Simd256.RotateLeft(Vector256 x, Vector256 amount) -> Vector256 -static Silk.NET.Maths.Simd256.RotateRight(Vector256 x, Vector256 amount) -> Vector256 -static Silk.NET.Maths.Simd256.CopySign(Vector256 source, Vector256 destination) -> Vector256 - -static Silk.NET.Maths.Simd64.ShiftLeft(Vector64 x, Vector64 amount) -> Vector64 -static Silk.NET.Maths.Simd64.ShiftRight(Vector64 x, Vector64 amount) -> Vector64 -static Silk.NET.Maths.Simd64.RotateLeft(Vector64 x, Vector64 amount) -> Vector64 -static Silk.NET.Maths.Simd64.RotateRight(Vector64 x, Vector64 amount) -> Vector64 -static Silk.NET.Maths.Simd64.CopySign(Vector64 source, Vector64 destination) -> Vector64 - -static readonly Silk.NET.Maths.Simd128.IsFloat -> bool -static readonly Silk.NET.Maths.Simd128.IsInteger -> bool -static readonly Silk.NET.Maths.Simd128.IsUnsignedInteger -> bool -static readonly Silk.NET.Maths.Simd128.IsSignedInteger -> bool - -static readonly Silk.NET.Maths.Simd256.IsFloat -> bool -static readonly Silk.NET.Maths.Simd256.IsInteger -> bool -static readonly Silk.NET.Maths.Simd256.IsUnsignedInteger -> bool -static readonly Silk.NET.Maths.Simd256.IsSignedInteger -> bool - -static readonly Silk.NET.Maths.Simd64.IsFloat -> bool -static readonly Silk.NET.Maths.Simd64.IsInteger -> bool -static readonly Silk.NET.Maths.Simd64.IsUnsignedInteger -> bool -static readonly Silk.NET.Maths.Simd64.IsSignedInteger -> bool -``` - -**Also apply that to Scalar.** - -# Behavioural changes - -### IEEE754 standard - -I propose we do *not* guarantee following it for the sake of performance. For example, artificially normalized values are preferred over the expected abnormal. - -### Reciprocal of an integer - -**OPEN QUESTION:** what should be a reciprocal of an integer? Just 0? What is its behaviour for integer 0? - -### IsHardwareAccelerated - -Currently, in the `feature/math-simd` branch it does not depend on the type. I suggest making it dependent on the type (e. g. by doing `&& IsSupported`). - -It also does not depend on the method, which may lead to worse performance than just scalar operations (for methods which use other simd methods *which* in turn use scalar operations). **OPEN QUESTION:** how can we check that a method is hw-accelerated? - -### How else can we guarantee the fastest code? - -**OPEN QUESTION:** How can we let the user know if a `method` x `type` x `bitness` x `target machine` indeed makes a use of HW-acceleration? Or is the fallback with loop over vector good enough? - -## Meeting Notes - -Proposal needs work (open questions addressed). Discussed in Working Group meeting 29/11/2021, 19:13 UTC. - -**Note:** it has been assumed that all SIMD proposal elements are also being applied to Scalar. - -- IEEE754 - - All methods and code thus far just follows whatever makes it fast, no compliance to any standard or other behaviour (c# builtin, hardware, etc) is guaranteed - - Pretty good to be that way, as we can be the fastest and 100% accuracy most people don't care about - - There's a difference between doing things for correctness and doing it for performance. - - example optimization which could be problematic: treating NaN as 0, assuming it'll never happen (case in point: GCC fastmath) - - Don't throw exceptions in performant, use NaN instead to represent exceptional circumstances? What about ints? - - The only time you can accelerate if a value is a constant (JIT-level knowledge...) - - Separate methods for opt-in correctness-sacrificial optimizations? - - "I'm aware of the implications, and am ready for them" - - Most sense, least surprise (0 / 0 = 0) - - Something like a "IsMaximum" API to represent the "maximum representable value for a T" and use that in operations - - .NET's default behaviour is changing to match Rust, WASM etc - platform-specifics (i.e. faster paths) - - "do whatever the operator will do" - - Just throw exceptions where they're not trivially avoidable. - - We want all of the APIs to be as close as they can to hardware-accelerated. - - are we sure? should they be explicitly labelled? - - If we're using an inaccurate algorithm, should it be explicitly labelled? - - Figure out ULP, and document if we're making this decision? The user could check the docs, find the ULP, and then either use the library or don't use the library according to that. - - It's not trivial to find edge cases, could catch people out without realising? - - Let's just add estimate APIs - - For estimate APIs should they throw exceptions? - -- Reciprocal of int - - see consensus - -- IsHardwareAccelerated - - Make IsHardwareAccelerated per-type - - Perhaps we could make a smarter way of doing IsHardwareAccelerated, but the working group thinks it's not necessary (and also has no ideas) - - "Some or most of the APIs for this type are hardware accelerated" - - Methods that aren't are slow-path - - Static class with a whole bunch of static APIs for indicating? - - Where do we draw the line? - - Lots of checks can hurt the JIT/inliner - - Usually we optimize "all or nothing" for a given type. There may be a few exceptions, but these would be few and far between. - - Per-method and per-type is just pernickety and the working group sees no use case for this today/doesn't really matter... - - -**Consensus** -- IEEE754: We'll have estimate APIs and "native"/"more precise" APIs, two versions of all except things built in to the hardware (at a given baseline) -- Reciprocal: do what C# does for non-estimate (and for estimate as well we guess) -- IsHardwareAccelerated: one boolean per type. Not worth making a new flag for the few cases where we have a couple of functions which are slow for a given type. diff --git a/docs/proposals/Proposal - 3.0 & 3.X Software Development Plan.md b/docs/proposals/Proposal - 3.0 & 3.X Software Development Plan.md deleted file mode 100644 index d2bd7d7cfd..0000000000 --- a/docs/proposals/Proposal - 3.0 & 3.X Software Development Plan.md +++ /dev/null @@ -1,201 +0,0 @@ -# Summary - -3.0 software development plan & ongoing monthly update, breaking change, and support policy for 3.X. - -# Contributors -- Dylan P (@Perksey) - -# Current Status -- [x] Proposed -- [x] Discussed with Working Group -- [x] Approved -- [ ] Implemented - -# Silk.NET 3.0 - -## Goals of 3.0 - -The key tenets of 3.0 are **portability**, **maintainability**, **usability**, and **performance**. To this end, the following objectives have been identified: -- Use .NET 6 - the first version of modern .NET to run on the majority of our desired target platforms - - (tenet: portability) -- Allow Silk.NET's rich abstractions to be integrated into other frameworks rather than being completely standalone. - - WPF, WinForms, MAUI, Avalonia (tenet: usability) -- Rewrite windowing to be more portable and facilitate true write-once-run-everywhere. - - For more information, see [the Windowing 3.0 proposal](Proposal%20-%20Windowing%203.0.md). (tenet: portability) -- Remove the bulk of our bindings generation code in favour of more mature alternatives - - For more information, see [the SilkTouch 3.0 proposal](Proposal%20-%20Generation%20of%20Library%20Sources%20and%20PInvoke%20Mechanisms.md). (tenet: maintainability) -- Accelerate our maths library using SIMD hardware intrinsics - - For more information, see [the Vectorization SIMD proposal](Proposal%20-%20Vectorization%20-%20SIMD.md). (tenet: performance) -- Redesign our input library to work in multiple scenarios and environments, as well as be less prone to breaking changes. - - For more information, see [the Multi-Backend Input proposal](Proposal%20-%20Multi-Backend%20Input.md). (tenet: usability) - -Silk.NET 3.0 presents us with an opportunity to rethink the entire library taking into account everything we've learnt over the past 2 years of the project's development. - -## Development Roadmap - -Note that this development roadmap does not take into account unit tests, only functional tests such as experiments. The team should of course strive to add as many tests as possible where possible. - -### 3.0 Preview 1 - -Before we can do anything, we need to get our brand new generators up and running. In this version: -- The Scraper works as a minimum viable product. It has minimal support for adding extra attributes for invoking overloaders. - - The Khronos APIs in particular will likely be incomplete compared to 2.X in this version. -- The Emitter works completely as intended. -- The Overloader works as a minimum viable product. It doesn't necessarily implement all overloads specified yet. -- Windowing and Input are implemented for desktop platforms, and have received initial testing. -- No development on Maths for this preview. -- Exclusive support for .NET 6 - -3.0 Preview 1 is not a production-ready preview and is very experimental. - -### 3.0 Preview 2 - -Now that we've got an initial preview out to show what our aims are, we can start refining everything. In this version: -- Bugfixes from 3.0 Preview 1 -- The Scraper has near-complete support for adding extra attributes for invoking overloaders. -- The Overloader has more overloads implemented. All generic overloads should be implemented by now, but some API-specific overloads may not be implemented. -- Android support has been restored for Windowing and Input, and have received initial testing on this platform. -- No development on Maths for this preview. - -3.0 Preview 2 is not a production-ready preview and is very experimental. - -### 3.0 Preview 3 - -By this preview, the groundwork has been established for 3.0 and we should ensure that all of our goals have ample progress towards the end product. In this version: -- Bugfixes from 3.0 Preview 2 -- The Scraper is complete. -- The Overloader is complete. -- iOS support has been added for Windowing and Input, and have received initial testing on this platform. -- If time permits, a start has been made on the SIMD APIs in Maths. No work has been done on integrating it into the other Maths types. - -3.0 Preview 3 is not a production-ready preview and is very experimental. - -### 3.0 Preview 4 - -This is the first "production-ready" preview and we want users to start integrating into their workloads, so we need to make sure good progress has been made to all goals for the 3.0 update and as many forseeable breaking changes as possible done. In this version: -- Bugfixes from 3.0 Preview 3 -- Windowing integrations for WPF and WinForms have been developed and have at least basic OpenGL support. The support may not be the most high performance possible at this time. -- SIMD APIs in Maths have been complete, and work has started to integrate them into the other Maths types in the most common cases. -- Ample work has been done to migrate 2.0 code to 3.0 code to evaluate differences in public API, fixing them where we deem necessary. - -3.0 Preview 4 is a production-ready preview and users are encouraged to start integrating this preview into their code. - -### 3.0 Preview 5 - -This is the last preview and is primarily a bugfix release. All breaking changes should've been done in previous previews, but if this is not the case all forseeable breaking must be 100% done in this preview. In this version: -- Bugfixes from 3.0 Preview 4 -- A windowing integration for MAUI has been developed and has at least basic OpenGL(ES) support in a state that is as high-performance and as smoothed-out as possible. -- If time permits, a windowing integration for Avalonia has been developed and has at least basic OpenGL(ES) support. If there is not enough time, this can be pushed to 3.X. -- SIMD APIs should be integrated into Maths in as many common cases as possible. Ongoing performance improvements may be done in 3.X. - -## Problems identified in past development - -- We have severely lacking documentation - - The intention is that all developers of large amounts of code write implementation documentation and/or "orientation guides" for their codebases informing readers of all major things there is to know in their code. - - We should also write documentation containing examples on using as many features of the surface APIs as possible \[for high level utilities\] - - We will enforce XML documentation in all manually-written utilities and as much as possible in bindings. - - If time permits, we should productionize our website powered by Statiq + our custom API reference generator. -- There's not a lot of planning - - We have solved this in the form of the proposal you are reading and all linked proposals: getting all the design done now and documented now, to prevent design debates later down the line. This should reduce friction when actually working on the library. - - We have been keeping the working group and key stakeholders in the loop with the 3.0 kickoff (again, see this proposal you are reading) - - The team are trying to communicate with eachother and figure out how to distribute work among themselves depending on individual circumstances and free time - - Codeowners have been established -- Barrier to entry for external contributors is very high - - Documentation should help with this. - - We should at least consider introducing something like stylecop to ensure code is readable and easy to navigate. - - We should look to make a general repo "orientation guide" teaching prospective contributors where they can find to expect what codebases. - - Hopefully we can pick up some external contributors along the way so _they_ can tell _us_ how to improve? -- Our level of correctness is inconsistent - - We should use .NET 5 enhanced warnings to help combat this. - - Our adoption of C# 8 nullability should be at a much greater extent than it is today, and not using nullability should require great justification. - -## Documentation Regime - -Documentation on how to use the surface API we expose for our High Level Utilities should be plentiful, and include examples for all of the common usecases of our libraries, if not more. The `documentation` folder will be structured as follows: - -``` -documentation - assets - branding - deprecation-notices - for-contributors - generators - input - maths - proposals - 1.0 - 1.x - 2.0 - 2.x - 3.0 - 3.x - rejected - windowing - generators - input - maths - windowing -``` - -The `documentation/for-contributors` folder will be used to document the implementation specifics, such as structure and implementation design philosophy, to help prospective contributors understand the library internals. - -The `documentation/assets` folder just contains images and other assets for the front page README.md. This folder was renamed from `documentation/readme`. - -The `documentation/branding` folder is a new folder containing all branding images for Silk.NET. - -The `documentation/deprecation-notices` is as it is today. - -The `documentation/for-contributors/proposals` folder, once the 3.0 proposals have been reviewed and signed-off by the Working Group, is as the `documentation/proposals` folder is today but slightly refactored to better organise the proposals and make it more clear which proposals concern which versions. - -All other folders will contain documentation targeted at users for using specific areas of the library. This can include surface API explanations, minimal code examples, and more: basically anything to make the usage of our library clearer to our users. - -# Silk.NET 3.X - -## Monthly Updates - -Silk.NET has been proven to excel at binding to OpenGL with games and applications such as [Project Hedra](https://projecthedra.com), a game made by @maxilevi; and [a clone of The Settlers](https://github.com/Pyrdacor/Freeserf.Net) made by @Pyrdacor. - -One thing we want to place an emphasis on is our commitment to actually keeping Silk.NET up-to-date. The schedule will be that on the **first Friday of the month** the bindings will be regenerated and a patch released containing all the changes since the last patch. - -We have a lot of bindings by now and the libraries we bind to change all the time. As such, monthly updates are critical to ensure our bindings are regenerated and are as up-to-date as possible. Bugfixes found over the month will be swept up in these monthly updates. - -### Emergency Patches - -If a bug is determined (agreed upon by the majority of maintainers) to be causing massive disruption to the point where the library is borderline unusable in some or all use cases of the library with a considerable proportion of the userbase affected, an out-of-cycle "emergency patch" may be issued on any other Friday between updates. - -### Versioning - -Any post-3.0, pre-4.0 release will be versioned as follows: -- The major version will always be 3 -- The minor version will be the number of the monthly update cycle i.e. the first monthly update will be versioned 3.1, the second 3.2, etc... -- The patch version will always be 0, unless it is an emergency patch in which case it'll be the number of the emergency patch i.e. if an emergency patch is required after the first monthly update the version will be 3.1.1, if another one is required (heaven forbid) in this same cycle it'll be 3.1.2 etc... -- The revision version will always be 0. - -Users are expected to keep all of the versions of all Silk.NET packages they are using in-sync. We could write a Roslyn analyser or MSBuild target to help push users to this. - -### Breaking Changes - -If an API is determined (agreed upon by the majority of maintainers) to be causing massive disruption or widespread confusion among a considerable proportion of the userbase, the Silk.NET team may reserve the right to make a breaking change in a post-3.0, pre-4.0 update as part of a monthly update cycle. This class of breaking changes shouldn't be done in an emergency patch unless the API issue in question was introduced in the then-current monthly update cycle (e.g. we need to quickly remove an API because it's super problematic for lots of people) - -Breaking changes in generated sources caused by changes in a third-party/external source the generated sources are generated from are allowed. - -ABI breaks may be allowed, but should be deferred unless absolutely necessary, so long as they are not source breaking - benign given all versions are in-sync, the only scenarios which could be affect is reflection. - -Additive changes which introduce a break are forbidden in a post-3.0, pre-4.0 update. - -### Support - -There are currently no plans to officially support anything but the latest monthly update i.e. the end-of-life date of a particular update is as soon as the next monthly update is released. Users are expected to be aware or made aware of the monthly update schedule and plan their work and/or support needs accordingly. - -Individual developers on the team may diverge from this, but they will be responsible for any support they give outside of this notice. If this changes and the Silk.NET team opt to introduce another support option, this proposal (or a future proposal which supersedes this one) will be updated accordingly and discussed with the Working Group. - -# Meeting Notes - -## 25/02/2022 - -[Video](https://youtu.be/dac3t0oh3VU?t=529) - -- Approved. -- Support Eto.Forms? - - Not really used or requested compared to the others, maybe as a community thing. -- There were some questions about the bindings libraries and how the generator differences are going to be consolidated. \ No newline at end of file diff --git a/docs/proposals/Proposal - Bitwise - Scalar.md b/docs/proposals/Proposal - Bitwise - Scalar.md deleted file mode 100644 index 5e0b073534..0000000000 --- a/docs/proposals/Proposal - Bitwise - Scalar.md +++ /dev/null @@ -1,31 +0,0 @@ -# Summary -Bitwise operations in `Scalar[]` - -# Contributors -- Kai Jellinghaus, Silk.NET maintainer -- Dylan Perks, Ultz Limited - -# Current Status -- [x] Proposed -- [x] Discussed with API Review Board (ARB) -- [x] Approved -- [x] [Implemented](https://github.com/dotnet/Silk.NET/pull/667) - -# Design Decisions - - -# Proposed API -To make this simpler for both me, and anyone who reads this, I've provided the API in the form it would appear in a PublicAPI.txt - -This same API would also be amended to the Vectorization/SIMD proposal, if both are accepted. - -```cs -static Silk.NET.Maths.Scalar.And(T left, T right) -> T -static Silk.NET.Maths.Scalar.Or(T left, T right) -> T -static Silk.NET.Maths.Scalar.Xor(T left, T right) -> T -static Silk.NET.Maths.Scalar.Not(T x) -> T -static Silk.NET.Maths.Scalar.ShiftLeft(T x, int amount) -> T -static Silk.NET.Maths.Scalar.ShiftRight(T x, int amount) -> T -static Silk.NET.Maths.Scalar.RotateLeft(T x, int amount) -> T -static Silk.NET.Maths.Scalar.RotateRight(T x, int amount) -> T -``` diff --git a/docs/proposals/Proposal - Chain Polymorphism.md b/docs/proposals/Proposal - Chain Polymorphism.md deleted file mode 100644 index 276e72696c..0000000000 --- a/docs/proposals/Proposal - Chain Polymorphism.md +++ /dev/null @@ -1,106 +0,0 @@ -# Summary - -Using the managed `Silk.NET.Vulkan.Chain` and its generically-typed descendants can be unwieldy in the specific case of recieving chains -with known starting element(s) but potential unknown later elements, e.g. a `SwapchainCreateInfoKHR` which may or may not have an -`ImageCreateInfo` later in the chain. If use of the managed chain api is desired in this case, the untyped `Chain` type must be used -and the result of its indexer cast to the desired chain start type. This, combined with the public api surface on ``Chain`2`` being -a strict superset of ``Chain`1`` etc., a polymorphic interface is desired for handling variable-size chains. - -# Contributors - -- [Khitiara](https://github.com/Khitiara) - -# Current Status - -- [x] Proposed -- [x] Discussed with API Review Board (ARB) -- [x] Approved -- [ ] Implemented - -# Design Decisions - -- This is mainly useful in cases where the managed api and its automatic management of chain memory is desired. The unmanaged non-generic API - already supports this use-case, so this function is mainly beneficial as method return types where chain extensions may not be known ahead of - time, and thus `out` parameters for all unmanaged chain elements are not suitable. - -# Proposed API - -A series of generic interfaces are created to accompany the generic `Chain<...>` classes: - -```csharp -public unsafe interface IChain : IDisposable - where TChain : unmanaged, IChainable { - public BaseInStructure* HeadPtr { get; } - public TChain Head { get; set; } -} - -public unsafe interface IChain : IChain - where TChain : unmanaged, IChainable - where T1 : unmanaged, IChainable { - public BaseInStructure* Item1Ptr { get; } - public T1 Item1 { get; set; } -} - -public unsafe interface IChain : IChain - where TChain : unmanaged, IChainable - where T1 : unmanaged, IChainable - where T2 : unmanaged, IChainable { - public BaseInStructure* Item2Ptr { get; } - public T2 Item2 { get; set; } -} - -... -``` - -and the existing generic `Chain<...>` types are modified to implement these new interfaces: - -```csharp -public unsafe sealed class Chain : Chain, IEquatable>, IChain - where TChain : unmanaged, IChainable { - ... -} - -public unsafe sealed class Chain : Chain, IEquatable>, IChain - where TChain : unmanaged, IChainable - where T1 : unmanaged, IChainable { - ... -} - -public unsafe sealed class Chain : Chain, IEquatable>, IChain - where TChain : unmanaged, IChainable - where T1 : unmanaged, IChainable - where T2 : unmanaged, IChainable { - ... -} - -... -``` - -Usage: - -```csharp -public IChain DeduceImageCreateInfo(IChain swapchainCreateInfo) { - ImageCreateInfo createInfo = ...; - - // condition here used for example - a TryFind extension or similar may be desirable in the long term - if (swapchainCreateInfo is Chain(_, formatListCreateInfo)) { - // Chain : IChain : IChain - return Chain.Create(createInfo, formatListCreateInfo); - } - - // Chain : IChain - return Chain.Create(createInfo); -} - -... - -public void Foo() { - SwapchainCreateInfoKHR sci = ...; - using IChain ici = DeduceImageCreateInfo(sci); - ReadOnlySpan fmts = ici switch { - Chain(_, var formatList) => - new ReadOnlySpan(formatList.PViewFormats, (int)formatList.ViewFormatCount).ToArray(), - Chain(var i) => stackalloc[] { i.Format } - } -} -``` diff --git a/docs/proposals/Proposal - Contexts.md b/docs/proposals/Proposal - Contexts.md deleted file mode 100644 index f567ae325e..0000000000 --- a/docs/proposals/Proposal - Contexts.md +++ /dev/null @@ -1,55 +0,0 @@ -# Summary -Currently, in Silk.NET you must have an `IWindow` or `IView` in order to use `Silk.NET.OpenGL` -and if you want to evade our windowing system, a lot of dirty hacks are required in order to -get access to `GL`. - -This proposal, along with others that are along the way, are part of an effort to remove -`SilkManager` in 2.0, which is a really poorly implemented injection system which didn't -really make sense anyway, as API instances would depend on a static state. - -- Written against Silk.NET 1.1 -- Slated for Silk.NET 1.X - -# Contributors -- Dylan P, Ultz Limited - -# Current Status -- [x] Proposed -- [ ] Discussed with API Review Board (ARB) -- [ ] Approved -- [ ] Implemented - -# Points to discuss -- In 2.0 we could completely remove the GL constructors that use SilkManager (after obsoleting them in the next update), so that each GL instance is tied to an OpenGL context. - -# Proposed API -```cs -// Silk.NET.Core -public interface IGLContext : IDisposable -{ - IntPtr Handle { get; } - bool IsCurrent { get; } - void SwapInterval(int interval); - void SwapBuffers(); - void MakeCurrent(); - void Clear(); - IntPtr GetProcAddress(string proc); -} -``` - -```diff -public interface IView -{ - // NOTE: Still need to discuss nullability attributes -+ IGLContext? Context { get; } -} -``` - -```diff -// Silk.NET.OpenGL -public abstract class GL -{ - // This overload evades the SilkManager entirely, getting all the data it needs from the context. -+ public static GL GetApi(IGLContext ctx); -} -``` diff --git a/docs/proposals/Proposal - Generation of Library Sources and PInvoke Mechanisms.md b/docs/proposals/Proposal - Generation of Library Sources and PInvoke Mechanisms.md deleted file mode 100644 index 5393371f67..0000000000 --- a/docs/proposals/Proposal - Generation of Library Sources and PInvoke Mechanisms.md +++ /dev/null @@ -1,342 +0,0 @@ -# Summary -Proposal design for a platform invoke (P/Invoke) mechanism for Silk.NET 3.0. - -# Contributors -- Dylan Perks (@Perksey) -- Kai Jellinghaus (@HurricanKai) - -# Current Status -- [x] Proposed -- [x] Discussed with Working Group (WG) -- [x] Approved -- [ ] Implemented - -# Design Decisions -- This proposal builds on the foundations laid out by Silk.NET's move to source generators in 2.0, and the introduction of the SilkTouch source generator as a result of this. -- This proposal assumes no knowledge of Silk.NET 2.0's SilkTouch. -- This takes the knowledge and insight gained during development of SilkTouch, and uses it to create a new set of generators which incorporate lessons learnt. -- This proposal breaks down the generator process into three distinct stages: - -## SilkTouch Scraper - -The Scraper is responsible for creating partial classes from some input source. It is a drop-in replacement for what BuildTools does today. Instead of doing all the parsing and interpretation of the input source ourselves, the proposed Scraper will instead use only C headers and have a "preburner" for gathering minimal metadata to feed into the generation process. - -The generation process of the proposed Scraper will be entirely different. Silk.NET will no longer do any parsing and interpretation of C headers or XML of C headers, instead we will delegate this to the ClangSharp P/Invoke Generator in the form of a "subagent" (a separate process spun up by the Scraper), adding appropriate modifications to ClangSharp P/Invoke Generator as necessary. This means that we will no longer be using the Khronos XML registries for generating bindings. Instead, we'll use the preburner stage to use the XML registry only to gather minimal metadata instructing the ClangSharp subagent to add metadata attributes to certain functions, parameters, or types; which will then be picked up on by the later stages of SilkTouch. An example of such metadata would be parsing the flow and len XML attributes to add appropriate C# attributes to influence overload generation. - -This also naturally makes us entirely dependent on an external dependency, but I propose we work with Microsoft as much as possible to add the functionality we need in the least breaking way possible, and in a way that satisfies both us and Microsoft. All designs for such modifications will be formalized in the ClangSharp repo. Should we fail to do this, we'll maintain a fork so we can still benefit from improvements made upstream, while giving ourselves the freedom to add the functionality we need. - -Microsoft have already stated that they're happy to work with us to get Silk.NET using ClangSharp, one maintainer even saying they're happy to add a CI test stage into the ClangSharp repo to ensure no incoming changes break Silk.NET's generation process. - -There is no required behaviour for the Scraper (due to a lot of unknowns at the moment) other than it **MUST** invoke ClangSharp to generate C# Emitter-compatible classes, and it **MUST** add appropriate attributes to invoke the Overloader stage according to any metadata available from Khronos XML if applicable. - -## SilkTouch Emitter -The Emitter, one of the two final stages whose resources **MUST** be entirely independent of eachother, is responsible for generating the actual indirect calls for performing the P/Invoke. - -The Emitter operates on partial methods, the behaviour of the implementations of which depending on the context in which it's used. - -All attributes **MUST** be name matched only, to allow the user to define these themselves and not create a hard dependency on a specific Silk.NET library such as the Silk.NET Core. - -Candidate methods for implementation by the Emitter **MUST** be partial and not have an implementation part yet. Their containing types **MUST** also be partial. - -The Emitter **MUST** be able to be invoked via the SilkTouch CLI and **MAY** be able to be invoked via an incremental Roslyn source generator. - -### Call Styles - -The Emitter's primary purpose is to load and use function pointers in a native library sourced from an operating system's kernel, though this doesn't necessarily have to be the case. This logic will be emitted by the Emitter itself, and will not require an external dependency like the Silk.NET Core. However, this logic will no longer be implicit. - -#### Built-in: Dynamic-Link Library Call Style - -Consider the following example: -```cs -[UseDynamicLibrary("glfw3.dll")] -public partial class Glfw -{ - public partial void glfwInit(); -} -``` - -The `UseDynamicLibrary` attribute instructs the Emitter that it **MUST** use [`DllImport`](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportattribute?view=net-5.0) to access native functions. [`NativeLibrary`](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativelibrary?view=net-5.0) can be used to modify the libsuperrary loading process per other requirements defined below. For the entry point, the function name **MUST** be used unless a `NativeApi` attribute is provided, in which case the `EntryPoint` indicated by that attribute **MUST** be used. - -Consider the following example: -```cs -[UseDynamicLibrary("glfw3.dll", "libglfw3.dylib")] -public partial class Glfw { /* ... */ } -``` - -`UseDynamicLibrary` **MUST** be able to be specified on either a function or type. - -The Emitter **MUST** allow multiple candidate library names and cycle through each candidate until one loads successfully. - -#### Built-in: Static-Link Library Call Style - -Consider the following example: -```cs -[UseStaticLibrary] -public partial class Glfw -{ - public partial void glfwInit(); -} -``` - -The `UseStaticLibrary` attribute instructs the Emitter that it **MUST** use [`DllImport`](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportattribute?view=net-5.0) to access native functions. `__Internal` **MUST** be used for the library name. For the entry point, the function name **MUST** be used unless a `NativeApi` attribute is provided, in which case the `EntryPoint` indicated by that attribute **MUST** be used. - -`UseStaticLibrary` **MUST** be able to be specified on either a function or type. - -Consider the following example: -```cs -#if __IOS__ -[UseStaticLibrary] -#endif -[UseDynamicLibrary("glfw3.dll")] -public partial class Glfw -{ - public partial void glfwInit(); -} -``` - -The Emitter **MUST** only generate code if all preprocessor directives guarding the `UseStaticLibrary` attribute evaluate to true. If the attribute is defined on both the function and the containing type, the preprocessor directives surrounding the function's attribute **MUST** be used instead of the preprocessor directives surrounding the type. - -Note to the reader: Given preprocessor directives are processed at parse time in Roslyn, both of those last requirements are basically benign. - -#### Custom Call Style: Procedure Address Expressions - -Custom code may be used as a call style by providing a pointer to SilkTouch using a Procedure Address Expression. This is useful in scenarios such as COM interop. - -Procedure Address Expressions are C# expressions that **MUST** evaluate to a `void*`, `nint`, or `IntPtr`. This is the actual address in memory of the function being invoked. - -Consider the following example: -```cs -public partial struct IUnknown -{ - public void** LpVtbl; - [UseExpression("LpVtbl[1]")] - public partial uint AddRef(); -} -``` - -`GetProcAddress` indicates that the C# code given **MUST** be used as the Procedure Address Expression to retrieve the function address to call. Any arbritrary code can be inserted into this attribute, so long as the result of the code once evaluated meets the Procedure Address Expression definition. For example, this is valid: -```cs -public partial struct IUnknownNullableContainer -{ - public IUnknownPtr? Value; - [UseExpression("Value.GetValueOrDefault().InnerValue->LpVtbl[1]")] - public partial uint AddRef(); -} - -public struct IUnknownPtr -{ - public IUnknown* InnerValue; -} - -public struct IUnknown -{ - public void** LpVtbl; -} -``` - -The Emitter **SHOULD** implicitly parenthesise the expression given in the attribute. - -Unless another call style is applicable, the Emitter **MUST** mandate that every function has a `UseExpression` (Procedure Address Expression) specified. - -The Emitter **MUST** call the function pointer returned by the Procedure Address Expression as part of this call style. - -#### Custom Call Style: Procedure Address Methods - -A level more abstracted than Procedure Address Expressions, which allows any custom code to retrieve a function pointer; Procedure Address Methods work similarly to the native library call style from an API perspective, but function similarly to the Procedure Address Expressions call style. - -The aim of this call style is to provide flexibility without comprimising code readability. Consider the following example: - -```cs -[UseMethod(nameof(GetProcAddressShim))] -public partial class Glfw -{ - [UseDynamicLibrary("glfw3.dll")] - public partial nint glfwGetProcAddress(byte* str); - - // shim to convert the string, which SilkTouch needs to use, to a byte pointer - THIS IS NOT A MODEL EXAMPLE! - private nint GetProcAddressShim(string str) => glfwGetProcAddress((byte*) Marshal.StringToHGlobalAnsi(str)); - - public partial void glBegin(uint mode); -} -``` - -Procedure Address Methods are method groups (or an otherwise callable expression) within the scope of the method that **MUST** return a `void*`, `nint`, or `IntPtr` when invoked. This is the actual address in memory of the function being invoked. - -Procedure Address Methods **MUST** take one parameter of type `string`. - -For the parameter passed into the callable specified in the attribute, the function name **MUST** be used unless the `EntryPoint` property in the `NativeApi` attribute is provided, in which case the `EntryPoint` indicated by the attribute **MUST** be used. - -The Emitter **MUST** call the function pointer returned by the Procedure Address Method as part of this call style. - -#### Call Style Priority - -Consider the following example: - -```cs -[UseDynamicLibrary("glfw3.dll")] -public partial class Glfw -{ - public partial nint glfwGetProcAddress(byte* str); - [UseExpression("glfwGetProcAddress((byte*)Unsafe.AsPointer(ref Unsafe.AsRef(0x006e696765426c67)))")] - public partial void glBegin(uint mode); -} -``` - -Here, a class using the Dynamic Library call style has a method which does not follow the call style defined at the class level, and is overridden using a `UseExpression` attribute. - -If multiple call styles are applicable, the following order of preference **MUST** be respected: -- Procedure Address Expressions -- Procedure Address Methods -- Static-Link Library -- Dynamic-Link Library - -Function-level attributes **MUST** be preferred over type-level ones, and follow the same order of preference. - -### Native Calls -For the most part, the resultant native signature used by the Emitter is matched 1:1 with the method signature. However there are certain modifications you can apply. Namely, the `NativeApi` attribute will allow specification of specific calling conventions. For example: - -```cs -[NativeApi(Conventions = new[]{typeof(CallConvMemberFunction), typeof(CallConvSuppressGCTransition)}] -public partial D3D12_HEAP_PROPERTIES GetCustomHeapProperties(uint nodeMask, D3D12_HEAP_TYPE heapType); -``` - - -`Conventions` will be used as the primary mechanism for customizing the behaviour of generation, just as `NativeApi` will be used as the primary attribute for this as well. The behaviour of each bit will be described in documentation comments in the Proposed API section. - -The Emitter does not do any marshalling. As such, the Emitter **MUST** mandate that every parameter and return type of every function fits the `unmanaged` constraint. For the readers benefit, this can be done using a property on `ITypeSymbol` in Roslyn. - -## SilkTouch Overloader -The Overloader, one of the two final stages whose resources **MUST** be entirely independent of eachother, creates overloads of functions that expose a more user-friendly interface than the function it overloads, and do appropriate marshalling to lower the parameter types used down to the original function's types. - -The Overloader **MUST** be able to be used on any function and not be tied to any of the Emitter's constraints. - -The Overloader **MUST** be able to be invoked via the SilkTouch CLI and **MAY** be able to be invoked via an incremental Roslyn source generator. - -The Overloader does not care about existing methods. If the Overloader generates an overload that also happens to exist manually, it is the user's repsonsibility to disable the relevant overloads for these cases. - -However, if the Overloader thinks that the overload it's generating may conflict with another overload or the original function, it **SHOULD** output the overload as an extension method rather than a method within the containing type, unless the original method is static in which case it **MUST** discard the overload and generate a warning. It **SHOULD** also do this if the containing type is not partial. - -The Silk.NET team does not wish to specify the functionality of the overloader at this time, and wishes to instead define this by experimenting with the overloader's functionality during development; with the understanding that the Silk.NET team must formalize a proposal with the working group before a "go live" release ships. - -# Proposed API -- Here you do some code blocks, this is the heart and soul of the proposal. DON'T DO ANY IMPLEMENTATIONS! Just declarations. - -## `UseDynamicLibrary` -```cs -namespace Silk.NET.Core -{ - [AttributeUsage(AttributeTargets.Function | AttributeTargets.Class)] - public class UseDynamicLibraryAttribute : Attribute - { - public UseDynamicLibrary(string libraryName, params string[] alternativeNames); - public string LibraryName { get; } - public string[] AlternativeNames { get; } - } -} -``` - -## `UseStaticLibrary` -```cs -namespace Silk.NET.Core -{ - [AttributeUsage(AttributeTargets.Function | AttributeTargets.Class)] - public class UseStaticLibraryAttribute : Attribute - { - } -} -``` - -## `UseExpression` -```cs -namespace Silk.NET.Core -{ - [AttributeUsage(AttributeTargets.Function | AttributeTargets.Class)] - public class UseExpressionAttribute : Attribute - { - public UseExpressionAttribute(string expr); - public string Expression { get; } - } -} -``` - -## `UseMethod` -```cs -namespace Silk.NET.Core -{ - [AttributeUsage(AttributeTargets.Function | AttributeTargets.Class)] - public class UseMethodAttribute : Attribute - { - public UseMethodAttribute(string expr); - public string Expression { get; } - } -} -``` - -## `NativeApi` -```cs -namespace Silk.NET.Core -{ - public class NativeApiAttribute : Attribute - { - public string EntryPoint { get; set; } - public Type[] Conventions { get; set; } - } -} -``` - -# Meeting Notes - -## 05/08/2021 - -- SilkTouch for 2.0 is very hard to use -- A lot of code -- Will explode the repo a lot, but will also improve compile times because everything's already there and no need to generate at compile time -- ClangSharp is used by win32metadata (official c#, rust bindings) and generally accurate for parsing header files - - very correct, battle tested, more reliable than BuildTools 2.0 -- Just use ReadOnlySpan (implicit conversion from string) - - does our userbase know this? -- Too many overloads could cause confusion/lack of visibility - - promote "best practice" - - include exposed native api -- Only overload what we determine as "best practice", discourage per-parameter overloading - - One permutation per "overload style"? i.e. one function with all spans - - Special "intermediary" types don't really make sense as it loses compile-time safety and has other compiler-level issues -- Establish a baseline of overloads - - Scrap ArrayOverloads - - Scrap RefOverloads -- Group? i.e. only create overloads based on a particular style -- **Overloader needs more review/work, postpone to another meeting** - - number of overloads is a big concern right now - -## 25/02/2022 - -[Video](https://youtu.be/dac3t0oh3VU?t=7616) - -- Approved (call conv modifier discussion notwithstanding), but we must come back to the overloader - it's a bit too early to decide on something solid as there's no perfect rule that we know of to generate them at this time - we can only get this through experimentation! -- Why use an enum and custom attribute rather than reusing UnmanagedCallConv and the typeof(CallConv*) types that C#/.NET have standardized on for moving forward? - - We don't really have control over those types. - - For \[contrived\] example, what if we want a JavaScript calling convention? - - We can't just hack up a "calling convention" the runtime doesn't support, `MemberFunction` for example was just something that _happened_ to work on the Windows ABI - - We could use CallModifiers to, for example, influence codegen to call into IJsInProcessRuntime and call JavaScript code - this isn't necessarily _just_ an ABI-based concept. It could support other scenarios. - - It makes more sense to separate these, as these are sort of associated with DllImport and that side of the calling process, and a "JavaScript" convention concept (as discussed before). - - It's difficult to represent right now, because we have the native API attribute - - **We could/should change this to use the CallConv types instead** - - Direct advantages - - As the runtime versions in the future, it will continue to add CallConv types. These types are the official way moving forward to represent any calling convention information for the rutnime going forward. - - SilkTouch has to go out of this way to map this and understand this anyway, unless we just have the types then we can specify them as-is - SilkTouch doesn't even need to understand these. - - "\[DllImport\] is effectively magic" - @tannergooding - - **Just change Modifiers to a CallConv type array** -- The overload problem does need to be solved in some way. Some functions have absurd amounts of overloads (particularly in assimp) - - We want to scrap a bunch of overloads as well. A lot of this is only generating a bunch of "important" overloads. - - Was there consideration for a source generator approach to opt-in to the friendliest variant that they want? - - Yes, kind of. We don't have a formal proposal as we only just thought of this today. - - We need to bake the most basic overloads into the assembly itself. - - We'd like to have a source generator. - - We want SilkTouch to be productized, and find a way to remap types per their liking and use overloads etc. - - We should experiment with this and report back in a future community meeting. - -**ACTIONS** -- [x] Change `Modifiers` to a CallConv\* `Type` array - -**FUTURE** -- [ ] Report back to the Community our findings in experimenting with overloads diff --git a/docs/proposals/Proposal - Input.md b/docs/proposals/Proposal - Input.md deleted file mode 100644 index 819dd31798..0000000000 --- a/docs/proposals/Proposal - Input.md +++ /dev/null @@ -1,427 +0,0 @@ -# Summary -Proposal API for Input via keyboards, mice, and controllers. - -# Contributors -- Dylan Perks, Ultz Limited -- Aaron Pearson, Ultz Limited -- Vassalware, Silk.NET Contributors -- Void, Silk.NET codeowners - -# Current Status -- [x] Proposed -- [x] Discussed with API Review Board (ARB) -- [x] Approved -- [ ] Implemented - -# Design Decisions -- Vibration has been excluded from this proposal, as we'd like to come up with a complete API for HD Rumble etc. -- I've decided to use interfaces for nearly everything, so that the implementation has more control. -- All modifications of states (i.e. functions) will go within the interface, whereas structs are used for read-only data. -- **IMPLEMENTATION DETAIL/REQUIREMENT:** In implementations, once an IJoystick, IGamepad, or other IInputDevice object has been created, **it must not be destroyed until its IInputContext is disposed**. This is to preserve event bindings. -- ButtonDown/Up and KeyDown/Up events (and similar) all fire once, when the key is first pushed down or up. I intend to champion a few extension packages to support more use cases, but I've kept this API pretty barebones. - -# Proposed API -## Interfaces - -### IJoystick -```cs -public interface IJoystick : IInputDevice -{ - IReadOnlyList Axes { get; } - IReadOnlyList