├── .gitattributes ├── .github └── workflows │ ├── compile.yml │ ├── gen-check.yml │ └── gen-docs.yml ├── .gitignore ├── Doxyfile ├── LICENSE ├── Makefile ├── README.md ├── doc ├── .gitignore └── articles │ ├── Asynchronous Operations.md │ ├── BufferMapping.md │ ├── Errors.md │ ├── Extensions.md │ ├── FloatingPointNumbers.md │ ├── Multithreading.md │ ├── Ownership.md │ ├── SentinelValues.md │ ├── Strings.md │ ├── StructChaining.md │ ├── Surfaces.md │ └── index.md ├── fix └── main.go ├── gen ├── README.md ├── cheader.tmpl ├── gen.go ├── main.go ├── utils.go ├── validator.go └── yml.go ├── go.mod ├── go.sum ├── schema.json ├── tests ├── compile │ ├── .gitignore │ ├── Makefile │ ├── main.c │ ├── main.cpp │ ├── main.inl │ └── windows │ │ └── makefile └── extensions │ ├── extension.yml │ └── webgpu_extension.h ├── webgpu.h └── webgpu.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | gen/** -linguist-detectable 2 | -------------------------------------------------------------------------------- /.github/workflows/compile.yml: -------------------------------------------------------------------------------- 1 | name: compile 2 | on: 3 | pull_request: 4 | jobs: 5 | compile-gcc-clang: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - run: | 10 | cd "${{ github.workspace }}/tests/compile" 11 | make 12 | compile-msvc: 13 | runs-on: windows-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: ilammy/msvc-dev-cmd@v1 17 | - name: Build something requiring CL.EXE 18 | run: | 19 | cd "${{ github.workspace }}/tests/compile/windows" 20 | nmake 21 | -------------------------------------------------------------------------------- /.github/workflows/gen-check.yml: -------------------------------------------------------------------------------- 1 | name: gen-check 2 | on: 3 | pull_request: 4 | jobs: 5 | gen-check: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v3 9 | - uses: actions/setup-go@v4 10 | with: 11 | go-version: '>=1.21.0' 12 | - run: | 13 | cd "${{ github.workspace }}" 14 | make gen-check 15 | -------------------------------------------------------------------------------- /.github/workflows/gen-docs.yml: -------------------------------------------------------------------------------- 1 | name: gen-docs 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | workflow_dispatch: 7 | pull_request: 8 | 9 | # Allow only one concurrent deployment 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | # Generate and build docs 16 | gen-docs: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: actions/setup-go@v4 21 | with: 22 | go-version: '>=1.21.0' 23 | - uses: ssciwr/doxygen-install@v1 24 | with: 25 | version: '1.10.0' 26 | - run: make doc 27 | - uses: actions/upload-pages-artifact@v3 28 | with: 29 | path: doc/generated/html 30 | 31 | # Deployment job 32 | deploy: 33 | if: ${{ success() && github.ref == 'refs/heads/main' }} 34 | needs: gen-docs 35 | 36 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 37 | permissions: 38 | pages: write # to deploy to Pages 39 | id-token: write # to verify the deployment originates from an appropriate source 40 | 41 | environment: 42 | name: github-pages 43 | url: ${{ steps.deployment.outputs.page_url }} 44 | 45 | runs-on: ubuntu-latest 46 | steps: 47 | - name: Deploy to GitHub Pages 48 | id: deployment 49 | uses: actions/deploy-pages@v4 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | -------------------------------------------------------------------------------- /Doxyfile: -------------------------------------------------------------------------------- 1 | # This file was initially generated by Doxyfile 1.10.0 and all entries left 2 | # to their default value have been removed for the sake of clarity. 3 | 4 | #--------------------------------------------------------------------------- 5 | # Project related configuration options 6 | #--------------------------------------------------------------------------- 7 | 8 | PROJECT_NAME = "WebGPU Headers" 9 | 10 | # This is the version of webgpu.h. Currently we don't have release versions. 11 | 12 | PROJECT_NUMBER = 13 | 14 | # This appears at the top of each page and should give viewer a quick idea 15 | # about the purpose of the project. Keep the description short. 16 | 17 | PROJECT_BRIEF = "The WebGPU C API" 18 | 19 | # The Doxygen-generated documentation is written in doc/generated. Make sure 20 | # to keep this in sync with the deployment workflow file 21 | # (.github/workflows/gen-docs.yml). 22 | 23 | OUTPUT_DIRECTORY = doc/generated 24 | 25 | # Since webgpu.h is a C API, we set the OPTIMIZE_OUTPUT_FOR_C tag to YES so 26 | # that Doxygen generates an output that is more tailored for C. 27 | 28 | OPTIMIZE_OUTPUT_FOR_C = YES 29 | 30 | EXTRACT_ALL = YES 31 | EXTRACT_STATIC = YES 32 | WARN_AS_ERROR = FAIL_ON_WARNINGS 33 | WARN_IF_INCOMPLETE_DOC = NO 34 | # Note EXTRACT_ALL bypasses these, but keep them in case we disable it. 35 | WARN_IF_UNDOC_ENUM_VAL = YES 36 | WARN_NO_PARAMDOC = NO 37 | WARN_IF_UNDOCUMENTED = YES 38 | 39 | #--------------------------------------------------------------------------- 40 | # Build related configuration options 41 | #--------------------------------------------------------------------------- 42 | 43 | # The WebGPU C API does not have cases of symbols only differing by case, so 44 | # we can afford to turn this to YES even on non-case sensitive file systems. 45 | # This options helps getting slightly better path names, although it is still 46 | # overall not satisfying so as soon as we have a proper way to generate good 47 | # human-memorable URLs we could turn this back to NO or SYSTEM. 48 | 49 | CASE_SENSE_NAMES = YES 50 | 51 | # No need to show header file, since there is only webgpu.h. When using this 52 | # Doxyfile with implementation-specific extensions (e.g., wgpu.h), it could 53 | # be useful to turn this back to YES. 54 | 55 | SHOW_HEADERFILE = NO 56 | 57 | # Instead of letting Doxygen sort definition alphabetically, we have it rely 58 | # on the order from webgpu.h. Since the latter is auto-generated, we can 59 | # expect the order there to be sound and consistent. 60 | 61 | SORT_MEMBER_DOCS = NO 62 | 63 | # No need to show used files as there is only webgpu.h 64 | 65 | SHOW_USED_FILES = NO 66 | 67 | # And no need for the Files page neither. 68 | 69 | SHOW_FILES = NO 70 | 71 | # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 72 | # by doxygen. The layout file controls the global structure of the generated 73 | # output files in an output format independent way. To create the layout file 74 | # that represents doxygen's defaults, run doxygen with the -l option. You can 75 | # optionally specify a file name after the option, if omitted DoxygenLayout.xml 76 | # will be used as the name of the layout file. See also section "Changing the 77 | # layout of pages" for information. 78 | # 79 | # Note that if you run doxygen from a directory containing a file called 80 | # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE 81 | # tag is left empty. 82 | 83 | LAYOUT_FILE = 84 | 85 | #--------------------------------------------------------------------------- 86 | # Configuration options related to the input files 87 | #--------------------------------------------------------------------------- 88 | 89 | # When adding extra files, separate them with spaces. 90 | 91 | INPUT = webgpu.h doc/articles/ 92 | 93 | #--------------------------------------------------------------------------- 94 | # Configuration options related to source browsing 95 | #--------------------------------------------------------------------------- 96 | 97 | # The header file itself is often a good source of information, so we have 98 | # documented entries be cross-referenced with their source. 99 | 100 | SOURCE_BROWSER = YES 101 | 102 | #--------------------------------------------------------------------------- 103 | # Configuration options related to the alphabetical class index 104 | #--------------------------------------------------------------------------- 105 | 106 | # Make sure the WGPU/wgpu prefix of type/function names are ignored while 107 | # sorting member names in the alphabetical index. 108 | 109 | IGNORE_PREFIX = WGPU,wgpu 110 | 111 | #--------------------------------------------------------------------------- 112 | # Configuration options related to the HTML output 113 | #--------------------------------------------------------------------------- 114 | 115 | # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output 116 | # The default value is: YES. 117 | 118 | GENERATE_HTML = YES 119 | 120 | # Sidebar-based page layout (https://www.doxygen.nl/manual/customize.html) 121 | 122 | DISABLE_INDEX = YES 123 | GENERATE_TREEVIEW = YES 124 | FULL_SIDEBAR = YES 125 | 126 | # Enum values look weird in Doxygen output in general, but a bit less weird 127 | # when only allowing 1 value per line. 128 | 129 | ENUM_VALUES_PER_LINE = 1 130 | 131 | #--------------------------------------------------------------------------- 132 | # Configuration options related to the LaTeX output 133 | #--------------------------------------------------------------------------- 134 | 135 | # We do not need a LaTeX documentation 136 | 137 | GENERATE_LATEX = NO 138 | 139 | #--------------------------------------------------------------------------- 140 | # Configuration options related to the preprocessor 141 | #--------------------------------------------------------------------------- 142 | 143 | # We need to expand macros to prevent the empty defines used as tags like 144 | # WGPU_ENUM_ATTRIBUTE to be treated by Doxygen and mess up with the whole 145 | # documentation. 146 | 147 | MACRO_EXPANSION = YES 148 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, "WebGPU native" developers 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all all-help-message help check-schema fix gen gen-check doc 2 | 3 | # default target if you just type `make` 4 | all: all-help-message fix gen doc 5 | 6 | # help message before starting `make all` 7 | all-help-message: help 8 | @echo 'Running default targets: fix gen doc' 9 | 10 | help: 11 | @echo 'Targets are: all, help, check-schema, fix, gen, gen-check, doc' 12 | 13 | check-schema: schema.json 14 | go run ./gen -schema schema.json -yaml webgpu.yml -header webgpu.h -yaml tests/extensions/extension.yml -header tests/extensions/webgpu_extension.h 15 | 16 | fix: check-schema webgpu.yml tests/extensions/extension.yml 17 | go run ./fix -yaml webgpu.yml 18 | go run ./fix -yaml tests/extensions/extension.yml 19 | 20 | gen: check-schema webgpu.yml tests/extensions/extension.yml 21 | 22 | gen-check: fix gen 23 | @git diff --quiet -- webgpu.h || { \ 24 | echo "error: The re-generated header from yml doesn't match the checked-in header"; \ 25 | git diff -- webgpu.h; \ 26 | exit 1; \ 27 | } 28 | @git diff --quiet -- webgpu.yml || { \ 29 | echo "error: Please re-run 'make fix' to format the yml"; \ 30 | git diff -- webgpu.yml; \ 31 | exit 1; \ 32 | } 33 | @git diff --quiet -- tests/extensions/webgpu_extension.h || { \ 34 | echo "error: The re-generated extensions header from yml doesn't match the checked-in header"; \ 35 | git diff -- tests/extensions/webgpu_extension.h; \ 36 | exit 1; \ 37 | } 38 | @git diff --quiet -- tests/extensions/extension.yml || { \ 39 | echo "error: Please re-run 'make fix' to format the extension yml"; \ 40 | git diff -- tests/extensions/extension.yml; \ 41 | exit 1; \ 42 | } 43 | 44 | doc: webgpu.h Doxyfile 45 | doxygen Doxyfile 46 | # Verify that no ` or :: made it through into the final docs 47 | ! grep -RE '`|>::' doc/generated/**/*.html 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebGPU Headers 2 | 3 | This repository contains C headers equivalent to the [WebGPU](https://gpuweb.github.io/gpuweb/) API and documentation on the native specificities of the headers. 4 | 5 | **This header is NOT STABLE yet, and the documentation is very much a work in progress!** 6 | 7 | All of the API is defined in the [webgpu.h](./webgpu.h) header file. 8 | **[Read the documentation here!](https://webgpu-native.github.io/webgpu-headers/)** 9 | 10 | ## Why? 11 | 12 | While WebGPU is a JavaScript API made for the Web, it is a good tradeoff of ergonomic, efficient and portable graphics API. 13 | Almost all of its concepts are not specific to the Web platform and the headers replicate them exactly, while adding capabilities to interact with native concepts (like windows). 14 | 15 | Implementations of this header include: 16 | 17 | - [Dawn](https://dawn.googlesource.com/dawn), the C++ WebGPU implementation used in Chromium 18 | - [wgpu-native](https://github.com/gfx-rs/wgpu-native), C bindings to [wgpu](https://github.com/gfx-rs/wgpu), the Rust WebGPU implementation used in Firefox 19 | - [Emscripten](https://github.com/emscripten-core/emscripten/blob/main/src/library_webgpu.js) translates [webgpu.h](./webgpu.h) calls to JavaScript WebGPU calls when compiling to WASM 20 | 21 | ## Details 22 | 23 | Here are some details about the structure of this repository. 24 | 25 | ### Main files 26 | 27 | - `webgpu.h` is the one and only header file that defines the WebGPU C API. Only this needs to be integrated in a C project that links against a WebGPU implementation. 28 | 29 | - `webgpu.yml` is the main machine-readable source of truth for the C API and its documentation (in [YAML](https://yaml.org/) format). It is used to generate the official `webgpu.h` header present in this repository, (will be used) to generate the official documentation, and may be used by any other third party to design tools and wrappers around WebGPU-Native. 30 | 31 | - `schema.json` is the [JSON schema](https://json-schema.org/) that formally specifies the structure of `webgpu.yml`. 32 | 33 | ### Generator 34 | 35 | - `Makefile` defines the rules to automatically generate `webgpu.h` from `webgpu.yml` and check the result. 36 | 37 | - `gen/` and the `go.*` files are the source code of the generator called by the `Makefile`. 38 | 39 | - `tests/compile` is used to check that the generated C header is indeed valid C/C++ code. 40 | 41 | ### Workflows 42 | 43 | - `.github/workflows` defines the automated processes that run upon new commits/PR, to check that changes in `webgpu.yml` and `webgpu.h` are consistent. 44 | 45 | ## Contributing 46 | 47 | **Important** When submitting a change, one must modify both the `webgpu.yml` and `webgpu.h` files in a consistent way. One should first edit `webgpu.yml` (the source of truth), then run `make gen` to update `webgpu.h` and finally commit both changes together. 48 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | /generated/ 2 | -------------------------------------------------------------------------------- /doc/articles/Asynchronous Operations.md: -------------------------------------------------------------------------------- 1 | # Asynchronous Operations {#Asynchronous-Operations} 2 | 3 | Asynchronous operations in webgpu.h return a @ref WGPUFuture. This is an opaque handle which applications may use to poll or wait for completion of the asynchronous operation. 4 | 5 | On all implementations of webgpu.h, it must be possible to react to async operations without undue latency or spin-waiting. 6 | 7 | ## Creation 8 | 9 | All asynchronous operations start when the application calls an asynchronous webgpu.h function. These functions return `WGPUFuture`, and take in their arguments a `CallbackInfo` struct like @ref WGPURequestDeviceCallbackInfo or @ref WGPUBufferMapCallbackInfo. `CallbackInfo` structs have the following members: 10 | - a `WGPUChainedStruct const * nextInChain` pointer, for extensions. 11 | - a @ref WGPUCallbackMode `mode` enum. 12 | - a `callback` function pointer. For example: 13 | ```c 14 | typedef void (*WGPUBufferMapCallback)( 15 | WGPUMapAsyncStatus status, 16 | WGPUStringView message, 17 | WGPU_NULLABLE void* userdata1, 18 | WGPU_NULLABLE void* userdata2) WGPU_FUNCTION_ATTRIBUTE; 19 | ``` 20 | - Two application-owned userdata members.
21 | `void* userdata1`
22 | `void* userdata2` 23 | 24 | The `callback` function pointer is called when the application _observes completion_ of the asynchronous operation. The `userdata1` and `userdata2` members are passed back to the application as the last two arguments in the callback function. Callbacks **might not** be called unless the application explicitly flushes them in order to _observe completion_. The point in time a callback is called depends on the @ref WGPUCallbackMode of the operation. webgpu.h provides three callback modes: @ref WGPUCallbackMode_WaitAnyOnly, @ref WGPUCallbackMode_AllowProcessEvents, and @ref WGPUCallbackMode_AllowSpontaneous. 25 | 26 | @ref WGPUCallbackMode_WaitAnyOnly 27 | 28 | > @copydoc ::WGPUCallbackMode_WaitAnyOnly 29 | 30 | @ref WGPUCallbackMode_AllowProcessEvents 31 | 32 | > @copydoc ::WGPUCallbackMode_AllowProcessEvents 33 | 34 | @ref WGPUCallbackMode_AllowSpontaneous 35 | 36 | > @copydoc ::WGPUCallbackMode_AllowSpontaneous 37 | 38 | ## Callback Statuses {#CallbackStatuses} 39 | 40 | Each event's callback has its own status enum. Generally, there will be one 41 | success case, and several failure cases. 42 | 43 | Every callback status enum has a `CallbackCancelled` status. This indicates that the callback was cancelled, though any background processing related to the event, like pipeline compilation, may not be complete. 44 | 45 | `CallbackCancelled` happens when the last (external) reference to the @ref WGPUInstance is dropped. 46 | At this point it becomes impossible to call @ref wgpuInstanceWaitAny or @ref wgpuInstanceProcessEvents. 47 | 48 | ## wgpuInstanceWaitAny {#Wait-Any} 49 | 50 | `WGPUWaitStatus wgpuInstanceWaitAny(WGPUInstance, size_t futureCount, WGPUFutureWaitInfo * futures, uint64_t timeoutNS)` 51 | 52 | Waits on any WGPUFuture in the list of `futures` to complete for `timeoutNS` nanoseconds. Returns when at least one `WGPUFuture` is completed or `timeoutNS` elapses, whichever is first. If `timeoutNS` is zero, all `futures` are polled once, without blocking. 53 | 54 | - Returns @ref WGPUWaitStatus_Success if at least one `WGPUFuture` completes. Each future which _just_ completed has its respective callback fired. Each future which _is_ complete has its corresponding @ref WGPUFutureWaitInfo::completed set to true. 55 | - Note that the timeout applies only to the "wait" phase, and does not affect the callback firing phase. 56 | - Returns @ref WGPUWaitStatus_TimedOut if the timeout passed without any futures completing. 57 | - Returns @ref WGPUWaitStatus_Error if the call was invalid for any of the following reasons: 58 | - A @ref Timed-Wait was performed when WGPUInstanceFeatures::timedWaitAnyEnable is not enabled. 59 | - The number of futures waited on in a @ref Timed-Wait is greater than the enabled WGPUInstanceFeatures::timedWaitAnyMaxCount. 60 | - A wait was attempted with @ref Mixed-Sources. 61 | 62 | ### Timed Wait {#Timed-Wait} 63 | 64 | Use of _timed waits_ (`timeoutNS > 0`), must be enabled on the WGPUInstance in @ref wgpuCreateInstance() with @ref WGPUInstanceFeatureName_TimedWaitAnyEnable, and the number of futures waited on must be less than or equal to @ref WGPUInstanceLimits::timedWaitAnyMaxCount. 65 | 66 | ### Mixed Sources {#Mixed-Sources} 67 | 68 | Asynchronous operations may originate from different sources. There are CPU-timeline operations and there are Queue-timeline operations. Within a _timed wait_, it is only valid to wait on `WGPUFuture`s originating from a single `WGPUQueue`. Waiting on two futures from different queues, or waiting on a Queue-timeline future and some other CPU-timeline future is an error. 69 | 70 | #### CPU-Timeline Operations 71 | 72 | - ::wgpuInstanceRequestAdapter 73 | - ::wgpuAdapterRequestDevice 74 | - ::wgpuShaderModuleGetCompilationInfo 75 | - ::wgpuDeviceCreateRenderPipelineAsync 76 | - ::wgpuDeviceCreateComputePipelineAsync 77 | - ::wgpuDevicePopErrorScope 78 | 79 | #### Queue-Timeline Operations 80 | 81 | - ::wgpuBufferMapAsync 82 | - ::wgpuQueueOnSubmittedWorkDone 83 | 84 | ## wgpuInstanceProcessEvents {#Process-Events} 85 | `void wgpuInstanceProcessEvents(WGPUInstance)` 86 | 87 | Processes asynchronous events on this `WGPUInstance`, calling any callbacks for asynchronous operations created with @ref WGPUCallbackMode_AllowProcessEvents that have completed. This is a non-blocking operation. 88 | 89 | ## Device Events 90 | 91 | Device events are slightly different in that their callback info are passed on the `WGPUDeviceDescriptor`, instead of in a function argument. 92 | 93 | - The DeviceLost callback is set via @ref WGPUDeviceDescriptor::deviceLostCallbackInfo. 94 | The Future for that event is @ref wgpuDeviceGetLostFuture. 95 | - The UncapturedError callback is set via @ref WGPUDeviceDescriptor::uncapturedErrorCallbackInfo. 96 | It is a repeating event, not a future, and it does not have a callback mode (see docs). 97 | 98 | The uncaptured error callback is guaranteed not to fire after the device becomes lost. When the device is lost, it is an appropriate time for the application to free userdata variables for the uncaptured error callback. Note that the device becomes lost _before_ the actual device lost callback fires. First the device state transitions to lost, then the device lost callback fires. The timing of the callback depends on the device lost callback mode. 99 | 100 | ## Callback Reentrancy {#CallbackReentrancy} 101 | 102 | There are three cases of async/callback re-entrancy: 103 | 104 | - Calls to the API are nested inside non-spontaneous callbacks (those with @ref WGPUCallbackMode_WaitAnyOnly or @ref WGPUCallbackMode_AllowProcessEvents). Such callbacks always happen in @ref wgpuInstanceWaitAny() or @ref wgpuInstanceProcessEvents(). 105 | - This does not introduce any unsafety. Implementations are required to exit critical sections before invoking callbacks. 106 | - This includes making nested calls to @ref wgpuInstanceWaitAny() and @ref wgpuInstanceProcessEvents(). (However, beware of overflowing the call stack!) 107 | - Calls to the API are nested inside @ref WGPUCallbackMode_AllowSpontaneous callbacks, which may happen at any time (during a `webgpu.h` function call or on an arbitrary thread). 108 | - Therefore, calls to the API should never be made in @ref WGPUCallbackMode_AllowSpontaneous callbacks, except where otherwise noted (e.g. @ref wgpuBufferGetMappedRange), due to the possibility of self-deadlock. 109 | Additionally, applications should take extra care even when accessing their *own* state (and locks) inside the callback. 110 | - This includes @ref WGPUDeviceDescriptor::uncapturedErrorCallbackInfo, which is always allowed to fire spontaneously. 111 | - Two threads are doing things in parallel, so calls to the API are made while callbacks (or API functions in general) are running on another thread. 112 | - In general, most API calls are thread-safe (see @ref ThreadSafety). 113 | -------------------------------------------------------------------------------- /doc/articles/BufferMapping.md: -------------------------------------------------------------------------------- 1 | # Buffer Mapping {#BufferMapping} 2 | 3 | ## Mapped Range Behavior {#MappedRangeBehavior} 4 | 5 | The @ref wgpuBufferGetMappedRange, @ref wgpuBufferGetConstMappedRange, @ref wgpuBufferReadMappedRange, and @ref wgpuBufferWriteMappedRange methods: 6 | 7 | - Fail (return `NULL` or `WGPUStatus_Error`) with @ref ImplementationDefinedLogging if: 8 | - There is any content-timeline error, as defined in the WebGPU specification for `getMappedRange()`, given the same buffer, offset, and size (buffer is not mapped, alignment constraints, overlaps, etc.) 9 | - **Except** for overlaps between *const* ranges, which are allowed in C *in non-Wasm targets only*. 10 | (Wasm does not allow this because const ranges do not exist in JS. 11 | All of these calls are implemented on top of `getMappedRange()`.) 12 | - @ref wgpuBufferGetMappedRange or @ref wgpuBufferWriteMappedRange is called, but the buffer is not mapped with @ref WGPUMapMode_Write. 13 | 14 | @ref wgpuBufferGetMappedRange, @ref wgpuBufferGetConstMappedRange additionally: 15 | 16 | - Do not guarantee they will return any particular address value relative to another GetMappedRange call. 17 | - Guarantee that the mapped pointer will be aligned to 16 bytes if the `MapAsync` and `GetMappedRange` offsets are also aligned to 16 bytes. 18 | 19 | More specifically: `GetMappedRange pointer` and `MapAsync offset + GetMappedRange offset` must be _congruent modulo_ `16`. 20 | 21 | - Implementations **should** try to guarantee better alignments (as large as 256 bytes), if they can do so without significant runtime overhead (i.e. without allocating new memory and copying data). 22 | -------------------------------------------------------------------------------- /doc/articles/Errors.md: -------------------------------------------------------------------------------- 1 | # Errors {#Errors} 2 | 3 | Errors are surfaced in several ways. 4 | 5 | Most errors only result from incorrect use of the API and should not need to be handled at runtime. 6 | However, a few (@ref WGPUErrorType_OutOfMemory, @ref WGPUErrorType_Internal) are potentially useful to handle. 7 | 8 | ## Device Error {#DeviceError} 9 | 10 | These behave the same way as [in the WebGPU JavaScript API specification](https://www.w3.org/TR/webgpu/#errors-and-debugging). 11 | They are receivable via @ref wgpuDevicePopErrorScope() and @ref WGPUDeviceDescriptor::uncapturedErrorCallbackInfo. 12 | 13 | These errors include: 14 | 15 | - All device-timeline errors in the WebGPU specification. 16 | - Enum values which are numerically invalid (this is not possible in JavaScript). 17 | - Enum values which are require features not enabled on the device (a [content-timeline](https://www.w3.org/TR/webgpu/#content-timeline) error in JavaScript), for example compressed texture formats. 18 | - Other content-timeline errors where specified. 19 | - @ref NonFiniteFloatValueError (except when they interrupt Wasm execution) 20 | 21 | ### Error Scopes {#ErrorScopes} 22 | 23 | Error scopes are used via @ref wgpuDevicePushErrorScope, @ref wgpuDevicePopErrorScope, and @ref WGPUDeviceDescriptor::uncapturedErrorCallbackInfo. These behave the same as in the JavaScript API, except for considerations around multi-threading (which JavaScript doesn't have at the time of this writing): 24 | 25 | - The error scope stack state is **thread-local**: each thread has a separate stack, which is initially empty. The error scope that captures an error depends on which thread made the API call that generated the error. 26 | Note in particular: 27 | - Async callbacks run on various threads and with unpredictable timing (see @ref Asynchronous-Operations), except when using @ref wgpuInstanceWaitAny. To avoid race conditions, if error scopes are used, applications generally should avoid having device errors escape from an async function, and/or should not keep scopes open when callbacks that could produce errors may run. 28 | - Runtimes with async task support (I/O runtimes, language async/coroutines/futures, etc.) may use "green threads" style systems to schedule tasks on different OS threads. Error scope stack state is OS-thread-local, not green-thread-local. 29 | - The UncapturedError callback (@ref WGPUDeviceDescriptor::uncapturedErrorCallbackInfo) is called for uncaptured errors on all threads. It **may** be called inline inside of a call to the API. 30 | 31 | ## Callback Error {#CallbackError} 32 | 33 | These behave similarly to the Promise-returning JavaScript APIs. Instead of there being two callbacks like in JavaScript (one for resolve and one for reject), there is a single callback which receives a status code, and depending on the status, _either_ a valid result with an empty message string (`{NULL, 0}`), _or_ an invalid result with a non-empty message string. 34 | 35 | ## Synchronous Error {#SynchronousError} 36 | 37 | These errors include: 38 | 39 | - @ref OutStructChainError cases. 40 | - [Content-timeline](https://www.w3.org/TR/webgpu/#content-timeline) errors other than those which are surfaced as @ref DeviceError in `webgpu.h`. See specific documentation to determine how each error is exposed. 41 | 42 | Generally these will return some kind of failure status (like \ref WGPUStatus_Error) or `NULL`, and produce an @ref ImplementationDefinedLogging message. 43 | 44 | ### Implementation-Defined Logging {#ImplementationDefinedLogging} 45 | 46 | Entry points may also specify that they produce "implementation-defined logging". 47 | These messages are logged in an implementation defined way (e.g. to an implementation-specific callback, or to a logging runtime). 48 | They are intended to be intended to be read by humans, useful primarily for development and crash reporting. 49 | -------------------------------------------------------------------------------- /doc/articles/Extensions.md: -------------------------------------------------------------------------------- 1 | # Extensions {#Extensions} 2 | 3 | `webgpu.h` is designed to be an extensible and forward-compatible API. 4 | The following types of extensions are supported: 5 | 6 | ``` 7 | wgpuPrefixNewFunction 8 | 9 | WGPUPrefixNewObject 10 | wgpuPrefixNewObjectNewMethod 11 | wgpuOldObjectPrefixNewMethod 12 | 13 | WGPUPrefixNewEnum 14 | WGPUPrefixNewEnum_NewValue 15 | WGPUOldEnum_PrefixNewValue 16 | 17 | WGPUPrefixNewStruct 18 | 19 | WGPUPrefixNewBitflagType 20 | WGPUPrefixNewBitflagType_NewValue 21 | WGPUOldBitflagType_PrefixNewValue 22 | 23 | WGPUPrefixNewCallback 24 | 25 | WGPU_PREFIX_NEW_CONSTANT 26 | ``` 27 | 28 | ("Prefix" is the name of the implementation that owns the extension, if any; see below.) 29 | 30 | When an application is running against an unknown `webgpu.h` implementation, extension support may be detected at runtime as follows: 31 | 32 | - New functions/methods may be runtime-detected by loading them dynamically, and checking whether loading succeeds. (@ref wgpuGetProcAddress() returns `NULL` for unknown function names.) 33 | - New objects may be detected by the presence of the methods that create them. 34 | - New (root) structs, enum/bitflag types, and callback types are always supported if the methods that accept them exist. 35 | - New enum/bitflag values and [chained structs](@ref StructChaining) are available iff the corresponding "feature" was already explicitly enabled for the context where they're used: 36 | - Device features are detected via @ref wgpuAdapterGetFeatures() and enabled via @ref WGPUDeviceDescriptor::requiredFeatures. 37 | - Instance features are detected via @ref wgpuHasInstanceFeature() and @ref wgpuGetInstanceFeatures(), and enabled via @ref WGPUInstanceDescriptor::requiredFeatures. 38 | - Instance limits are detected via @ref wgpuGetInstanceLimits(), and enabled via @ref WGPUInstanceDescriptor::requiredLimits. 39 | 40 | The following design principles should be followed to ensure future extensibility: 41 | 42 | - Enums always have a `Force32 = 0x7FFFFFFF` value to force them to be 32-bit (and have a stable ABI representation). 43 | - Bitflag types are always 64-bit. 44 | - Structures should be extensible (have a `nextInChain`), or at least be associated with some struct (e.g. child, sibling, or parent) that is extensible. 45 | 46 | Note also: 47 | 48 | - Whenever necessary a version `2` or implementation-specific version of an existing method or type can be added. 49 | 50 | ## Registry of prefixes and enum blocks 51 | 52 | Implementation-specific extensions **should** use the naming conventions listed above, with the name prefixes listed here. 53 | 54 | Implementation-specific extensions **must** use their assigned block when adding new values to existing enum types. (Implementation-specific enum types do not need to use these blocks since they are exclusive to one implementation.) 55 | 56 | If an implementation does not have an assigned prefix and block, it **should** be added to this registry. 57 | 58 | | | Prefix | Enum Block | Description 59 | |----------------------|--------------|---------------|------------ 60 | | Standard | (none) | `0x0000_????` | Extensions standardized in webgpu.h 61 | | Compatibility Mode | *TBD* | `0x0002_????` | **Special:** implementations that don't support Compatibility Mode must ignore any chained structs with @ref WGPUSType values in this block, instead of erroring. This block must only be used for Compat additions that can be ignored without affecting the semantics of a non-erroring program. 62 | | wgpu-native | `Wgpu` | `0x0003_????` | - 63 | | Emscripten | `Emscripten` | `0x0004_????` | - 64 | | Dawn | `Dawn` | `0x0005_????` | - 65 | | Wagyu | `Wagyu` | `0x0006_????` | - 66 | 67 | Note all negative values (values with the most-significant bit set to 1) are reserved for future use. 68 | 69 | ## Bitflag Registry {#BitflagRegistry} 70 | 71 | Implementation-specific extensions **must** choose one of the following options when adding new bitflag values: 72 | - Register their reserved bitflag values in this document. 73 | - Add a new bitflag type, and use it via an extension struct. 74 | 75 | Core and Compatibility Mode bits will always be in the least-significant 53 bits, because the JS API can only represent 53 bits. 76 | Therefore, extended bitflag values **should** be in the most-significant 11 bits, overflowing into the most-significant end of the least-significant 53 bits if necessary (or avoiding doing so by adding a new bitflag type entirely). 77 | 78 | - (None have been registered yet!) 79 | -------------------------------------------------------------------------------- /doc/articles/FloatingPointNumbers.md: -------------------------------------------------------------------------------- 1 | # Floating-Point Numbers {#FloatingPointNumbers} 2 | 3 | ## Double-as-Supertype {#DoubleAsSupertype} 4 | 5 | Like in the JS API, `double` (aka JavaScript's native `Number` type) is used in several places as a supertype of various numeric values. 6 | Such a value will be numerically downcast to the appropriate subtype depending how it is used, 7 | as specified in the JS API spec. 8 | 9 | - In @ref WGPUColor, as a supertype of `f32`/`u32`/`i32` 10 | - In @ref WGPURenderPassColorAttachment::clearValue, the type depends on the texture format. 11 | - In @ref wgpuRenderPassEncoderSetBlendConstant, the type is `f32`. 12 | - In @ref WGPUConstantEntry::value, as a supertype of all of the overrideable WGSL types 13 | (`bool`/`f32`/`u32`/`i32`/`f16` and possibly more). 14 | - The type depends on the WGSL type of the constant being overridden. 15 | 16 | ## Nullable Floating-Point Type {#NullableFloatingPointType} 17 | 18 | Floating-point-typed (`float`/`double`) values which are nullable or optional use `NaN` to 19 | represent the null value. A value `value` represents the null value iff `isnan(value) != 0`. 20 | (Do not use an equality check with a `NaN` constant, because `NaN == NaN` is false.) 21 | 22 | Infinities are invalid. See @ref NonFiniteFloatValueError. 23 | 24 | ## Non-Finite Float Value Errors {#NonFiniteFloatValueError} 25 | 26 | The JavaScript API does not allow non-finite floating-point values (it throws a `TypeError`). 27 | 28 | In `webgpu.h`, a value is finite iff `isfinite(value) != 0`. 29 | Using a non-finite value (aside from `NaN` for a @ref NullableFloatingPointType) 30 | results in a validation @ref DeviceError, except on Wasm-on-JS targets where a `TypeError` 31 | thrown by JS **may** be passed unhandled, interrupting Wasm execution. 32 | -------------------------------------------------------------------------------- /doc/articles/Multithreading.md: -------------------------------------------------------------------------------- 1 | # Multithreading {#Multithreading} 2 | 3 | `webgpu.h` implementations are allowed to require that all returned objects, except for `WGPUInstance`, can only be used from the thread they were created on, causing undefined behavior otherwise. 4 | 5 | Where multithreading is supported: 6 | 7 | - The implementation must provide the documented @ref ThreadSafety guarantees. 8 | - All objects must be freely usable on any thread at any time, except: 9 | - Where APIs are specified as being non-thread-safe, they must mutexed. 10 | - The exceptions for Wasm, below: @ref MultithreadingInWasm. 11 | - State must be thread-global, except where otherwise defined. 12 | - For example, buffer map state is thread-global, and mapped memory ranges may be used from any thread. 13 | - Note: Error scope state is thread-local. See @ref ErrorScopes. 14 | 15 | Native (non-Wasm) implementations **should** support multithreading. 16 | 17 | ## Multithreading In WebAssembly {#MultithreadingInWasm} 18 | 19 | At the time of this writing, the JS WebGPU API is not multithreading-capable. 20 | Initial `webgpu.h` implementations will not be multithreading-capable. 21 | 22 | Wasm-on-JS implementations *may* implement multithreading by proxying calls to a single JS "thread", as long as the C API behavior is conformant. 23 | 24 | Once the JS API is multithreading-capable, there are still expected to be some thread-local behaviors: 25 | 26 | - Buffer mapping state may be thread-local. 27 | - Implementations *should* make this state thread-global if feasible (e.g. by proxying all mapping calls to a single JS thread). 28 | - Any object which is non-shareable or non-transferable in JS may also be fully or partially non-shareable or non-transferable in Wasm (e.g. encoder objects may be thread-locked, similar to how they are not thread safe in `webgpu.h` in general). (In Rust terms, shareable = `Send`+`Sync`, transferable = `Send`.) 29 | - Implementations *may* make them shareable. (For example, proxying all encoder methods to a single thread would make them fully shareable but be inefficient; alternatively, encoder commands can be buffered, which might enable some multithreaded use-cases even if `Finish()` still must happen on the thread that created the encoder.) 30 | 31 | ## Thread Safety {#ThreadSafety} 32 | 33 | The `webgpu.h` API is thread-safe (when multithreading is supported). That is, its functions are reentrant and may be called during the execution of other functions, with the following exceptions: 34 | 35 | - Encoder objects (@ref WGPUCommandEncoder, @ref WGPUComputePassEncoder, @ref WGPURenderPassEncoder, and @ref WGPURenderBundleEncoder) are not thread-safe. Note these objects appear only in their own methods. 36 | - Additionally, in Wasm, these objects may be thread-locked, as discussed above. 37 | - API calls may not be made during @ref WGPUCallbackMode_AllowSpontaneous callbacks. See @ref CallbackReentrancy. 38 | 39 | The following _are_ thread safe: 40 | 41 | - @ref wgpuInstanceWaitAny() and @ref wgpuInstanceProcessEvents 42 | - @ref wgpuDeviceDestroy() 43 | - @ref wgpuBufferDestroy(), @ref wgpuTextureDestroy(), and @ref wgpuQuerySetDestroy() 44 | -------------------------------------------------------------------------------- /doc/articles/Ownership.md: -------------------------------------------------------------------------------- 1 | # Ownership {#Ownership} 2 | 3 | Objects in `webgpu.h` are refcounted via the `AddRef` and `Release` functions. 4 | The refcount only changes when these methods are called explicitly (not, for example, in \ref wgpuCommandEncoderFinish or \ref wgpuQueueSubmit). 5 | 6 | Applications are *not* required to maintain refs to WebGPU objects which are internally used by other WebGPU objects (CommandBuffer→BindGroup, BindGroup→TextureView, TextureView→Texture, etc.); `webgpu.h` implementations must maintain internal references, as needed, to be internally memory safe. These *internal* references do *not* make it safe to use objects that have ever reached an *external* refcount of 0. 7 | 8 | Memory for variable-sized outputs from the API (message strings, capability arrays, etc.) is managed in different ways depending on whether they are returned values or callback arguments. 9 | 10 | ## Returned with Ownership {#ReturnedWithOwnership} 11 | 12 | Objects returned directly from the API (e.g. \ref WGPUBuffer from \ref wgpuDeviceCreateBuffer and \ref WGPUTexture via \ref WGPUSurfaceTexture from \ref wgpuSurfaceGetCurrentTexture) start with one application-owned ref. 13 | The application must `Release` this ref before losing the pointer. 14 | (The returned object may _also_ have other refs, either API-owned refs or existing application-owned refs, but this should not be relied upon.) 15 | 16 | Variable-sized outputs returned from the API (e.g. the strings in \ref WGPUAdapterInfo, from \ref wgpuAdapterGetInfo) are application-owned. 17 | The application must call the appropriate `FreeMembers` function (e.g. \ref wgpuAdapterInfoFreeMembers) before losing the member pointers. 18 | `FreeMembers` functions do not traverse the [struct chain](@ref StructChaining) and must be called separately on each struct (that has a `FreeMembers` function) in the chain. 19 | 20 | Note that such functions will *not* free any previously-allocated data: overwriting an output structure without first releasing ownership will leak the allocations; e.g.: 21 | 22 | - Overwriting the strings in \ref WGPUAdapterInfo with \ref wgpuAdapterGetInfo without first calling \ref wgpuAdapterInfoFreeMembers. 23 | - Overwriting the `texture` in \ref WGPUSurfaceTexture with \ref wgpuSurfaceGetCurrentTexture without first calling \ref wgpuTextureRelease. 24 | 25 | Note also that some structs with `FreeMembers` functions may be used as both inputs and outputs. In this case `FreeMembers` must only be used if the member allocations were made by the `webgpu.h` implementation (as an output), not if they were made by the application (as an input). 26 | 27 | ## Releasing a Device object {#DeviceRelease} 28 | 29 | Unlike other destroyable objects, releasing the last (external) ref to a device causes it to be automatically destroyed, if it isn't already lost or destroyed. Though the device object is no longer valid to use after releasing the last ref, the direct effects of @ref wgpuDeviceDestroy() still take effect: 30 | 31 | - It destroys all buffers on the device, which will unmap them and abort any pending map requests. 32 | - It loses the device and triggers the DeviceLost event. 33 | 34 | Because the device's last ref has already been released, DeviceLost callbacks triggered in this way will *not* receive a pointer to the device object. More specifically, freeing the last ref: 35 | 36 | 1. Sets a flag on the DeviceLost future (if it is uncompleted, even if it is already ready) indicating it should pass a null @ref WGPUDevice to the callback. 37 | 1. Calls @ref wgpuDeviceDestroy(), readying the DeviceLost future. 38 | - This may call the DeviceLost callback, if it is @ref WGPUCallbackMode_AllowSpontaneous. 39 | 1. Decrements the refcount, bringing it to 0. 40 | 41 | ## Callback Arguments {#CallbackArgs} 42 | 43 | Output arguments passed from the API to application callbacks include objects and message strings, which are passed to most callbacks. 44 | 45 | ### Passed with Ownership {#PassedWithOwnership} 46 | 47 | Usually, object arguments passed to callbacks start with one application-owned ref, which the application must free before losing the pointer. 48 | 49 | ### Passed without Ownership {#PassedWithoutOwnership} 50 | 51 | A.k.a. "pass by reference". 52 | 53 | Sometimes, object arguments passed to callbacks are non-owning (such as the \ref WGPUDevice in \ref WGPUDeviceLostCallback) - the application doesn't need to free them. 54 | 55 | Variable-sized and [struct-chained](@ref StructChaining) outputs passed from the API to callbacks (such as message strings in most callbacks) are always owned by the API and passed without ownership. They are guaranteed to be valid only during the callback's execution, after which the pointers passed to the callback are no longer valid. 56 | 57 | ### Implementation-Allocated Struct Chain {#ImplementationAllocatedStructChain} 58 | 59 | Some callback arguments contain [chained structs](@ref StructChaining). 60 | These are allocated by the implementation. They: 61 | 62 | - May be chained in any order. 63 | - May contain chain members not known to the application (e.g. implementation-specific extensions or extensions added in a later version of `webgpu.h`). 64 | 65 | Applications must handle these cases gracefully, by traversing the struct chain and ignoring any structs in the chain that have @ref WGPUChainedStruct::sType values other than the ones they're interested in. 66 | 67 | Implementations may consider injecting bogus structs into such chains, e.g. `{.sType=0xDEADBEEF}` in debug builds, to help developers catch invalid assumptions in their applications. 68 | -------------------------------------------------------------------------------- /doc/articles/SentinelValues.md: -------------------------------------------------------------------------------- 1 | # Sentinel Values {#SentinelValues} 2 | 3 | ## Undefined and Null 4 | 5 | Since WebGPU is defined first as a JavaScript API, it uses the JavaScript value 6 | `undefined` in many places to indicate the lack of a value. 7 | 8 | This is usually used in dictionaries, where, for example, `{}` and 9 | `{ powerPreference: undefined }` are equivalent, and distinct from both 10 | `{ powerPreference: "high-performance" }` and `{ powerPreference: "low-power" }`. 11 | 12 | It may also be used in functions/methods. For example, `GPUBuffer`'s 13 | `getMappedRange(optional GPUSize64 offset = 0, optional GPUSize64 size)` 14 | can be called equivalently as `b.getMappedRange()`, `b.getMappedRange(0)`, 15 | `b.getMappedRange(undefined)`, or `b.getMappedRange(undefined, undefined)`. 16 | 17 | To represent `undefined` in C, `webgpu.h` uses `NULL` where possible (anything 18 | behind a pointer, including objects), `*_UNDEFINED` sentinel numeric values 19 | (usually `UINT32_MAX` or similar), `*_Undefined` enum values (usually `0`), 20 | or other semantic-specific names (like `WGPU_WHOLE_SIZE`). 21 | 22 | The place that uses the type will define what to do with an undefined or 23 | other sentinel value. It may be: 24 | 25 | - Required, in which case an error is produced. 26 | - Defaulting, in which case it trivially defaults to some other value. 27 | - Optional, in which case the API accepts the sentinel value and handles it 28 | (usually this is either a special value or it has more complex defaulting, 29 | for example depending on other values). 30 | 31 | ## C-Specific Sentinel Values 32 | 33 | Undefined and null values are also used in C-specific ways in place of 34 | WebIDL's more flexible typing: 35 | 36 | - \ref WGPUStringView has a special null value 37 | - \ref WGPUFuture has a special null value 38 | - Special cases to indicate the parent struct is null, avoiding extra layers of 39 | pointers just for nullability: 40 | - \ref WGPUVertexBufferLayout::stepMode = \ref WGPUVertexStepMode_Undefined with \ref WGPUVertexBufferLayout::attributeCount 41 | - \ref WGPUBufferBindingLayout::type = \ref WGPUBufferBindingType_BindingNotUsed 42 | - \ref WGPUSamplerBindingLayout::type = \ref WGPUSamplerBindingType_BindingNotUsed 43 | - \ref WGPUTextureBindingLayout::sampleType = \ref WGPUTextureSampleType_BindingNotUsed 44 | - \ref WGPUStorageTextureBindingLayout::access = \ref WGPUStorageTextureAccess_BindingNotUsed 45 | - \ref WGPURenderPassColorAttachment::view = `NULL` 46 | - \ref WGPUColorTargetState::format = \ref WGPUTextureFormat_Undefined 47 | - \ref NullableFloatingPointType 48 | -------------------------------------------------------------------------------- /doc/articles/Strings.md: -------------------------------------------------------------------------------- 1 | # Strings {#Strings} 2 | 3 | Strings are represented in UTF-8, using the \ref WGPUStringView struct: 4 | 5 | > \copydoc WGPUStringView 6 | 7 | ## Nullable Input String {#NullableInputString} 8 | 9 | An input string where the null value may be treated separately from the empty string (e.g. to indicate the absence of a string, or to run some non-trivial defaulting algorithm). 10 | 11 | ## Non-Null Input String {#NonNullInputString} 12 | 13 | This input string is non-nullable. 14 | If the null value is passed, it is treated as the empty string. 15 | 16 | ## Output String {#OutputString} 17 | 18 | This output string is always explicitly sized and never the null value. There is no null terminator inside the string; there may or may not be one after the end. If empty, the data pointer may or may not be null. 19 | 20 | To format explicitly-sized strings with `printf`, use `%.*s` (`%s` with a "precision" argument `.*` specifying the max number of bytes to read from the pointer). 21 | 22 | ### Localizable Human-Readable Message String {#LocalizableHumanReadableMessageString} 23 | 24 | This is a @ref OutputString which is human-readable and implementation-dependent, and may be locale-dependent. 25 | It should not be parsed or otherwise treated as machine-readable. 26 | -------------------------------------------------------------------------------- /doc/articles/StructChaining.md: -------------------------------------------------------------------------------- 1 | # Struct-Chaining {#StructChaining} 2 | 3 | Struct-chaining is a C API pattern using linked lists and dynamic typing to extend existing structs with new members, while maintaining API and ABI compatibility. For example: 4 | 5 | An extensible struct is statically typed. It is the root of a linked list, containing a pointer to the next struct in the chain: 6 | 7 | ```c 8 | typedef struct WGPUMyStructBase { 9 | WGPUChainedStruct * nextInChain; 10 | uint32_t x; 11 | } WGPUMyBaseStruct; 12 | ``` 13 | 14 | Each extension struct is a "subtype" of @ref WGPUChainedStruct; that is, its first member is a @ref WGPUChainedStruct, so that it can be safely cast to @ref WGPUChainedStruct. This allows the implementation to read its @ref WGPUChainedStruct::sType, which is some value of @ref WGPUSType ("Struct Type") that dynamically identifies the struct's type. (The `sType` may come from an implementation-specific extension; @ref WGPUSType is an "open" enum.) 15 | 16 | Once the implementation identifies the struct by its `sType`, it casts the pointer back to the appropriate struct type in order to access its contents. Setting `sType` incorrectly (or pointing to any type that isn't a subtype of @ref WGPUChainedStruct) causes undefined behavior. 17 | 18 | ```c 19 | typedef enum WGPUSType { 20 | // ... 21 | WGPUSType_MyStructExtension1 = /* ... */, 22 | WGPUSType_MyStructExtension2 = /* ... */, 23 | // ... 24 | } WGPUStype; 25 | 26 | typedef struct WGPUMyStructExtension1 { 27 | WGPUChainedStruct chain; // .chain.sType must be WGPUSType_MyStructExtension1 28 | uint32_t y; 29 | } WGPUMyStructExtension1; 30 | 31 | typedef struct WGPUMyStructExtension2 { 32 | WGPUChainedStruct chain; // .chain.sType must be WGPUSType_MyStructExtension2 33 | uint32_t z; 34 | } WGPUMyStructExtension2; 35 | ``` 36 | 37 | This is used like so: 38 | 39 | ```c 40 | WGPUMyStructExtension2 ext2 = WGPU_MY_STRUCT_EXTENSION2_INIT; 41 | // .chain.sType is already set correctly by the INIT macro. 42 | // .chain.next is set to NULL indicating the end of the chain. 43 | ext2.z = 2; 44 | 45 | WGPUMyStructExtension1 ext1 = WGPU_MY_STRUCT_EXTENSION1_INIT; 46 | // .chain.sType is already set correctly by the INIT macro. 47 | // .chain.next may be set in either of two ways, equivalently: 48 | ext1.chain.next = &ext2.chain; 49 | ext1.chain.next = (WGPUChainedStruct*) &ext2; 50 | ext1.y = 1; 51 | 52 | WGPUMyStructBase base = WGPU_MY_STRUCT_BASE_INIT; 53 | // Note: base structs do not have STypes (they are statically typed). 54 | base.nextInChain = &ext1.chain; 55 | base.x = 0; 56 | ``` 57 | 58 | The pointer links in a struct chain are all mutable pointers. Whether the structs in the chain are actually mutated depends on the function they are passed to (whether the struct chain is passed as an input or an output). Some structs (e.g. @ref WGPULimits) may be either an input or an output depending on the function being called. 59 | 60 | ## Struct-Chaining Error {#StructChainingError} 61 | 62 | A struct-chaining error occurs if a struct chain is incorrectly constructed (in a detectable way). 63 | They occur if and only if: 64 | 65 | - The `sType` of a struct in the chain is not valid _in the context of the chain root's static type_. 66 | - If this happens, the implementation must not downcast the pointer to access the rest of the struct (even if it would know how to downcast it in other contexts). 67 | - Multiple instances of the same `sType` value are seen in the same struct chain. (Note this also detects and disallows cycles.) 68 | - Implementation-specific extensions also _should_ avoid designs that use unbounded recursion (such as linked lists) in favor of iterative designs (arrays or arrays-of-pointers). This is to avoid stack overflows in struct handling and serialization/deserialization. 69 | 70 | Struct chains which are used in device-timeline validation/operations (e.g. @ref WGPUBufferDescriptor in @ref wgpuDeviceCreateBuffer) have their chain errors surfaced asynchronously, like any other validation error. 71 | 72 | Struct chains which are used in content-timeline operations (e.g. @ref OutStructChainError) have their chain errors surfaced synchronously, like other content-timeline validation errors. 73 | 74 | ### Out-Struct-Chain Error {#OutStructChainError} 75 | 76 | Operations which take out-struct-chains (e.g. @ref WGPULimits, in @ref wgpuAdapterGetLimits and @ref wgpuDeviceGetLimits, but not in @ref WGPUDeviceDescriptor) handle struct-chaining errors as follows: 77 | 78 | - The output struct and struct chain is not modified. 79 | - The operation produces a @ref SynchronousError (return value and log message). 80 | 81 | ## Ownership 82 | 83 | `FreeMembers` functions do not traverse the [struct chain](@ref StructChaining) and must be called separately on each struct (that has a `FreeMembers` function) in the chain. 84 | See @ref ReturnedWithOwnership. 85 | 86 | ## Callbacks 87 | 88 | See @ref PassedWithoutOwnership. 89 | -------------------------------------------------------------------------------- /doc/articles/Surfaces.md: -------------------------------------------------------------------------------- 1 | # Surfaces {#Surfaces} 2 | 3 | Surfaces are used to continuously present color texture data to users in an OS Window, HTML ``, or other similar outputs. 4 | The `webgpu.h` concept of @ref WGPUSurface is similar to WebGPU's [`GPUCanvasContext`](https://gpuweb.github.io/gpuweb/#canvas-context) but includes additional options to control behavior or query options that are specific to the environment the application runs in. In other GPU APIs, similar concepts are called "default framebuffer", "swapchain" or "presentable". 5 | 6 | To use a surface, there is a one-time setup, then additional per-frame operations. 7 | The one time setup is: environment-specific creation (to wrap a ``, `HWND`, `Window`, etc.), querying capabilities of the surface, and configuring the surface. 8 | Per-frame operations are: getting a current @ref WGPUSurfaceTexture to render content to, rendering content, presenting the surface, and when appropriate reconfiguring the surface (typically when the window is resized). 9 | 10 | Sections below give more details about these operations, including the specification of their behavior. 11 | 12 | ## Surface Creation {#Surface-Creation} 13 | 14 | A @ref WGPUSurface is child object of a @ref WGPUInstance and created using @ref wgpuInstanceCreateSurface. 15 | The description of a @ref WGPUSurface is a @ref WGPUSurfaceDescriptor with a sub-descriptor chained containing the environment-specific objects used to identify the surface. 16 | 17 | Surfaces that can be presented to using `webgpu.h` (but not necessarily by all implementations) are: 18 | 19 | - `ANativeWindow` on Android with @ref WGPUSurfaceSourceAndroidNativeWindow 20 | - `CAMetalLayer` on various Apple OSes like macOS and iOS with @ref WGPUSurfaceSourceMetalLayer 21 | - `` HTML elements in Emscripten (targeting WebAssembly) with `WGPUSurfaceSourceCanvasHTMLSelector_Emscripten` 22 | - `HWND` on Windows with @ref WGPUSurfaceSourceWindowsHWND 23 | - `Window` using Xlib with @ref WGPUSurfaceSourceXlibWindow 24 | - `wl_surface` on Wayland systems with @ref WGPUSurfaceSourceWaylandSurface 25 | - `xcb_window_t` using XCB windows with @ref WGPUSurfaceSourceXCBWindow 26 | 27 | Note, if the same environment-specific object is used as the output of two different things simultaneously (two different `WGPUSurface`s, or one `WGPUSurface` and something else outside `webgpu.h`), the behavior is undefined. 28 | 29 | For example, creating an @ref WGPUSurface from an `HWND` is done like so: 30 | 31 | ```c 32 | WGPUSurfaceSourceWindowsHWND hwndDesc = { 33 | .chain = { .sType = WGPUSType_SurfaceSourceWindowsHWND, }, 34 | .hinstance = GetModuleHandle(nullptr), 35 | .hwnd = myHWND, 36 | }; 37 | WGPUSurfaceDescriptor desc { 38 | .nextInChain = &hwndDesc.chain, 39 | .label = {.data = "Main window", .length = WGPU_STRLEN}, 40 | }; 41 | WGPUSurface surface = wgpuInstanceCreateSurface(myInstance, &desc); 42 | ``` 43 | 44 | In addition, a @ref WGPUSurface has a bunch of internal fields that could be represented like this (in C/Rust-like pseudocode): 45 | 46 | ```cpp 47 | struct WGPUSurface { 48 | // The parent object 49 | WGPUInstance instance; 50 | 51 | // The current configuration 52 | Option config = None; 53 | 54 | // A reference to the frame's texture, if any. 55 | Option currentFrame = None; 56 | }; 57 | ``` 58 | 59 | The behavior of @ref wgpuInstanceCreateSurface(instance, descriptor) is: 60 | 61 | - If any of these validation steps fails, return an error @ref WGPUSurface object: 62 | 63 | - Validate that all the sub-descriptors in the chain for `descriptor` are known to this implementation. 64 | - Validate that `descriptor` contains information about exactly one OS surface. 65 | - As best as possible, validate that the OS surface described in the descriptor is valid (for example a zero `HWND` doesn't exist and isn't valid). 66 | 67 | - Return a new @ref WGPUSurface with its `instance` member initialized with the `instance` parameter and other values defaulted. 68 | 69 | ## Querying Surface Capabilities {#Surface-Capabilities} 70 | 71 | Depending on the OS, GPU used, backing API for WebGPU and other factors, different capabilities are available to render and present the @ref WGPUSurface. 72 | For this reason, negotiation is done between the WebGPU implementation and the application to choose how to use the @ref WGPUSurface. 73 | This first step of the negotiation is querying what capabilities are available using @ref wgpuSurfaceGetCapabilities that fills an @ref WGPUSurfaceCapabilities structure with the following information: 74 | 75 | - A bit set of supported @ref WGPUTextureUsage that are guaranteed to contain @ref WGPUTextureUsage_RenderAttachment. 76 | - A list of supported @ref WGPUTextureFormat values, in order of preference. 77 | - A list of supported @ref WGPUPresentMode values (guaranteed to contain @ref WGPUPresentMode_Fifo). 78 | - A list of supported @ref WGPUCompositeAlphaMode values (@ref WGPUCompositeAlphaMode_Auto is always supported but never listed in capabilities as it just lets the implementation decide what to use). 79 | 80 | The call to @ref wgpuSurfaceGetCapabilities may allocate memory for pointers filled in the @ref WGPUSurfaceCapabilities structure so @ref wgpuSurfaceCapabilitiesFreeMembers must be called to avoid leaking memory once the capabilities are no longer needed. 81 | 82 | This is an example of how to query the capabilities of a @ref WGPUSurface: 83 | 84 | ```c 85 | // Get the capabilities 86 | WGPUSurfaceCapabilities caps; 87 | if (!wgpuSurfaceGetCapabilities(mySurface, myAdapter, &caps)) { 88 | // Either a validation error happened or the adapter doesn't support the surface. 89 | // TODO: This should be a WGPUStatus. 90 | return; 91 | } 92 | 93 | // Do things with capabilities 94 | bool canSampleSurface = caps.usages & WGPUTextureUsage_TextureBinding; 95 | WGPUTextureFormat preferredFormat = caps.format[0]; 96 | 97 | bool supportsMailbox = false; 98 | for (size_t i = 0; i < caps.presentModeCount; i++) { 99 | if (caps.presentModes[i] == WGPUPresentMode_Mailbox) supportsMailbox = true; 100 | } 101 | 102 | // Cleanup 103 | wgpuSurfaceCapabilitiesFreeMembers(caps); 104 | ``` 105 | 106 | The behavior of @ref wgpuSurfaceGetCapabilities(surface, adapter, caps) is: 107 | 108 | - If any of these validation steps fails, return false. (TODO return an error WGPUStatus): 109 | 110 | - Validate that all the sub-descriptors in the chain for `caps` are known to this implementation. 111 | - Validate that `surface` and `adapter` are created from the same @ref WGPUInstance. 112 | 113 | - Fill `caps` with `adapter`'s capabilities to render to `surface`. 114 | - Return true. (TODO return WGPUStatus_Success) 115 | 116 | ## Surface Configuration {#Surface-Configuration} 117 | 118 | Before it can use it for rendering, the application must configure the surface. 119 | The configuration is the second step of the negotiation, done after analyzing the results of @ref wgpuSurfaceGetCapabilities. 120 | It contains the following kinds of parameters: 121 | 122 | - The @ref WGPUDevice that will be used to render to the surface. 123 | - Parameters for the textures returned by @ref wgpuSurfaceGetCurrentTexture. 124 | - @ref WGPUPresentMode and @ref WGPUCompositeAlphaMode parameters for how and when the surface will be presented to the user. 125 | 126 | This is an example of how to configure a @ref WGPUSurface: 127 | 128 | ```c 129 | WGPUSurfaceConfiguration config = { 130 | nextInChain = nullptr, 131 | device = myDevice, 132 | format = preferredFormat, 133 | width = 640, // Depending on the window size. 134 | height = 480, 135 | usage = WGPUTextureUsage_RenderAttachment, 136 | presentMode = supportsMailbox ? WGPUPresentMode_Mailbox : WGPUPresentMode_Fifo, 137 | alphaMode = WGPUCompositeAlphaMode_Auto, 138 | }; 139 | wgpuSurfaceConfigure(mySurface, &config); 140 | ``` 141 | 142 | The parameters for the texture are used to create the texture each frame (see @ref Surface-Presenting) with the equivalent @ref WGPUTextureDescriptor computed like this: 143 | 144 | ```c 145 | WGPUTextureDescriptor GetSurfaceEquivalentTextureDescriptor(const WGPUSurfaceConfiguration* config) { 146 | return { 147 | // Parameters controlled by the surface configuration. 148 | .size = {config->width, config->height, 1}, 149 | .usage = config->usage, 150 | .format = config->format, 151 | .viewFormatCount = config->viewFormatCount, 152 | .viewFormats = config->viewFormats, 153 | 154 | // Parameters that cannot be changed. 155 | .nextInChain = nullptr, 156 | .label = {.data = "", .length = WGPU_STRLEN}, 157 | .dimension = WGPUTextureDimension_2D, 158 | .sampleCount = 1, 159 | .mipLevelCount = 1, 160 | }; 161 | } 162 | ``` 163 | 164 | When a surface is successfully configured, the new configuration overrides any previous configuration and destroys the previous current texture (if any) so it can no longer be used. 165 | 166 | The behavior of @ref wgpuSurfaceConfigure(surface, config) is: 167 | 168 | - If any of these validation steps fails, TODO: what should happen on failure? 169 | 170 | - Validate that `surface` is not an error. 171 | - Let `adapter` be the adapter used to create `device`. 172 | - Let `caps` be the @ref WGPUSurfaceCapabilities filled with @ref wgpuSurfaceGetCapabilities(surface, adapter, &caps). 173 | - Validate that all the sub-descriptors in the chain for `caps` are known to this implementation. 174 | - Validate that `device` is alive. 175 | - Validate that `config->presentMode` is in `caps->presentModes`. 176 | - Validate that `config->alphaMode` is either `WGPUCompositeAlphaMode_Auto` or in `caps->alphaModes`. 177 | - Validate that `config->format` if in `caps->formats`. 178 | - Validate that `config->usage` is a subset of `caps->usages`. 179 | - Let `textureDesc` be `GetSurfaceEquivalentTextureDescriptor(config)`. 180 | - Validate that `wgpuDeviceCreateTexture(device, &textureDesc)` would succeed. 181 | 182 | - Set `surface.config` to a deep copy of `config`. 183 | - If `surface.currentFrame` is not `None`: 184 | 185 | - Do as if @ref wgpuTextureDestroy(surface.currentFrame) was called. 186 | - Set `surface.currentFrame` to `None`. 187 | 188 | It can also be useful to remove the configuration of a @ref WGPUSurface without replacing it with a valid one. 189 | Without removing the configuration, the @ref WGPUSurface will keep referencing the @ref WGPUDevice that cannot be totally reclaimed. 190 | 191 | The behavior of @ref wgpuSurfaceUnconfigure() is: 192 | 193 | - Set `surface.config` to `None`. 194 | - If `surface.currentFrame` is not `None`: 195 | 196 | - Do as if @ref wgpuTextureDestroy(surface.currentFrame) was called. 197 | - Set `surface.currentFrame` to `None`. 198 | 199 | ## Presenting to Surface {#Surface-Presenting} 200 | 201 | Each frame, the application retrieves the @ref WGPUTexture for the frame with @ref wgpuSurfaceGetCurrentTexture, renders to it and then presents it on the screen with @ref wgpuSurfacePresent. 202 | 203 | Issues can happen when trying to retrieve the frame's @ref WGPUTexture, so the application must check @ref WGPUSurfaceTexture `.status` to see if the surface or the device was lost, or some other windowing system issue caused a timeout. 204 | The environment can also change the surface without breaking it, but making the current configuration suboptimal. 205 | In this case, @ref WGPUSurfaceTexture `.status` will be @ref WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal and the application should (but isn't required to) handle it. 206 | Surfaces often become suboptimal when the window is resized (so presenting requires resizing a texture, which is both performance overhead, and a visual quality degradation). 207 | 208 | This is an example of how to render to a @ref WGPUSurface each frame: 209 | 210 | ```c 211 | // Get the texture and handle exceptional cases. 212 | WGPUSurfaceTexture surfaceTexture; 213 | wgpuSurfaceGetCurrentTexture(mySurface, &surfaceTexture); 214 | 215 | if (surfaceTexture.texture == NULL) { 216 | // Recover if possible. 217 | return; 218 | } 219 | // Since the texture is not null, the status is some kind of success. 220 | // We can optionally handle the "SuccessSuboptimal" case. 221 | if (surfaceTexture.status == WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal) { 222 | HandleResize(); 223 | return; 224 | } 225 | 226 | // The application renders to the texture. 227 | RenderTo(surfaceTexture.texture); 228 | 229 | // Present the texture, it is no longer accessible after that point. 230 | wgpuSurfacePresent(mySurface); 231 | 232 | // Release the reference we got to the now presented texture. (it can safely be done before present as well) 233 | wgpuTextureRelease(surfaceTexture.texture); 234 | 235 | ``` 236 | 237 | The behavior of @ref wgpuSurfaceGetCurrentTexture(surface, surfaceTexture) is: 238 | 239 | 1. Set `surfaceTexture->texture` to `NULL`. 240 | 1. If any of these validation steps fails, set `surfaceTexture->status` to `WGPUSurfaceGetCurrentTextureStatus_Error` and return (TODO send error to device?). 241 | 1. Validate that `surface` is not an error. 242 | 1. Validate that `surface.config` is not `None`. 243 | 1. Validate that `surface.currentFrame` is `None`. 244 | 1. Let `textureDesc` be `GetSurfaceEquivalentTextureDescriptor(surface.config)`. 245 | 1. If `surface.config.device` is alive: 246 | 1. If the implementation detects any other problem preventing use of the surface, set `surfaceTexture->status` to an appropriate status (something other than `SuccessOptimal`, `SuccessSuboptimal`, or `Error`) and return. 247 | 1. Create a new @ref WGPUTexture `t`, as if calling `wgpuDeviceCreateTexture(surface.config.device, &textureDesc)`, but wrapping the appropriate backing resource. 248 | 1. If the implementation detects a reason why the current configuration is suboptimal, set `surfaceTexture->status` to `WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal`. 249 | Otherwise, set it to `WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal`. 250 | 251 | Otherwise: 252 | 1. Create a new invalid @ref WGPUTexture `t`, as if calling `wgpuDeviceCreateTexture(surface.config.device, &texturedesc)`. 253 | 1. Set `surfaceTexture->status` to `WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal`. 254 | 1. Set `surface.currentFrame` to `t`. 255 | 1. Add a new reference to `t`. 256 | 1. Set `surfaceTexture->texture` to a new reference to `t`. 257 | 258 | The behavior of @ref wgpuSurfacePresent(surface) is: 259 | 260 | - If any of these validation steps fails, TODO send error to device? 261 | 262 | - Validate that `surface` is not an error. 263 | - Validate that `surface.currentFrame` is not `None`. 264 | 265 | - Do as if @ref wgpuTextureDestroy(surface.currentFrame) was called. 266 | - Present `surface.currentFrame` to the `surface`. 267 | - Set `surface.currentFrame` to `None`. 268 | -------------------------------------------------------------------------------- /doc/articles/index.md: -------------------------------------------------------------------------------- 1 | \page articles Articles 2 | 3 | - \subpage Asynchronous-Operations 4 | - \subpage BufferMapping 5 | - \subpage Errors 6 | - \subpage Extensions 7 | - \subpage FloatingPointNumbers 8 | - \subpage Multithreading 9 | - \subpage Ownership 10 | - \subpage SentinelValues 11 | - \subpage Strings 12 | - \subpage StructChaining 13 | - \subpage Surfaces 14 | -------------------------------------------------------------------------------- /fix/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | command "github.com/mikefarah/yq/v4/cmd" 9 | ) 10 | 11 | var ( 12 | yamlPath string 13 | ) 14 | 15 | func main() { 16 | flag.StringVar(&yamlPath, "yaml", "", "path of the yaml spec") 17 | flag.Parse() 18 | 19 | arrays := []string{"constants", "typedefs", "enums", "bitflags", "structs", "callbacks", "functions", "objects"} 20 | for _, array := range arrays { 21 | SortArrayByFieldInPlace(array, "name") 22 | } 23 | } 24 | 25 | func SortArrayByFieldInPlace(array string, field string) { 26 | args := []string{"eval", "-i", fmt.Sprintf(".%s |= sort_by(.%s | downcase)", array, field), yamlPath} 27 | 28 | cmd := command.New() 29 | cmd.SetArgs(args) 30 | if err := cmd.Execute(); err != nil { 31 | os.Exit(1) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /gen/README.md: -------------------------------------------------------------------------------- 1 | # gen 2 | 3 | The generator for generating `webgpu.h` header and other extension headers or implementation specific headers from the yaml spec files. 4 | 5 | # Generate implementation specific header 6 | 7 | The generator also allows generating custom implementation specific headers that build on top of `webgpu.h` header. The generator accepts the combination of `-yaml` & `-header` flags in sequence, which it uses to validate the specifications and then generate their headers. 8 | 9 | For example, if `wgpu.yml` contains the implementation specific API, the header can be generated using: 10 | 11 | ```shell 12 | > go run ./gen -schema schema.json -yaml webgpu.yml -header webgpu.h -yaml wgpu.yml -header wgpu.h 13 | ``` 14 | 15 | Since the generator does some duplication validation, the order of the files matter, so generator mandates the core `webgpu.yml` to be first in the sequence. 16 | 17 | # yaml spec 18 | 19 | ### Types 20 | 21 | | Primitive types | Complex types | 22 | | --------------- | ----------------- | 23 | | `bool` | `enum.*` | 24 | | `string` | `bitflag.*` | 25 | | `uint16` | `struct.*` | 26 | | `uint32` | `function_type.*` | 27 | | `uint64` | `object.*` | 28 | | `usize` | 29 | | `int16` | 30 | | `int32` | 31 | | `float32` | 32 | | `float64` | 33 | | `c_void` | 34 | 35 | | Structure types | | 36 | | ------------------------- | ------------------------------------------------------ | 37 | | `extensible` | structs that can be extended | 38 | | `extensible_callback_arg` | structs used as callback args that can be extended | 39 | | `extension` | extension structs used in `extensible` structs' chains | 40 | | `standalone` | structs that are neither extensions nor extensible | 41 | 42 | #### Arrays 43 | 44 | Arrays are supported using a special syntax, for example `array`. The generator will emit two fields for array types, one for element count and another for the pointer to the type. 45 | -------------------------------------------------------------------------------- /gen/cheader.tmpl: -------------------------------------------------------------------------------- 1 | {{- MCommentN .Copyright 0}} 2 | 3 | /** @file */ 4 | {{MCommentMainPage .Doc 0}} 5 | 6 | #ifndef {{.HeaderName | ConstantCase}}_H_ 7 | #define {{.HeaderName | ConstantCase}}_H_ 8 | 9 | {{ if eq .Name "webgpu" -}} 10 | #if defined(WGPU_SHARED_LIBRARY) 11 | # if defined(_WIN32) 12 | # if defined(WGPU_IMPLEMENTATION) 13 | # define WGPU_EXPORT __declspec(dllexport) 14 | # else 15 | # define WGPU_EXPORT __declspec(dllimport) 16 | # endif 17 | # else // defined(_WIN32) 18 | # if defined(WGPU_IMPLEMENTATION) 19 | # define WGPU_EXPORT __attribute__((visibility("default"))) 20 | # else 21 | # define WGPU_EXPORT 22 | # endif 23 | # endif // defined(_WIN32) 24 | #else // defined(WGPU_SHARED_LIBRARY) 25 | # define WGPU_EXPORT 26 | #endif // defined(WGPU_SHARED_LIBRARY) 27 | 28 | #if !defined(WGPU_OBJECT_ATTRIBUTE) 29 | #define WGPU_OBJECT_ATTRIBUTE 30 | #endif 31 | #if !defined(WGPU_ENUM_ATTRIBUTE) 32 | #define WGPU_ENUM_ATTRIBUTE 33 | #endif 34 | #if !defined(WGPU_STRUCTURE_ATTRIBUTE) 35 | #define WGPU_STRUCTURE_ATTRIBUTE 36 | #endif 37 | #if !defined(WGPU_FUNCTION_ATTRIBUTE) 38 | #define WGPU_FUNCTION_ATTRIBUTE 39 | #endif 40 | #if !defined(WGPU_NULLABLE) 41 | #define WGPU_NULLABLE 42 | #endif 43 | 44 | #include 45 | #include 46 | #include 47 | 48 | #define _wgpu_COMMA , 49 | #if defined(__cplusplus) 50 | # define _wgpu_ENUM_ZERO_INIT(type) type(0) 51 | # define _wgpu_STRUCT_ZERO_INIT {} 52 | # if __cplusplus >= 201103L 53 | # define _wgpu_MAKE_INIT_STRUCT(type, value) (type value) 54 | # else 55 | # define _wgpu_MAKE_INIT_STRUCT(type, value) value 56 | # endif 57 | #else 58 | # define _wgpu_ENUM_ZERO_INIT(type) (type)0 59 | # define _wgpu_STRUCT_ZERO_INIT {0} 60 | # if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 61 | # define _wgpu_MAKE_INIT_STRUCT(type, value) ((type) value) 62 | # else 63 | # define _wgpu_MAKE_INIT_STRUCT(type, value) value 64 | # endif 65 | #endif 66 | {{- else -}} 67 | #include "webgpu.h" 68 | 69 | #if !defined(_wgpu_EXTEND_ENUM) 70 | #ifdef __cplusplus 71 | #define _wgpu_EXTEND_ENUM(E, N, V) static const E N = E(V) 72 | #else 73 | #define _wgpu_EXTEND_ENUM(E, N, V) static const E N = (E)(V) 74 | #endif 75 | #endif // !defined(_wgpu_EXTEND_ENUM) 76 | {{- end }} 77 | 78 | /** 79 | * \defgroup Constants Constants 80 | * \brief Constants. 81 | * 82 | * @{ 83 | */ 84 | 85 | /** 86 | * 'True' value of @ref WGPUBool. 87 | * 88 | * @remark It's not usually necessary to use this, as `true` (from 89 | * `stdbool.h` or C++) casts to the same value. 90 | */ 91 | #define WGPU_TRUE (UINT32_C(1)) 92 | /** 93 | * 'False' value of @ref WGPUBool. 94 | * 95 | * @remark It's not usually necessary to use this, as `false` (from 96 | * `stdbool.h` or C++) casts to the same value. 97 | */ 98 | #define WGPU_FALSE (UINT32_C(0)) 99 | {{- range .Constants}} 100 | {{- MComment .Doc 0}} 101 | #define WGPU_{{ConstantCaseName .Base}} ({{.Value | CValue}}) 102 | {{- end}} 103 | 104 | /** @} */ 105 | 106 | /** 107 | * \defgroup UtilityTypes Utility Types 108 | * 109 | * @{ 110 | */ 111 | {{ if eq .Name "webgpu"}} 112 | /** 113 | * Nullable value defining a pointer+length view into a UTF-8 encoded string. 114 | * 115 | * Values passed into the API may use the special length value @ref WGPU_STRLEN 116 | * to indicate a null-terminated string. 117 | * Non-null values passed out of the API (for example as callback arguments) 118 | * always provide an explicit length and **may or may not be null-terminated**. 119 | * 120 | * Some inputs to the API accept null values. Those which do not accept null 121 | * values "default" to the empty string when null values are passed. 122 | * 123 | * Values are encoded as follows: 124 | * - `{NULL, WGPU_STRLEN}`: the null value. 125 | * - `{non_null_pointer, WGPU_STRLEN}`: a null-terminated string view. 126 | * - `{any, 0}`: the empty string. 127 | * - `{NULL, non_zero_length}`: not allowed (null dereference). 128 | * - `{non_null_pointer, non_zero_length}`: an explictly-sized string view with 129 | * size `non_zero_length` (in bytes). 130 | * 131 | * For info on how this is used in various places, see \ref Strings. 132 | */ 133 | typedef struct WGPUStringView { 134 | WGPU_NULLABLE char const * data; 135 | size_t length; 136 | } WGPUStringView WGPU_STRUCTURE_ATTRIBUTE; 137 | 138 | /** 139 | * Initializer for @ref WGPUStringView. 140 | */ 141 | #define WGPU_STRING_VIEW_INIT _wgpu_MAKE_INIT_STRUCT(WGPUStringView, { \ 142 | /*.data=*/NULL _wgpu_COMMA \ 143 | /*.length=*/WGPU_STRLEN _wgpu_COMMA \ 144 | }) 145 | 146 | typedef uint64_t WGPUFlags; 147 | typedef uint32_t WGPUBool; 148 | {{- end }} 149 | {{- range .Typedefs}} 150 | {{- MComment .Doc 0}} 151 | typedef {{CType .Type ""}} {{CType .Base ""}}; 152 | {{- end}} 153 | 154 | /** @} */ 155 | 156 | /** 157 | * \defgroup Objects Objects 158 | * \brief Opaque, non-dispatchable handles to WebGPU objects. 159 | * 160 | * @{ 161 | */ 162 | 163 | {{- range .Objects}} 164 | {{- if and (not .IsStruct) (not .Extended)}} 165 | {{- MComment .Doc 0}} 166 | typedef struct {{CType .Base ""}}Impl* {{CType .Base ""}} WGPU_OBJECT_ATTRIBUTE; 167 | {{- end}} 168 | {{- end}} 169 | 170 | /** @} */ 171 | 172 | {{- if .Structs}} 173 | 174 | // Structure forward declarations 175 | {{- range .Structs}} 176 | struct {{CType .Base ""}}; 177 | {{- end}} 178 | {{- end}} 179 | 180 | {{- if .Callbacks}} 181 | 182 | // Callback info structure forward declarations 183 | {{- range .Callbacks}} 184 | struct {{CType .Base ""}}CallbackInfo; 185 | {{- end}} 186 | {{- end}} 187 | 188 | /** 189 | * \defgroup Enumerations Enumerations 190 | * \brief Enums. 191 | * 192 | * @{ 193 | */ 194 | 195 | {{- range $enum := .Enums}} 196 | {{ MComment .Doc 0}} 197 | {{- if .Extended}} 198 | {{- range $entryIndex, $_ := .Entries}} 199 | {{- if .}} 200 | {{- MCommentEnumValue .Doc 0 $enum $entryIndex }} 201 | _wgpu_EXTEND_ENUM({{CType $enum.Base ""}}, {{CEnumName $enum.Base .Base}}, {{EnumValue32 $enum $entryIndex | printf "0x%.8X"}}); 202 | {{- end}} 203 | {{- end}} 204 | {{- else}} 205 | typedef enum {{CType .Base ""}} { 206 | {{- range $entryIndex, $_ := .Entries}} 207 | {{- if .}} 208 | {{- MCommentEnumValue .Doc 4 $enum $entryIndex }} 209 | {{CEnumName $enum.Base .Base}} = {{EnumValue32 $enum $entryIndex | printf "0x%.8X"}}, 210 | {{- end}} 211 | {{- end}} 212 | {{CType $enum.Base ""}}_Force32 = 0x7FFFFFFF 213 | } {{CType .Base ""}} WGPU_ENUM_ATTRIBUTE; 214 | {{- end}} 215 | {{- end}} 216 | 217 | /** @} */ 218 | 219 | /** 220 | * \defgroup Bitflags Bitflags 221 | * \brief Type and constant definitions for bitflag types. 222 | * 223 | * @{ 224 | */ 225 | 226 | {{- range $bitflag := .Bitflags}} 227 | {{ MCommentBitflagType .Doc 0}} 228 | {{- if not .Extended}} 229 | typedef WGPUFlags {{CType .Base ""}}; 230 | {{- end}} 231 | {{- range $entryIndex, $_ := .Entries}} 232 | {{- MCommentBitflagValue .Doc 0 $bitflag $entryIndex }} 233 | static const {{CType $bitflag.Base ""}} {{CEnumName $bitflag.Base .Base}} = {{BitflagValue $bitflag $entryIndex}}; 234 | {{- end}} 235 | {{- end}} 236 | 237 | /** @} */ 238 | 239 | {{- if eq .Name "webgpu"}} 240 | 241 | typedef void (*WGPUProc)(void) WGPU_FUNCTION_ATTRIBUTE; 242 | {{- end}} 243 | 244 | /** 245 | * \defgroup Callbacks Callbacks 246 | * \brief Callbacks through which asynchronous functions return. 247 | * 248 | * @{ 249 | */ 250 | 251 | {{- range .Callbacks}} 252 | {{ MCommentCallback . 0}} 253 | typedef void (*{{CType .Base ""}}Callback)({{CallbackArgs .}}) WGPU_FUNCTION_ATTRIBUTE; 254 | {{- end}} 255 | 256 | /** @} */ 257 | 258 | {{- if eq .Name "webgpu"}} 259 | /** 260 | * \defgroup ChainedStructures Chained Structures 261 | * \brief Structures used to extend descriptors. 262 | * 263 | * @{ 264 | */ 265 | 266 | typedef struct WGPUChainedStruct { 267 | struct WGPUChainedStruct * next; 268 | WGPUSType sType; 269 | } WGPUChainedStruct WGPU_STRUCTURE_ATTRIBUTE; 270 | 271 | /** @} */ 272 | {{ end}} 273 | 274 | /** 275 | * \defgroup Structures Structures 276 | * \brief Descriptors and other transparent structures. 277 | * 278 | * @{ 279 | */ 280 | 281 | /** 282 | * \defgroup CallbackInfoStructs Callback Info Structs 283 | * \brief Callback info structures that are used in asynchronous functions. 284 | * 285 | * @{ 286 | */ 287 | 288 | {{- range .Callbacks}} 289 | {{ MComment .Doc 0}} 290 | typedef struct {{CType .Base ""}}CallbackInfo { 291 | WGPUChainedStruct * nextInChain; 292 | {{- if eq .Style "callback_mode" }} 293 | /** 294 | * Controls when the callback may be called. 295 | * 296 | * Has no default. The `INIT` macro sets this to (@ref WGPUCallbackMode)0. 297 | */ 298 | WGPUCallbackMode mode; 299 | {{- end}} 300 | {{CType .Base ""}}Callback callback; 301 | WGPU_NULLABLE void* userdata1; 302 | WGPU_NULLABLE void* userdata2; 303 | } {{CType .Base ""}}CallbackInfo WGPU_STRUCTURE_ATTRIBUTE; 304 | 305 | /** 306 | * Initializer for @ref {{CType .Base ""}}CallbackInfo. 307 | */ 308 | #define WGPU_{{ConstantCaseName .Base}}_CALLBACK_INFO_INIT _wgpu_MAKE_INIT_STRUCT({{CType .Base ""}}CallbackInfo, { \ 309 | /*.nextInChain=*/NULL _wgpu_COMMA \ 310 | {{- if eq .Style "callback_mode" }} 311 | /*.mode=*/_wgpu_ENUM_ZERO_INIT(WGPUCallbackMode) _wgpu_COMMA \ 312 | {{- end}} 313 | /*.callback=*/NULL _wgpu_COMMA \ 314 | /*.userdata1=*/NULL _wgpu_COMMA \ 315 | /*.userdata2=*/NULL _wgpu_COMMA \ 316 | }) 317 | {{- end}} 318 | 319 | /** @} */ 320 | 321 | {{- "\n"}} 322 | {{- range $struct := .Structs}} 323 | {{- MCommentStruct . 0}} 324 | typedef struct {{CType .Base ""}} { 325 | {{- if or (eq .Type "extensible") (eq .Type "extensible_callback_arg") }} 326 | WGPUChainedStruct * nextInChain; 327 | {{- else if eq .Type "extension"}} 328 | WGPUChainedStruct chain; 329 | {{- end}} 330 | {{- range $memberIndex, $_ := .Members}} 331 | {{- if (.Type | IsArray)}} 332 | /** 333 | * Array count for `{{.Name | CamelCase}}`. The `INIT` macro sets this to 0. 334 | */ 335 | {{ StructMemberArrayCount $struct $memberIndex}} 336 | {{- MCommentMember . 4 }} 337 | {{ StructMemberArrayData $struct $memberIndex}} 338 | {{- else}} 339 | {{- MCommentMember . 4 }} 340 | {{ StructMember $struct $memberIndex}} 341 | {{- end}} 342 | {{- end}} 343 | } {{CType .Base ""}} WGPU_STRUCTURE_ATTRIBUTE; 344 | 345 | /** 346 | * Initializer for @ref {{CType .Base ""}}. 347 | */ 348 | #define WGPU_{{ConstantCaseName .Base}}_INIT _wgpu_MAKE_INIT_STRUCT({{CType .Base ""}}, { \ 349 | {{- if or (eq .Type "extensible") (eq .Type "extensible_callback_arg") }} 350 | /*.nextInChain=*/NULL _wgpu_COMMA \ 351 | {{- else if eq .Type "extension" }} 352 | /*.chain=*/_wgpu_MAKE_INIT_STRUCT(WGPUChainedStruct, { \ 353 | /*.next=*/NULL _wgpu_COMMA \ 354 | /*.sType=*/WGPUSType_{{PascalCaseName .Base}} _wgpu_COMMA \ 355 | }) _wgpu_COMMA \ 356 | {{- end }} 357 | {{- range $memberIndex, $_ := .Members}} 358 | {{ StructMemberInitializer $struct $memberIndex}} 359 | {{- end}} 360 | }) 361 | {{ end}}{{"\n" -}} 362 | 363 | /** @} */ 364 | 365 | #ifdef __cplusplus 366 | extern "C" { 367 | #endif 368 | 369 | #if !defined(WGPU_SKIP_PROCS){{"\n" -}} 370 | 371 | // Global procs 372 | {{- range .Functions}} 373 | {{- MCommentProcPointer (PascalCaseName .Base) 0}} 374 | typedef {{FunctionReturns .}} (*WGPUProc{{PascalCaseName .Base}})({{FunctionArgs . nil}}) WGPU_FUNCTION_ATTRIBUTE; 375 | {{- end}} 376 | {{- if eq .Name "webgpu"}} 377 | {{- MCommentProcPointer "GetProcAddress" 0}} 378 | typedef WGPUProc (*WGPUProcGetProcAddress)(WGPUStringView procName) WGPU_FUNCTION_ATTRIBUTE; 379 | {{ end}} 380 | 381 | {{- range $object := .Objects}} 382 | 383 | // Procs of {{PascalCaseName $object.Base}} 384 | {{- range $object.Methods}} 385 | {{- MCommentProcPointer (CMethodName $object .) 0}} 386 | typedef {{FunctionReturns .}} (*WGPUProc{{CMethodName $object .}})({{FunctionArgs . $object}}) WGPU_FUNCTION_ATTRIBUTE; 387 | {{- end}} 388 | {{- end}} 389 | 390 | #endif // !defined(WGPU_SKIP_PROCS) 391 | 392 | #if !defined(WGPU_SKIP_DECLARATIONS){{"\n" -}} 393 | 394 | /** 395 | * \defgroup GlobalFunctions Global Functions 396 | * \brief Functions that are not specific to an object. 397 | * 398 | * @{ 399 | */ 400 | 401 | {{- range .Functions}} 402 | {{- MCommentFunction . 0}} 403 | WGPU_EXPORT {{FunctionReturns .}} wgpu{{PascalCaseName .Base}}({{FunctionArgs . nil}}) WGPU_FUNCTION_ATTRIBUTE; 404 | {{- end}} 405 | {{- if eq .Name "webgpu"}} 406 | /** 407 | * Returns the "procedure address" (function pointer) of the named function. 408 | * The result must be cast to the appropriate proc pointer type. 409 | */ 410 | WGPU_EXPORT WGPUProc wgpuGetProcAddress(WGPUStringView procName) WGPU_FUNCTION_ATTRIBUTE; 411 | {{- end}} 412 | 413 | /** @} */ 414 | 415 | /** 416 | * \defgroup Methods Methods 417 | * \brief Functions that are relative to a specific object. 418 | * 419 | * @{ 420 | */ 421 | 422 | {{- range $object := .Objects}} 423 | 424 | /** 425 | * \defgroup WGPU{{PascalCaseName $object.Base}}Methods WGPU{{PascalCaseName $object.Base}} methods 426 | * \brief Functions whose first argument has type WGPU{{PascalCaseName $object.Base}}. 427 | * 428 | * @{ 429 | */ 430 | {{- range $object.Methods}} 431 | {{- MCommentFunction . 0}} 432 | WGPU_EXPORT {{FunctionReturns .}} wgpu{{CMethodName $object .}}({{FunctionArgs . $object}}) WGPU_FUNCTION_ATTRIBUTE; 433 | {{- end}} 434 | 435 | /** @} */ 436 | {{- end}} 437 | 438 | /** @} */ 439 | 440 | #endif // !defined(WGPU_SKIP_DECLARATIONS) 441 | 442 | #ifdef __cplusplus 443 | } // extern "C" 444 | #endif 445 | 446 | #endif // {{.HeaderName | ConstantCase}}_H_ 447 | -------------------------------------------------------------------------------- /gen/gen.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "math" 7 | "reflect" 8 | "slices" 9 | "strconv" 10 | "strings" 11 | "text/template" 12 | ) 13 | 14 | type Generator struct { 15 | ExtPrefix string 16 | HeaderName string 17 | *Yml 18 | } 19 | 20 | func (g *Generator) Gen(dst io.Writer) error { 21 | t := template. 22 | New(""). 23 | Funcs(template.FuncMap{ 24 | "SComment": func(v string, indent int) string { return Comment(v, CommentTypeSingleLine, indent, true) }, 25 | "MComment": func(v string, indent int) string { return Comment(v, CommentTypeMultiLine, indent, true) }, 26 | "SCommentN": func(v string, indent int) string { return Comment(v, CommentTypeSingleLine, indent, false) }, 27 | "MCommentN": func(v string, indent int) string { return Comment(v, CommentTypeMultiLine, indent, false) }, 28 | "MCommentMainPage": func(v string, indent int) string { 29 | if v == "" || strings.TrimSpace(v) == "TODO" { 30 | return "" 31 | } 32 | return Comment("\\mainpage\n\n"+strings.TrimSpace(v), CommentTypeMultiLine, indent, true) 33 | }, 34 | "MCommentEnumValue": func(v string, indent int, e Enum, entryIndex int) string { 35 | var s string 36 | v = strings.TrimSpace(v) 37 | if v != "" && v != "TODO" { 38 | s += v 39 | } 40 | value, _ := g.EnumValue32(e, entryIndex) 41 | if value == 0 { 42 | s = "`0`. " + s 43 | } 44 | return Comment(strings.TrimSpace(s), CommentTypeMultiLine, indent, true) 45 | }, 46 | "MCommentBitflagType": func(v string, indent int) string { 47 | var s string 48 | v = strings.TrimSpace(v) 49 | if v != "" && v != "TODO" { 50 | s += v 51 | } 52 | s += "\n\nFor reserved non-standard bitflag values, see @ref BitflagRegistry." 53 | return Comment(strings.TrimSpace(s), CommentTypeMultiLine, indent, true) 54 | }, 55 | "MCommentBitflagValue": func(v string, indent int, b Bitflag, entryIndex int) string { 56 | value, _ := g.BitflagValue(b, entryIndex, true) 57 | s := value + "\n" 58 | v = strings.TrimSpace(v) 59 | if v != "" && v != "TODO" { 60 | s += v 61 | } 62 | return Comment(strings.TrimSpace(s), CommentTypeMultiLine, indent, true) 63 | }, 64 | "MCommentFunction": func(fn *Function, indent int) string { 65 | var s string 66 | { 67 | var funcDoc = strings.TrimSpace(fn.Doc) 68 | if funcDoc != "" && funcDoc != "TODO" { 69 | s += funcDoc 70 | } 71 | } 72 | for _, arg := range fn.Args { 73 | argDoc := strings.TrimSpace(arg.Doc) 74 | var sArg string 75 | if argDoc != "" && argDoc != "TODO" { 76 | sArg = argDoc 77 | } 78 | 79 | if arg.PassedWithOwnership != nil { 80 | if *arg.PassedWithOwnership { 81 | sArg += "\nThis parameter is @ref ReturnedWithOwnership." 82 | } else { 83 | panic("invalid") 84 | } 85 | } 86 | 87 | sArg = strings.TrimSpace(sArg) 88 | if sArg != "" { 89 | s += "\n\n@param " + CamelCase(arg.Name) + "\n" + sArg 90 | } 91 | } 92 | if fn.Returns != nil { 93 | returnsDoc := strings.TrimSpace(fn.Returns.Doc) 94 | var sRet string 95 | if returnsDoc != "" && returnsDoc != "TODO" { 96 | sRet = returnsDoc 97 | } 98 | 99 | if fn.Returns.PassedWithOwnership != nil { 100 | if *fn.Returns.PassedWithOwnership { 101 | sRet += "\nThis value is @ref ReturnedWithOwnership." 102 | } else { 103 | panic("invalid") 104 | } 105 | } 106 | 107 | sRet = strings.TrimSpace(sRet) 108 | if sRet != "" { 109 | s += "\n\n@returns\n" + sRet 110 | } 111 | } 112 | return Comment(strings.TrimSpace(s), CommentTypeMultiLine, indent, true) 113 | }, 114 | "MCommentCallback": func(cb *Callback, indent int) string { 115 | var s string 116 | { 117 | var funcDoc = strings.TrimSpace(cb.Doc) 118 | if funcDoc != "" && funcDoc != "TODO" { 119 | s += funcDoc 120 | } 121 | s += "\n\nSee also @ref CallbackError." 122 | } 123 | for _, arg := range cb.Args { 124 | var argDoc = strings.TrimSpace(arg.Doc) 125 | var sArg string 126 | if argDoc != "" && argDoc != "TODO" { 127 | sArg += argDoc 128 | } 129 | 130 | if arg.PassedWithOwnership != nil { 131 | if *arg.PassedWithOwnership { 132 | sArg += "\nThis parameter is @ref PassedWithOwnership." 133 | } else { 134 | sArg += "\nThis parameter is @ref PassedWithoutOwnership." 135 | } 136 | } 137 | 138 | sArg = strings.TrimSpace(sArg) 139 | if sArg != "" { 140 | s += "\n\n@param " + CamelCase(arg.Name) + "\n" + sArg 141 | } 142 | } 143 | return Comment(strings.TrimSpace(s), CommentTypeMultiLine, indent, true) 144 | }, 145 | "MCommentMember": func(member *ParameterType, indent int) string { 146 | var s string 147 | 148 | var srcDoc = strings.TrimSpace(member.Doc) 149 | if srcDoc != "" && srcDoc != "TODO" { 150 | s += srcDoc 151 | } 152 | 153 | switch member.Type { 154 | case "nullable_string": 155 | s += "\n\nThis is a \\ref NullableInputString." 156 | case "string_with_default_empty": 157 | s += "\n\nThis is a \\ref NonNullInputString." 158 | case "out_string": 159 | s += "\n\nThis is an \\ref OutputString." 160 | } 161 | 162 | s += "\n\nThe `INIT` macro sets this to " + g.DefaultValue(*member, true /* isDocString */) + "." 163 | 164 | if member.PassedWithOwnership != nil { 165 | panic("invalid") 166 | } 167 | 168 | return Comment(strings.TrimSpace(s), CommentTypeMultiLine, indent, true) 169 | }, 170 | "MCommentStruct": func(st *Struct, indent int) string { 171 | var s string 172 | 173 | var srcDoc = strings.TrimSpace(st.Doc) 174 | if srcDoc != "" && srcDoc != "TODO" { 175 | s += srcDoc 176 | } 177 | 178 | if st.Type == "extensible_callback_arg" { 179 | s += "\n\nThis is an @ref ImplementationAllocatedStructChain root.\nArbitrary chains must be handled gracefully by the application!" 180 | } 181 | 182 | s += "\n\nDefault values can be set using @ref WGPU_" + g.ConstantCaseName(st.Base) + "_INIT as initializer." 183 | 184 | return Comment(strings.TrimSpace(s), CommentTypeMultiLine, indent, true) 185 | }, 186 | "MCommentProcPointer": func(name string, indent int) string { 187 | var s string 188 | s += "Proc pointer type for @ref wgpu" + name + ":\n" 189 | s += "> @copydoc wgpu" + name 190 | return Comment(strings.TrimSpace(s), CommentTypeMultiLine, indent, true) 191 | }, 192 | "ConstantCase": ConstantCase, 193 | "PascalCase": PascalCase, 194 | "CamelCase": CamelCase, 195 | "ConstantCaseName": g.ConstantCaseName, 196 | "PascalCaseName": g.PascalCaseName, 197 | "CEnumName": g.CEnumName, 198 | "CMethodName": g.CMethodName, 199 | "CType": g.CType, 200 | "CValue": g.CValue, 201 | "EnumValue32": g.EnumValue32, 202 | "BitflagValue": func(b Bitflag, entryIndex int) (string, error) { 203 | return g.BitflagValue(b, entryIndex, false) 204 | }, 205 | "IsArray": func(typ string) bool { 206 | return arrayTypeRegexp.Match([]byte(typ)) 207 | }, 208 | "ArrayType": func(typ string, pointer PointerType) string { 209 | matches := arrayTypeRegexp.FindStringSubmatch(typ) 210 | if len(matches) == 2 { 211 | return g.CType(matches[1], pointer) 212 | } 213 | return "" 214 | }, 215 | "Singularize": Singularize, 216 | "IsLast": func(i int, s any) bool { return i == reflect.ValueOf(s).Len()-1 }, 217 | "FunctionReturns": g.FunctionReturns, 218 | "FunctionArgs": g.FunctionArgs, 219 | "CallbackArgs": g.CallbackArgs, 220 | "StructMember": g.StructMember, 221 | "StructMemberArrayCount": g.StructMemberArrayCount, 222 | "StructMemberArrayData": g.StructMemberArrayData, 223 | "StructMemberInitializer": g.StructMemberInitializer, 224 | }) 225 | t, err := t.Parse(tmpl) 226 | if err != nil { 227 | return fmt.Errorf("GenCHeader: failed to parse template: %w", err) 228 | } 229 | if err := t.Execute(dst, g); err != nil { 230 | return fmt.Errorf("GenCHeader: failed to execute template: %w", err) 231 | } 232 | return nil 233 | } 234 | 235 | func (g *Generator) FindBaseType(typ string) Base { 236 | // Handle type names prefixed with the type category. 237 | category, name, found := strings.Cut(typ, ".") 238 | if !found { 239 | panic("Cannot find base type for invalid type identifier: " + typ) 240 | } 241 | 242 | switch category { 243 | case "constant": 244 | idx := slices.IndexFunc(g.Constants, func(c Constant) bool { return c.Name == name }) 245 | if idx == -1 { 246 | return Base{Name: name, Namespace: g.PrefixForNamespace("")} 247 | } 248 | return g.Constants[idx].Base 249 | case "typedef": 250 | idx := slices.IndexFunc(g.Typedefs, func(t Typedef) bool { return t.Name == name }) 251 | if idx == -1 { 252 | return Base{Name: name, Namespace: g.PrefixForNamespace("")} 253 | } 254 | return g.Typedefs[idx].Base 255 | case "enum": 256 | idx := slices.IndexFunc(g.Enums, func(e Enum) bool { return e.Name == name }) 257 | if idx == -1 { 258 | return Base{Name: name, Namespace: g.PrefixForNamespace("")} 259 | } 260 | return g.Enums[idx].Base 261 | case "bitflag": 262 | idx := slices.IndexFunc(g.Bitflags, func(b Bitflag) bool { return b.Name == name }) 263 | if idx == -1 { 264 | return Base{Name: name, Namespace: g.PrefixForNamespace("")} 265 | } 266 | return g.Bitflags[idx].Base 267 | case "struct": 268 | idx := slices.IndexFunc(g.Structs, func(s Struct) bool { return s.Name == name }) 269 | if idx == -1 { 270 | return Base{Name: name, Namespace: g.PrefixForNamespace("")} 271 | } 272 | return g.Structs[idx].Base 273 | case "callback": 274 | idx := slices.IndexFunc(g.Callbacks, func(c Callback) bool { return c.Name == name }) 275 | if idx == -1 { 276 | return Base{Name: name, Namespace: g.PrefixForNamespace("")} 277 | } 278 | return g.Callbacks[idx].Base 279 | case "object": 280 | idx := slices.IndexFunc(g.Objects, func(o Object) bool { return o.Name == name }) 281 | if idx == -1 { 282 | return Base{Name: name, Namespace: g.PrefixForNamespace("")} 283 | } 284 | return g.Objects[idx].Base 285 | default: 286 | panic("Unable to find unknown category type: " + category + " for identifier: " + typ) 287 | } 288 | } 289 | 290 | func (g *Generator) ConstantCaseName(b Base) string { 291 | if b.Extended { 292 | return ConstantCase(b.Name) 293 | } 294 | 295 | prefix := g.PrefixForNamespace(b.Namespace) 296 | switch prefix { 297 | case "": 298 | return ConstantCase(b.Name) 299 | default: 300 | return ConstantCase(prefix + "_" + b.Name) 301 | } 302 | } 303 | 304 | func (g *Generator) PascalCaseName(b Base) string { 305 | if b.Extended { 306 | return PascalCase(b.Name) 307 | } 308 | 309 | prefix := g.PrefixForNamespace(b.Namespace) 310 | switch prefix { 311 | case "": 312 | return PascalCase(b.Name) 313 | default: 314 | return PascalCase(prefix + "_" + b.Name) 315 | } 316 | } 317 | 318 | func (g *Generator) CEnumName(typ Base, entry Base) string { 319 | if !typ.Extended { 320 | return g.CType(typ, "") + "_" + PascalCase(entry.Name) 321 | } else { 322 | return g.CType(typ, "") + "_" + g.PascalCaseName(entry) 323 | } 324 | } 325 | 326 | func (g *Generator) CMethodName(o Object, m Function) string { 327 | if !o.Extended { 328 | return g.PascalCaseName(o.Base) + PascalCase(m.Name) 329 | } else { 330 | return PascalCase(o.Name) + g.PascalCaseName(m.Base) 331 | } 332 | } 333 | 334 | func (g *Generator) CValue(s string) (string, error) { 335 | switch s { 336 | case "usize_max": 337 | return "SIZE_MAX", nil 338 | case "uint32_max": 339 | return "UINT32_MAX", nil 340 | case "uint64_max": 341 | return "UINT64_MAX", nil 342 | case "nan": 343 | return "NAN", nil 344 | default: 345 | var num string 346 | var base int 347 | if strings.HasPrefix(s, "0x") { 348 | base = 16 349 | num = strings.TrimPrefix(s, "0x") 350 | } else { 351 | base = 10 352 | num = s 353 | } 354 | v, err := strconv.ParseUint(num, base, 64) 355 | if err != nil { 356 | return "", fmt.Errorf("CValue: failed to parse \"%s\": %w", s, err) 357 | } 358 | var suffix string 359 | if v <= math.MaxUint32 { 360 | suffix = "UL" 361 | } else { 362 | suffix = "ULL" 363 | } 364 | return "0x" + strconv.FormatUint(v, 16) + suffix, nil 365 | } 366 | } 367 | 368 | func (g *Generator) CType(typ any, pointerType PointerType) string { 369 | appendModifiers := func(s string, pointerType PointerType) string { 370 | var sb strings.Builder 371 | sb.WriteString(s) 372 | switch pointerType { 373 | case PointerTypeImmutable: 374 | sb.WriteString(" const *") 375 | case PointerTypeMutable: 376 | sb.WriteString(" *") 377 | } 378 | return sb.String() 379 | } 380 | 381 | var ctype string 382 | switch t := typ.(type) { 383 | case string: 384 | { 385 | switch t { 386 | case "bool": 387 | ctype = "WGPUBool" 388 | case "nullable_string", "string_with_default_empty", "out_string": 389 | ctype = "WGPUStringView" 390 | case "uint16": 391 | ctype = "uint16_t" 392 | case "uint32": 393 | ctype = "uint32_t" 394 | case "uint64": 395 | ctype = "uint64_t" 396 | case "usize": 397 | ctype = "size_t" 398 | case "int16": 399 | ctype = "int16_t" 400 | case "int32": 401 | ctype = "int32_t" 402 | case "float32", "nullable_float32": 403 | ctype = "float" 404 | case "float64", "float64_supertype": 405 | ctype = "double" 406 | case "c_void": 407 | ctype = "void" 408 | default: 409 | // Handle type names prefixed with the type category. 410 | return g.CType(g.FindBaseType(t), pointerType) 411 | } 412 | } 413 | case Base: 414 | { 415 | ctype = "WGPU" + g.PascalCaseName(t) 416 | } 417 | default: 418 | panic("Unknown input for type") 419 | } 420 | 421 | return appendModifiers(ctype, pointerType) 422 | } 423 | 424 | func (g *Generator) FunctionReturns(f Function) string { 425 | if f.Callback != nil { 426 | return "WGPUFuture" 427 | } 428 | if f.Returns != nil { 429 | sb := &strings.Builder{} 430 | if f.Returns.Optional { 431 | sb.WriteString("WGPU_NULLABLE ") 432 | } 433 | sb.WriteString(g.CType(f.Returns.Type, f.Returns.Pointer)) 434 | return sb.String() 435 | } 436 | return "void" 437 | } 438 | 439 | func (g *Generator) FunctionArgs(f Function, o *Object) string { 440 | sb := &strings.Builder{} 441 | if o != nil { 442 | if len(f.Args) > 0 { 443 | fmt.Fprintf(sb, "%s %s, ", g.CType(o.Base, ""), CamelCase(o.Name)) 444 | } else { 445 | fmt.Fprintf(sb, "%s %s", g.CType(o.Base, ""), CamelCase(o.Name)) 446 | } 447 | } 448 | for i, arg := range f.Args { 449 | if arg.Optional { 450 | sb.WriteString("WGPU_NULLABLE ") 451 | } 452 | matches := arrayTypeRegexp.FindStringSubmatch(arg.Type) 453 | if len(matches) == 2 { 454 | fmt.Fprintf(sb, "size_t %sCount, ", CamelCase(Singularize(arg.Name))) 455 | fmt.Fprintf(sb, "%s %s", g.CType(matches[1], arg.Pointer), CamelCase(arg.Name)) 456 | } else { 457 | fmt.Fprintf(sb, "%s %s", g.CType(arg.Type, arg.Pointer), CamelCase(arg.Name)) 458 | } 459 | if i != len(f.Args)-1 { 460 | sb.WriteString(", ") 461 | } 462 | } 463 | if f.Callback != nil { 464 | fmt.Fprintf(sb, ", %sCallbackInfo callbackInfo", g.CType(*f.Callback, "")) 465 | } 466 | return sb.String() 467 | } 468 | 469 | func (g *Generator) CallbackArgs(f Callback) string { 470 | sb := &strings.Builder{} 471 | for _, arg := range f.Args { 472 | if arg.Optional { 473 | sb.WriteString("WGPU_NULLABLE ") 474 | } 475 | var structPrefix string 476 | if strings.HasPrefix(arg.Type, "struct.") { 477 | structPrefix = "struct " 478 | } 479 | matches := arrayTypeRegexp.FindStringSubmatch(arg.Type) 480 | if len(matches) == 2 { 481 | fmt.Fprintf(sb, "size_t %sCount, ", CamelCase(Singularize(arg.Name))) 482 | fmt.Fprintf(sb, "%s%s %s, ", structPrefix, g.CType(matches[1], arg.Pointer), CamelCase(arg.Name)) 483 | } else { 484 | fmt.Fprintf(sb, "%s%s %s, ", structPrefix, g.CType(arg.Type, arg.Pointer), CamelCase(arg.Name)) 485 | } 486 | } 487 | sb.WriteString("WGPU_NULLABLE void* userdata1, WGPU_NULLABLE void* userdata2") 488 | return sb.String() 489 | } 490 | 491 | func (g *Generator) EnumValue16(e Enum, entryIndex int) (uint16, error) { 492 | entry := e.Entries[entryIndex] 493 | if entry.Value == "" { 494 | return uint16(entryIndex), nil 495 | } else { 496 | var num string 497 | var base int 498 | if strings.HasPrefix(entry.Value, "0x") { 499 | base = 16 500 | num = strings.TrimPrefix(entry.Value, "0x") 501 | } else { 502 | base = 10 503 | num = entry.Value 504 | } 505 | value, err := strconv.ParseUint(num, base, 16) 506 | if err != nil { 507 | return 0, err 508 | } 509 | return uint16(value), nil 510 | } 511 | } 512 | 513 | func (g *Generator) EnumValue32(e Enum, entryIndex int) (uint32, error) { 514 | value16, err := g.EnumValue16(e, entryIndex) 515 | if err != nil { 516 | return 0, err 517 | } 518 | return uint32(g.EnumPrefix)<<16 | uint32(value16), nil 519 | } 520 | 521 | func bitflagEntryValue(entry BitflagEntry, entryIndex int) (uint64, error) { 522 | if entry.Value == "" { 523 | value := uint64(math.Pow(2, float64(entryIndex-1))) 524 | return value, nil 525 | } else { 526 | var num string 527 | var base int 528 | if strings.HasPrefix(entry.Value, "0x") { 529 | base = 16 530 | num = strings.TrimPrefix(entry.Value, "0x") 531 | } else { 532 | base = 10 533 | num = entry.Value 534 | } 535 | return strconv.ParseUint(num, base, 64) 536 | } 537 | } 538 | 539 | func (g *Generator) BitflagValue(b Bitflag, entryIndex int, isDocString bool) (string, error) { 540 | entry := b.Entries[entryIndex] 541 | 542 | var value uint64 543 | var entryComment string 544 | if len(entry.ValueCombination) > 0 { 545 | if entry.Value != "" { 546 | return "", fmt.Errorf("BitflagValue: found conflicting 'value' and 'value_combination' in '%s'", b.Name) 547 | } 548 | entryComment += "`" 549 | for valueIndex, v := range entry.ValueCombination { 550 | // find the value by searching in b, bitwise-OR it into the result 551 | for searchIndex, search := range b.Entries { 552 | if search.Name == v { 553 | searchValue, err := bitflagEntryValue(search, searchIndex) 554 | if err != nil { 555 | return "", nil 556 | } 557 | value |= searchValue 558 | break 559 | } 560 | } 561 | // construct comment 562 | idx := slices.IndexFunc(b.Entries, func(e BitflagEntry) bool { return e.Name == v }) 563 | if idx != -1 { 564 | entryComment += g.PascalCaseName(b.Entries[idx].Base) 565 | } else { 566 | entryComment += PascalCase(v) 567 | } 568 | if valueIndex != len(entry.ValueCombination)-1 { 569 | entryComment += " | " 570 | } 571 | } 572 | entryComment += "`." 573 | } else { 574 | var err error 575 | value, err = bitflagEntryValue(entry, entryIndex) 576 | if err != nil { 577 | return "", nil 578 | } 579 | if value == 0 { 580 | entryComment = "`0`." 581 | } 582 | } 583 | if isDocString { 584 | return entryComment, nil 585 | } else { 586 | return fmt.Sprintf("0x%.16X", value), nil 587 | } 588 | } 589 | 590 | func (g *Generator) PrefixForNamespace(namespace string) string { 591 | switch namespace { 592 | case "": 593 | return g.ExtPrefix 594 | case "webgpu": 595 | return "" 596 | default: 597 | return namespace 598 | } 599 | } 600 | 601 | func (g *Generator) StructMember(s Struct, memberIndex int) (string, error) { 602 | member := s.Members[memberIndex] 603 | 604 | matches := arrayTypeRegexp.FindStringSubmatch(member.Type) 605 | if len(matches) == 2 { 606 | panic("StructMember used on array type") 607 | } 608 | 609 | sb := &strings.Builder{} 610 | if member.Optional { 611 | sb.WriteString("WGPU_NULLABLE ") 612 | } 613 | if strings.HasPrefix(member.Type, "callback.") { 614 | fmt.Fprintf(sb, "%sCallbackInfo %s;", g.CType(member.Type, ""), CamelCase(member.Name)) 615 | } else { 616 | fmt.Fprintf(sb, "%s %s;", g.CType(member.Type, member.Pointer), CamelCase(member.Name)) 617 | } 618 | return sb.String(), nil 619 | } 620 | 621 | func (g *Generator) StructMemberArrayCount(s Struct, memberIndex int) (string, error) { 622 | member := s.Members[memberIndex] 623 | 624 | matches := arrayTypeRegexp.FindStringSubmatch(member.Type) 625 | if len(matches) != 2 { 626 | panic("StructMemberArrayCount used on non-array") 627 | } 628 | 629 | return fmt.Sprintf("size_t %sCount;", CamelCase(Singularize(member.Name))), nil 630 | } 631 | 632 | func (g *Generator) StructMemberArrayData(s Struct, memberIndex int) (string, error) { 633 | member := s.Members[memberIndex] 634 | 635 | matches := arrayTypeRegexp.FindStringSubmatch(member.Type) 636 | if len(matches) != 2 { 637 | panic("StructMemberArrayCount used on non-array") 638 | } 639 | 640 | sb := &strings.Builder{} 641 | if member.Optional { 642 | sb.WriteString("WGPU_NULLABLE ") 643 | } 644 | fmt.Fprintf(sb, "%s %s;", g.CType(matches[1], member.Pointer), CamelCase(member.Name)) 645 | return sb.String(), nil 646 | } 647 | 648 | func (g *Generator) StructMemberInitializer(s Struct, memberIndex int) (string, error) { 649 | member := s.Members[memberIndex] 650 | sb := &strings.Builder{} 651 | matches := arrayTypeRegexp.FindStringSubmatch(member.Type) 652 | if len(matches) == 2 { 653 | fmt.Fprintf(sb, "/*.%sCount=*/0 _wgpu_COMMA \\\n", CamelCase(Singularize(member.Name))) 654 | fmt.Fprintf(sb, " /*.%s=*/NULL _wgpu_COMMA \\", CamelCase(member.Name)) 655 | } else { 656 | fmt.Fprintf(sb, "/*.%s=*/%s _wgpu_COMMA \\", CamelCase(member.Name), g.DefaultValue(member, false /* isDocString */)) 657 | } 658 | return sb.String(), nil 659 | } 660 | 661 | func (g *Generator) DefaultValue(member ParameterType, isDocString bool) string { 662 | ref := func(s string) string { 663 | if isDocString { 664 | return "@ref " + s 665 | } else { 666 | return s 667 | } 668 | } 669 | literal := func(s string) string { 670 | if isDocString { 671 | return "`" + s + "`" 672 | } else { 673 | return s 674 | } 675 | } 676 | 677 | switch { 678 | case member.Pointer != "": 679 | if member.Default != nil { 680 | panic("pointer type should not have a default") 681 | } 682 | return literal("NULL") 683 | 684 | // Cases that may have member.Default 685 | case strings.HasPrefix(member.Type, "enum."): 686 | if member.Default == nil { 687 | if member.Type == "enum.optional_bool" { 688 | // This Undefined is a special one that is not the zero-value, so that 689 | // a stdbool.h bool cast correctly to WGPUOptionalBool; this means we 690 | // must explicitly initialize it 691 | return ref("WGPUOptionalBool_Undefined") 692 | } else if isDocString { 693 | return "(@ref " + g.CType(member.Type, "") + ")0" 694 | } else { 695 | return "_wgpu_ENUM_ZERO_INIT(" + g.CType(member.Type, "") + ")" 696 | } 697 | } else { 698 | return ref(g.CType(member.Type, "") + "_" + PascalCase(*member.Default)) 699 | } 700 | case strings.HasPrefix(member.Type, "bitflag."): 701 | if member.Default == nil { 702 | return ref(g.CType(member.Type, "") + "_None") 703 | } else { 704 | return ref(g.CType(member.Type, "") + "_" + PascalCase(*member.Default)) 705 | } 706 | case member.Type == "uint16", member.Type == "uint32", member.Type == "uint64", member.Type == "usize", member.Type == "int32": 707 | if member.Default == nil { 708 | return literal("0") 709 | } else if strings.HasPrefix(*member.Default, "constant.") { 710 | return ref("WGPU_" + g.ConstantCaseName(g.FindBaseType(*member.Default))) 711 | } else { 712 | return literal(*member.Default) 713 | } 714 | case member.Type == "float32" || member.Type == "nullable_float32": 715 | if member.Default == nil { 716 | return literal("0.f") 717 | } else if strings.HasPrefix(*member.Default, "constant.") { 718 | return ref("WGPU_" + g.ConstantCaseName(g.FindBaseType(*member.Default))) 719 | } else if strings.Contains(*member.Default, ".") { 720 | return literal(*member.Default + "f") 721 | } else { 722 | return literal(*member.Default + ".f") 723 | } 724 | case member.Type == "float64" || member.Type == "float64_supertype": 725 | if member.Default == nil { 726 | return literal("0.") 727 | } else if strings.HasPrefix(*member.Default, "constant.") { 728 | return ref("WGPU_" + g.ConstantCaseName(g.FindBaseType(*member.Default))) 729 | } else { 730 | return literal(*member.Default) 731 | } 732 | case member.Type == "bool": 733 | if member.Default == nil { 734 | return literal("WGPU_FALSE") 735 | } else if strings.HasPrefix(*member.Default, "constant.") { 736 | return ref("WGPU_" + g.ConstantCaseName(g.FindBaseType(*member.Default))) 737 | } else if *member.Default == "true" { 738 | return literal("WGPU_TRUE") 739 | } else if *member.Default == "false" { 740 | return literal("WGPU_FALSE") 741 | } else { 742 | return *member.Default 743 | } 744 | case strings.HasPrefix(member.Type, "struct."): 745 | if member.Optional { 746 | return literal("NULL") 747 | } else if member.Default == nil { 748 | return ref("WGPU_" + g.ConstantCaseName(g.FindBaseType(member.Type)) + "_INIT") 749 | } else if *member.Default == "zero" { 750 | if isDocString { 751 | return "zero (which sets the entry to `BindingNotUsed`)" 752 | } else { 753 | return literal("_wgpu_STRUCT_ZERO_INIT") 754 | } 755 | } else { 756 | panic("unknown default for struct type") 757 | } 758 | case member.Default != nil: 759 | panic(fmt.Errorf("type %s should not have a default", member.Type)) 760 | 761 | // Cases that should not have member.Default 762 | case strings.HasPrefix(member.Type, "callback."): 763 | return ref("WGPU_" + g.ConstantCaseName(g.FindBaseType(member.Type)) + "_CALLBACK_INFO_INIT") 764 | case strings.HasPrefix(member.Type, "object."): 765 | return literal("NULL") 766 | case strings.HasPrefix(member.Type, "array<"): 767 | return literal("NULL") 768 | case member.Type == "out_string", member.Type == "string_with_default_empty", member.Type == "nullable_string": 769 | return ref("WGPU_STRING_VIEW_INIT") 770 | case member.Type == "c_void": 771 | return literal("NULL") 772 | default: 773 | panic("invalid prefix: " + member.Type + " in member " + member.Name) 774 | } 775 | } 776 | -------------------------------------------------------------------------------- /gen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "os" 6 | "path/filepath" 7 | "slices" 8 | "strings" 9 | 10 | _ "embed" 11 | 12 | "github.com/goccy/go-yaml" 13 | ) 14 | 15 | //go:embed cheader.tmpl 16 | var tmpl string 17 | 18 | var ( 19 | schemaPath string 20 | headerPaths StringListFlag 21 | yamlPaths StringListFlag 22 | extPrefix bool 23 | ) 24 | 25 | func main() { 26 | flag.StringVar(&schemaPath, "schema", "", "path of the json schema") 27 | flag.Var(&yamlPaths, "yaml", "path of the yaml spec") 28 | flag.Var(&headerPaths, "header", "output path of the header") 29 | flag.BoolVar(&extPrefix, "extprefix", true, "append prefix to extension identifiers") 30 | flag.Parse() 31 | if schemaPath == "" || len(headerPaths) == 0 || len(yamlPaths) == 0 || len(headerPaths) != len(yamlPaths) { 32 | flag.Usage() 33 | os.Exit(1) 34 | } 35 | 36 | // Order matters for validation steps, so enforce it. 37 | if len(yamlPaths) > 1 && filepath.Base(yamlPaths[0]) != "webgpu.yml" { 38 | panic(`"webgpu.yml" must be the first sequence in the order`) 39 | } 40 | 41 | // Validate the yaml files (jsonschema, duplications) 42 | if err := ValidateYamls(schemaPath, yamlPaths); err != nil { 43 | panic(err) 44 | } 45 | 46 | // Generate the header files 47 | for i, yamlPath := range yamlPaths { 48 | headerPath := headerPaths[i] 49 | headerFileName := filepath.Base(headerPath) 50 | headerFileNameSplit := strings.Split(headerFileName, ".") 51 | if len(headerFileNameSplit) != 2 { 52 | panic("got invalid header file name: " + headerFileName) 53 | } 54 | 55 | src, err := os.ReadFile(yamlPath) 56 | if err != nil { 57 | panic(err) 58 | } 59 | 60 | dst, err := os.Create(headerPath) 61 | if err != nil { 62 | panic(err) 63 | } 64 | 65 | var yml Yml 66 | if err := yaml.Unmarshal(src, &yml); err != nil { 67 | panic(err) 68 | } 69 | 70 | SortAndTransform(&yml) 71 | 72 | prefix := "" 73 | if yml.Name != "webgpu" && extPrefix { 74 | prefix = yml.Name 75 | } 76 | g := &Generator{ 77 | Yml: &yml, 78 | HeaderName: headerFileNameSplit[0], 79 | ExtPrefix: prefix, 80 | } 81 | if err := g.Gen(dst); err != nil { 82 | panic(err) 83 | } 84 | } 85 | } 86 | 87 | func UpperConcatCase(s string) string { 88 | return strings.ToUpper(PascalCase(s)) 89 | } 90 | 91 | func SortAndTransform(yml *Yml) { 92 | // Sort structs 93 | SortStructs(yml.Structs) 94 | 95 | // Sort constants 96 | slices.SortStableFunc(yml.Constants, func(a, b Constant) int { 97 | return strings.Compare(UpperConcatCase(a.Name), UpperConcatCase(b.Name)) 98 | }) 99 | 100 | // Sort enums 101 | slices.SortStableFunc(yml.Enums, func(a, b Enum) int { 102 | // We want to generate extended enum declarations before the normal ones. 103 | if a.Extended && !b.Extended { 104 | return -1 105 | } else if !a.Extended && b.Extended { 106 | return 1 107 | } 108 | return strings.Compare(UpperConcatCase(a.Name), UpperConcatCase(b.Name)) 109 | }) 110 | 111 | // Sort bitflags 112 | slices.SortStableFunc(yml.Bitflags, func(a, b Bitflag) int { 113 | // We want to generate extended bitflag declarations before the normal ones. 114 | if a.Extended && !b.Extended { 115 | return -1 116 | } else if !a.Extended && b.Extended { 117 | return 1 118 | } 119 | return strings.Compare(UpperConcatCase(a.Name), UpperConcatCase(b.Name)) 120 | }) 121 | 122 | // Add free_member function for relevant structs 123 | for _, s := range yml.Structs { 124 | if s.FreeMembers { 125 | yml.Objects = append(yml.Objects, Object{ 126 | Base: Base{Name: s.Name, Namespace: s.Namespace}, 127 | IsStruct: true, 128 | Methods: []Function{{ 129 | Base: Base{ 130 | Name: "free_members", 131 | Namespace: s.Namespace, 132 | Doc: "Frees members which were allocated by the API."}, 133 | }}, 134 | }) 135 | } 136 | } 137 | 138 | // Sort objects 139 | slices.SortStableFunc(yml.Objects, func(a, b Object) int { 140 | return strings.Compare(UpperConcatCase(a.Name), UpperConcatCase(b.Name)) 141 | }) 142 | 143 | // Sort methods 144 | for _, obj := range yml.Objects { 145 | slices.SortStableFunc(obj.Methods, func(a, b Function) int { 146 | return strings.Compare(UpperConcatCase(a.Name), UpperConcatCase(b.Name)) 147 | }) 148 | } 149 | 150 | // Add add_ref and release methods for objects 151 | for i, o := range yml.Objects { 152 | if !o.Extended && !o.IsStruct { 153 | yml.Objects[i].Methods = append(yml.Objects[i].Methods, 154 | Function{ 155 | Base: Base{ 156 | Name: "add_ref", 157 | Namespace: o.Namespace, 158 | Doc: "TODO", 159 | }, 160 | }, 161 | Function{ 162 | Base: Base{ 163 | Name: "release", 164 | Namespace: o.Namespace, 165 | Doc: "TODO", 166 | }, 167 | }) 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /gen/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "strings" 8 | "unicode" 9 | ) 10 | 11 | type StringListFlag []string 12 | 13 | var StringListFlagI flag.Value = &StringListFlag{} 14 | 15 | func (f *StringListFlag) String() string { return fmt.Sprintf("%#v", f) } 16 | func (f *StringListFlag) Set(v string) error { *f = append(*f, v); return nil } 17 | 18 | type CommentType uint8 19 | 20 | const ( 21 | CommentTypeSingleLine CommentType = iota 22 | CommentTypeMultiLine 23 | ) 24 | 25 | func Comment(in string, mode CommentType, indent int, newline bool) string { 26 | if in == "" || strings.TrimSpace(in) == "TODO" { 27 | return "" 28 | } 29 | 30 | const space = ' ' 31 | var out strings.Builder 32 | if newline { 33 | out.WriteString("\n") 34 | } 35 | if mode == CommentTypeMultiLine { 36 | for i := 0; i < indent; i++ { 37 | out.WriteRune(space) 38 | } 39 | out.WriteString("/**\n") 40 | } 41 | sc := bufio.NewScanner(strings.NewReader(strings.TrimSpace(in))) 42 | for sc.Scan() { 43 | line := sc.Text() 44 | for i := 0; i < indent; i++ { 45 | out.WriteRune(space) 46 | } 47 | switch mode { 48 | case CommentTypeSingleLine: 49 | out.WriteString("//") 50 | case CommentTypeMultiLine: 51 | out.WriteString(" *") 52 | default: 53 | panic("unreachable") 54 | } 55 | if line != "" { 56 | out.WriteString(" ") 57 | out.WriteString(line) 58 | } 59 | out.WriteString("\n") 60 | } 61 | if mode == CommentTypeMultiLine { 62 | for i := 0; i < indent; i++ { 63 | out.WriteRune(space) 64 | } 65 | out.WriteString(" */") 66 | } 67 | return out.String() 68 | } 69 | 70 | func ConstantCase(v string) string { 71 | return strings.ToUpper(v) 72 | } 73 | 74 | func PascalCase(s string) string { 75 | var out strings.Builder 76 | out.Grow(len(s)) 77 | nextUpper := true 78 | for _, c := range s { 79 | if nextUpper { 80 | out.WriteRune(unicode.ToUpper(c)) 81 | nextUpper = false 82 | } else { 83 | if c == '_' { 84 | nextUpper = true 85 | } else { 86 | out.WriteRune(c) 87 | } 88 | } 89 | } 90 | return out.String() 91 | } 92 | 93 | func CamelCase(s string) string { 94 | var out strings.Builder 95 | out.Grow(len(s)) 96 | nextUpper := false 97 | for _, c := range s { 98 | if nextUpper { 99 | out.WriteRune(unicode.ToUpper(c)) 100 | nextUpper = false 101 | } else { 102 | if c == '_' { 103 | nextUpper = true 104 | } else { 105 | out.WriteRune(c) 106 | } 107 | } 108 | } 109 | return out.String() 110 | } 111 | 112 | func Singularize(s string) string { 113 | switch s { 114 | case "entries": 115 | return "entry" 116 | default: 117 | return strings.TrimSuffix(s, "s") 118 | } 119 | } 120 | 121 | func TrimTypePrefix(s string) string { 122 | switch { 123 | case strings.HasPrefix(s, "enum."): 124 | return strings.TrimPrefix(s, "enum.") 125 | case strings.HasPrefix(s, "bitflag."): 126 | return strings.TrimPrefix(s, "bitflag.") 127 | case strings.HasPrefix(s, "struct."): 128 | return strings.TrimPrefix(s, "struct.") 129 | case strings.HasPrefix(s, "callback."): 130 | return strings.TrimPrefix(s, "callback.") 131 | case strings.HasPrefix(s, "object."): 132 | return strings.TrimPrefix(s, "object.") 133 | default: 134 | return "" 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /gen/validator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "slices" 8 | 9 | "github.com/goccy/go-yaml" 10 | "github.com/santhosh-tekuri/jsonschema/v5" 11 | _ "github.com/santhosh-tekuri/jsonschema/v5/httploader" 12 | ) 13 | 14 | func ValidateYamls(schemaPath string, yamlPaths []string) error { 15 | // Validation through json schema 16 | for _, yamlPath := range yamlPaths { 17 | yamlFile, err := os.ReadFile(yamlPath) 18 | if err != nil { 19 | return fmt.Errorf("ValidateYaml: %w", err) 20 | } 21 | var yml map[string]any 22 | if err := yaml.Unmarshal(yamlFile, &yml); err != nil { 23 | return fmt.Errorf("ValidateYaml: %w", err) 24 | } 25 | 26 | schema := jsonschema.MustCompile(schemaPath) 27 | if err := schema.Validate(yml); err != nil { 28 | return fmt.Errorf("ValidateYaml: %w", err) 29 | } 30 | } 31 | 32 | // Validation of possible duplication of entries across multiple yaml files 33 | if err := mergeAndValidateDuplicates(yamlPaths); err != nil { 34 | panic(err) 35 | } 36 | 37 | // TODO: add dependency check validations 38 | return nil 39 | } 40 | 41 | func mergeAndValidateDuplicates(yamlPaths []string) (errs error) { 42 | constants := make(map[string]Constant) 43 | enums := make(map[string]Enum) 44 | bitflags := make(map[string]Bitflag) 45 | structs := make(map[string]Struct) 46 | callbacks := make(map[string]Callback) 47 | functions := make(map[string]Function) 48 | objects := make(map[string]Object) 49 | 50 | for _, yamlPath := range yamlPaths { 51 | src, err := os.ReadFile(yamlPath) 52 | if err != nil { 53 | panic(err) 54 | } 55 | 56 | var data Yml 57 | if err := yaml.Unmarshal(src, &data); err != nil { 58 | panic(err) 59 | } 60 | 61 | for _, c := range data.Constants { 62 | if _, ok := constants[c.Name]; ok { 63 | errs = errors.Join(errs, fmt.Errorf("merge: constants.%s in %s was already found previously while parsing, duplicates are not allowed", c.Name, yamlPath)) 64 | } 65 | constants[c.Name] = c 66 | } 67 | for _, e := range data.Enums { 68 | if prevEnum, ok := enums[e.Name]; ok { 69 | if !e.Extended { 70 | errs = errors.Join(errs, fmt.Errorf("merge: enums.%s in %s is being extended but isn't marked as one", e.Name, yamlPath)) 71 | } 72 | for _, entry := range e.Entries { 73 | if entry != nil { 74 | if slices.ContainsFunc(prevEnum.Entries, func(e *EnumEntry) bool { return e != nil && e.Name == entry.Name }) { 75 | errs = errors.Join(errs, fmt.Errorf("merge: enums.%s.%s in %s was already found previously while parsing, duplicates are not allowed", e.Name, entry.Name, yamlPath)) 76 | } 77 | prevEnum.Entries = append(prevEnum.Entries, entry) 78 | } 79 | } 80 | enums[e.Name] = prevEnum 81 | } else { 82 | enums[e.Name] = e 83 | } 84 | } 85 | for _, bf := range data.Bitflags { 86 | if prevBf, ok := bitflags[bf.Name]; ok { 87 | if !bf.Extended { 88 | errs = errors.Join(errs, fmt.Errorf("merge: bitflags.%s in %s is being extended but isn't marked as one", bf.Name, yamlPath)) 89 | } 90 | for _, entry := range bf.Entries { 91 | if slices.ContainsFunc(prevBf.Entries, func(e BitflagEntry) bool { return e.Name == entry.Name }) { 92 | errs = errors.Join(errs, fmt.Errorf("merge: bitflags.%s.%s in %s was already found previously while parsing, duplicates are not allowed", bf.Name, entry.Name, yamlPath)) 93 | } 94 | if entry.Value == "" && len(entry.ValueCombination) == 0 { 95 | errs = errors.Join(errs, fmt.Errorf("merge: bitflags.%s.%s in %s was extended but doesn't have a value or value_combination, extended bitflag entries must have an explicit value", bf.Name, entry.Name, yamlPath)) 96 | } 97 | prevBf.Entries = append(prevBf.Entries, entry) 98 | } 99 | bitflags[bf.Name] = prevBf 100 | } else { 101 | bitflags[bf.Name] = bf 102 | } 103 | } 104 | for _, c := range data.Callbacks { 105 | if _, ok := callbacks[c.Name]; ok { 106 | errs = errors.Join(errs, fmt.Errorf("merge: callbacks.%s in %s was already found previously while parsing, duplicates are not allowed", c.Name, yamlPath)) 107 | } 108 | callbacks[c.Name] = c 109 | } 110 | for _, s := range data.Structs { 111 | if _, ok := structs[s.Name]; ok { 112 | errs = errors.Join(errs, fmt.Errorf("merge: structs.%s in %s was already found previously while parsing, duplicates are not allowed", s.Name, yamlPath)) 113 | } 114 | structs[s.Name] = s 115 | } 116 | for _, f := range data.Functions { 117 | if _, ok := functions[f.Name]; ok { 118 | errs = errors.Join(errs, fmt.Errorf("merge: functions.%s in %s was already found previously while parsing, duplicates are not allowed", f.Name, yamlPath)) 119 | } 120 | functions[f.Name] = f 121 | } 122 | for _, o := range data.Objects { 123 | if prevObj, ok := objects[o.Name]; ok { 124 | if !o.Extended { 125 | errs = errors.Join(errs, fmt.Errorf("merge: objects.%s in %s is being extended but isn't marked as one", o.Name, yamlPath)) 126 | } 127 | for _, method := range o.Methods { 128 | if slices.ContainsFunc(prevObj.Methods, func(f Function) bool { return f.Name == method.Name }) { 129 | errs = errors.Join(errs, fmt.Errorf("merge: objects.%s.%s in %s was already found previously while parsing, duplicates are not allowed", o.Name, method.Name, yamlPath)) 130 | } 131 | prevObj.Methods = append(prevObj.Methods, method) 132 | } 133 | objects[o.Name] = prevObj 134 | } else { 135 | objects[o.Name] = o 136 | } 137 | } 138 | } 139 | return 140 | } 141 | -------------------------------------------------------------------------------- /gen/yml.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | "regexp" 6 | "slices" 7 | "strings" 8 | ) 9 | 10 | type Yml struct { 11 | Copyright string `yaml:"copyright"` 12 | Name string `yaml:"name"` 13 | Doc string `yaml:"doc"` 14 | EnumPrefix uint16 `yaml:"enum_prefix"` 15 | 16 | Constants []Constant `yaml:"constants"` 17 | Typedefs []Typedef `yaml:"typedefs"` 18 | Enums []Enum `yaml:"enums"` 19 | Bitflags []Bitflag `yaml:"bitflags"` 20 | Structs []Struct `yaml:"structs"` 21 | Callbacks []Callback `yaml:"callbacks"` 22 | Functions []Function `yaml:"functions"` 23 | Objects []Object `yaml:"objects"` 24 | } 25 | 26 | type Base struct { 27 | Name string `yaml:"name"` 28 | Namespace string `yaml:"namespace"` 29 | Doc string `yaml:"doc"` 30 | Extended bool `yaml:"extended"` 31 | } 32 | 33 | type Constant struct { 34 | Base `yaml:",inline"` 35 | Value string `yaml:"value"` 36 | } 37 | 38 | type Typedef struct { 39 | Base `yaml:",inline"` 40 | Type string `yaml:"type"` 41 | } 42 | 43 | type Enum struct { 44 | Base `yaml:",inline"` 45 | Entries []*EnumEntry `yaml:"entries"` 46 | } 47 | type EnumEntry struct { 48 | Base `yaml:",inline"` 49 | Value string `yaml:"value"` 50 | } 51 | 52 | type Bitflag struct { 53 | Base `yaml:",inline"` 54 | Entries []BitflagEntry `yaml:"entries"` 55 | } 56 | type BitflagEntry struct { 57 | Base `yaml:",inline"` 58 | Value string `yaml:"value"` 59 | ValueCombination []string `yaml:"value_combination"` 60 | } 61 | 62 | type PointerType string 63 | 64 | const ( 65 | PointerTypeMutable PointerType = "mutable" 66 | PointerTypeImmutable PointerType = "immutable" 67 | ) 68 | 69 | type ParameterType struct { 70 | Name string `yaml:"name"` 71 | Namespace string `yaml:"namespace"` 72 | Doc string `yaml:"doc"` 73 | Type string `yaml:"type"` 74 | PassedWithOwnership *bool `yaml:"passed_with_ownership"` 75 | Pointer PointerType `yaml:"pointer"` 76 | Optional bool `yaml:"optional"` 77 | Default *string `yaml:"default"` 78 | } 79 | 80 | type Callback struct { 81 | Base `yaml:",inline"` 82 | Style string `yaml:"style"` 83 | Args []ParameterType `yaml:"args"` 84 | } 85 | 86 | type Function struct { 87 | Base `yaml:",inline"` 88 | Returns *ParameterType `yaml:"returns"` 89 | Callback *string `yaml:"callback"` 90 | Args []ParameterType `yaml:"args"` 91 | } 92 | 93 | type Struct struct { 94 | Base `yaml:",inline"` 95 | Type string `yaml:"type"` 96 | FreeMembers bool `yaml:"free_members"` 97 | Members []ParameterType `yaml:"members"` 98 | Extends []string `yaml:"extends"` 99 | } 100 | 101 | type Object struct { 102 | Base `yaml:",inline"` 103 | Methods []Function `yaml:"methods"` 104 | 105 | IsStruct bool `yaml:"-"` 106 | } 107 | 108 | var arrayTypeRegexp = regexp.MustCompile(`array<([a-zA-Z0-9._]+)>`) 109 | 110 | func SortStructs(structs []Struct) { 111 | type node struct { 112 | visited bool 113 | depth int 114 | Extensions []string 115 | Struct 116 | } 117 | nodeMap := make(map[string]node, len(structs)) 118 | for _, s := range structs { 119 | node := nodeMap[s.Name] 120 | node.Struct = s 121 | nodeMap[s.Name] = node 122 | if s.Type == "extension" { 123 | for _, extend := range s.Extends { 124 | parent := nodeMap[extend] 125 | parent.Extensions = append(parent.Extensions, s.Name) 126 | nodeMap[extend] = parent 127 | } 128 | } 129 | } 130 | 131 | slices.SortStableFunc(structs, func(a, b Struct) int { 132 | return strings.Compare(PascalCase(a.Name), PascalCase(b.Name)) 133 | }) 134 | 135 | var computeDepth func(string) int 136 | computeDepth = func(name string) int { 137 | node, ok := nodeMap[name] 138 | if !ok { 139 | panic("found invalid non-existing type: " + name) 140 | } 141 | 142 | if node.visited { 143 | return node.depth 144 | } 145 | 146 | maxDependentDepth := 0 147 | for _, member := range node.Members { 148 | if strings.HasPrefix(member.Type, "struct.") { 149 | dependentDepth := computeDepth(strings.TrimPrefix(member.Type, "struct.")) 150 | maxDependentDepth = int(math.Max(float64(maxDependentDepth), float64(dependentDepth+1))) 151 | } else { 152 | matches := arrayTypeRegexp.FindStringSubmatch(member.Type) 153 | if len(matches) == 2 { 154 | typ := matches[1] 155 | if strings.HasPrefix(typ, "struct.") { 156 | dependentDepth := computeDepth(strings.TrimPrefix(typ, "struct.")) 157 | maxDependentDepth = int(math.Max(float64(maxDependentDepth), float64(dependentDepth+1))) 158 | } 159 | } 160 | } 161 | } 162 | for _, extension := range node.Extensions { 163 | dependentDepth := computeDepth(extension) 164 | maxDependentDepth = int(math.Max(float64(maxDependentDepth), float64(dependentDepth+1))) 165 | } 166 | 167 | node.depth = maxDependentDepth 168 | node.visited = true 169 | nodeMap[name] = node 170 | return maxDependentDepth 171 | } 172 | 173 | for _, s := range structs { 174 | computeDepth(s.Name) 175 | } 176 | slices.SortStableFunc(structs, func(a, b Struct) int { 177 | return nodeMap[a.Name].depth - nodeMap[b.Name].depth 178 | }) 179 | } 180 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/webgpu-native/webgpu-headers 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/goccy/go-yaml v1.11.3 7 | github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 8 | ) 9 | 10 | require ( 11 | github.com/a8m/envsubst v1.4.2 // indirect 12 | github.com/alecthomas/participle/v2 v2.1.1 // indirect 13 | github.com/dimchansky/utfbom v1.1.1 // indirect 14 | github.com/elliotchance/orderedmap v1.6.0 // indirect 15 | github.com/fatih/color v1.17.0 // indirect 16 | github.com/goccy/go-json v0.10.3 // indirect 17 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 18 | github.com/jinzhu/copier v0.4.0 // indirect 19 | github.com/magiconair/properties v1.8.7 // indirect 20 | github.com/mattn/go-colorable v0.1.13 // indirect 21 | github.com/mattn/go-isatty v0.0.20 // indirect 22 | github.com/mikefarah/yq/v4 v4.44.2 // indirect 23 | github.com/pelletier/go-toml/v2 v2.2.2 // indirect 24 | github.com/spf13/cobra v1.8.0 // indirect 25 | github.com/spf13/pflag v1.0.5 // indirect 26 | github.com/yuin/gopher-lua v1.1.1 // indirect 27 | golang.org/x/net v0.26.0 // indirect 28 | golang.org/x/sys v0.21.0 // indirect 29 | golang.org/x/text v0.16.0 // indirect 30 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 31 | gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect 32 | gopkg.in/yaml.v3 v3.0.1 // indirect 33 | ) 34 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg= 2 | github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= 3 | github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= 4 | github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= 5 | github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= 9 | github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= 10 | github.com/elliotchance/orderedmap v1.6.0 h1:xjn+kbbKXeDq6v9RVE+WYwRbYfAZKvlWfcJNxM8pvEw= 11 | github.com/elliotchance/orderedmap v1.6.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= 12 | github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= 13 | github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 14 | github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= 15 | github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= 16 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 17 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 18 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 19 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 20 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= 21 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 22 | github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= 23 | github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= 24 | github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ= 25 | github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= 26 | github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= 27 | github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= 28 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 29 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 30 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 31 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 32 | github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= 33 | github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= 34 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 35 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 36 | github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= 37 | github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 38 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= 39 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 40 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 41 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 42 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 43 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 44 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 45 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 46 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 47 | github.com/mikefarah/yq/v4 v4.44.2 h1:J+ezWCDTg+SUs0jXdcE0HIPH1+rEr0Tbn9Y1SwiWtH0= 48 | github.com/mikefarah/yq/v4 v4.44.2/go.mod h1:9bnz36uZJDEyxdIjRronBcqStS953k3y3DrSRXr4F/w= 49 | github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= 50 | github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= 51 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 52 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 53 | github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= 54 | github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= 55 | github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= 56 | github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 57 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 58 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 59 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 60 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 61 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 62 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 63 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 64 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 65 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 66 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 67 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 68 | github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= 69 | github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= 70 | golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= 71 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 72 | golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= 73 | golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= 74 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 75 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 76 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 77 | golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= 78 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 79 | golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= 80 | golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 81 | golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= 82 | golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 83 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 84 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 85 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= 86 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= 87 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 88 | gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE= 89 | gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= 90 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 91 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 92 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 93 | -------------------------------------------------------------------------------- /schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft-07/schema", 3 | "type": "object", 4 | "additionalProperties": false, 5 | "definitions": { 6 | "Name": { 7 | "type": "string", 8 | "pattern": "^[a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?$" 9 | }, 10 | "Value64": { 11 | "oneOf": [ 12 | { 13 | "type": "integer", 14 | "minimum": 0, 15 | "maximum": 18446744073709551615 16 | }, 17 | { 18 | "type": "string", 19 | "enum": [ 20 | "usize_max", 21 | "uint32_max", 22 | "uint64_max", 23 | "nan" 24 | ] 25 | } 26 | ] 27 | }, 28 | "Value16": { 29 | "type": "integer", 30 | "minimum": 0, 31 | "maximum": 65535 32 | }, 33 | "PrimitiveType": { 34 | "type": "string", 35 | "enum": [ 36 | "c_void", 37 | "bool", 38 | "nullable_string", 39 | "string_with_default_empty", 40 | "out_string", 41 | "uint16", 42 | "uint32", 43 | "uint64", 44 | "usize", 45 | "int16", 46 | "int32", 47 | "float32", 48 | "nullable_float32", 49 | "float64", 50 | "float64_supertype", 51 | "array", 52 | "array", 53 | "array", 54 | "array", 55 | "array", 56 | "array", 57 | "array", 58 | "array", 59 | "array", 60 | "array" 61 | ] 62 | }, 63 | "ComplexType": { 64 | "type": "string", 65 | "pattern": "^(array<)?(typedef\\.|enum\\.|bitflag\\.|struct\\.|function_type\\.|object\\.)([a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?)(>)?$" 66 | }, 67 | "CallbackType": { 68 | "type": "string", 69 | "pattern": "^(callback\\.)([a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?)$" 70 | }, 71 | "Type": { 72 | "oneOf": [ 73 | { 74 | "$ref": "#/definitions/PrimitiveType" 75 | }, 76 | { 77 | "$ref": "#/definitions/ComplexType" 78 | }, 79 | { 80 | "$ref": "#/definitions/CallbackType" 81 | } 82 | ] 83 | }, 84 | "Pointer": { 85 | "type": "string", 86 | "enum": [ 87 | "immutable", 88 | "mutable" 89 | ] 90 | }, 91 | "CallbackStyle": { 92 | "type": "string", 93 | "enum": [ 94 | "callback_mode", 95 | "immediate" 96 | ] 97 | }, 98 | "Callback": { 99 | "type": "object", 100 | "additionalProperties": false, 101 | "properties": { 102 | "name": { 103 | "$ref": "#/definitions/Name", 104 | "description": "Callback name" 105 | }, 106 | "namespace": { 107 | "type": "string", 108 | "description": "Optional property, specifying the namespace where this callback is defined", 109 | "pattern": "^[a-z]+$" 110 | }, 111 | "doc": { 112 | "type": "string" 113 | }, 114 | "style": { 115 | "$ref": "#/definitions/CallbackStyle", 116 | "description": "Callback style" 117 | }, 118 | "args": { 119 | "type": "array", 120 | "description": "Optional property, list of callback arguments", 121 | "items": { 122 | "$ref": "#/definitions/FunctionParameterType" 123 | } 124 | } 125 | }, 126 | "required": [ 127 | "name", 128 | "doc", 129 | "style" 130 | ] 131 | }, 132 | "ParameterType": { 133 | "type": "object", 134 | "additionalProperties": false, 135 | "properties": { 136 | "name": { 137 | "$ref": "#/definitions/Name", 138 | "description": "Parameter name" 139 | }, 140 | "doc": { 141 | "type": "string" 142 | }, 143 | "type": { 144 | "$ref": "#/definitions/Type", 145 | "description": "Parameter type" 146 | }, 147 | "passed_with_ownership": { 148 | "type": "boolean", 149 | "description": "Whether the value is passed with ownership or without ownership" 150 | }, 151 | "pointer": { 152 | "$ref": "#/definitions/Pointer", 153 | "description": "Optional property, specifies if a parameter type is a pointer" 154 | }, 155 | "optional": { 156 | "type": "boolean", 157 | "description": "Optional property, to indicate if a parameter is optional" 158 | }, 159 | "default": { 160 | "type": [ 161 | "string", 162 | "number", 163 | "boolean" 164 | ], 165 | "description": "Default value assigned to this parameter when using initializer macro. Special context-dependent values include constant names (`constant.*`), bitflag names (unprefixed), and `zero` for struct-zero-init (where zero-init is known to have the desired result)." 166 | } 167 | }, 168 | "required": [ 169 | "name", 170 | "doc", 171 | "type" 172 | ] 173 | }, 174 | "FunctionParameterType": { 175 | "unevaluatedProperties": false, 176 | "allOf": [ 177 | { 178 | "$ref": "#/definitions/ParameterType" 179 | }, 180 | { 181 | "type": "object", 182 | "properties": { 183 | "doc": { 184 | "type": "string", 185 | "$comment": "Doxygen doesn't support multi-paragraph param docs (containing \\n\\n)", 186 | "pattern": "^\n?.+(\n.+)*\n?$" 187 | } 188 | } 189 | } 190 | ] 191 | }, 192 | "Function": { 193 | "type": "object", 194 | "additionalProperties": false, 195 | "properties": { 196 | "name": { 197 | "$ref": "#/definitions/Name", 198 | "description": "Name of the function" 199 | }, 200 | "namespace": { 201 | "type": "string", 202 | "description": "Optional property, specifying the namespace where this function is defined", 203 | "pattern": "^[a-z]+$" 204 | }, 205 | "doc": { 206 | "type": "string" 207 | }, 208 | "returns": { 209 | "type": "object", 210 | "additionalProperties": false, 211 | "description": "Optional property, return type of the function", 212 | "properties": { 213 | "doc": { 214 | "type": "string", 215 | "$comment": "Doxygen doesn't support multi-paragraph return docs (containing \\n\\n)", 216 | "pattern": "^$|^\n?.+(\n.+)*\n?$" 217 | }, 218 | "type": { 219 | "$ref": "#/definitions/Type", 220 | "description": "Return type of the function" 221 | }, 222 | "optional": { 223 | "type": "boolean", 224 | "description": "Indicates if the return type is optional/nullable" 225 | }, 226 | "passed_with_ownership": { 227 | "type": "boolean", 228 | "description": "Whether the value is passed with ownership or without ownership" 229 | }, 230 | "pointer": { 231 | "$ref": "#/definitions/Pointer", 232 | "description": "Optional property, specifies if a method return type is a pointer" 233 | } 234 | }, 235 | "required": [ 236 | "doc", 237 | "type" 238 | ] 239 | }, 240 | "callback": { 241 | "$ref": "#/definitions/CallbackType", 242 | "description": "Optional property, callback type for async functon" 243 | }, 244 | "args": { 245 | "type": "array", 246 | "description": "Optional property, list of function arguments", 247 | "items": { 248 | "$ref": "#/definitions/FunctionParameterType" 249 | } 250 | } 251 | }, 252 | "required": [ 253 | "name", 254 | "doc" 255 | ] 256 | } 257 | }, 258 | "properties": { 259 | "copyright": { 260 | "type": "string", 261 | "description": "The license string to include at the top of the generated header" 262 | }, 263 | "name": { 264 | "$ref": "#/definitions/Name", 265 | "description": "The name/namespace of the specification" 266 | }, 267 | "enum_prefix": { 268 | "type": "number", 269 | "minimum": 0, 270 | "maximum": 32767, 271 | "description": "The dedicated enum prefix for the implementation specific header to avoid collisions" 272 | }, 273 | "doc": { 274 | "type": "string" 275 | }, 276 | "typedefs": { 277 | "type": "array", 278 | "items": { 279 | "type": "object", 280 | "additionalProperties": false, 281 | "description": "An alias of a primitive type", 282 | "properties": { 283 | "name": { 284 | "$ref": "#/definitions/Name" 285 | }, 286 | "namespace": { 287 | "type": "string", 288 | "description": "Optional property, specifying the namespace where this typedef is defined", 289 | "pattern": "^[a-z]+$" 290 | }, 291 | "doc": { 292 | "type": "string" 293 | }, 294 | "type": { 295 | "$ref": "#/definitions/PrimitiveType" 296 | } 297 | }, 298 | "required": [ 299 | "name", 300 | "doc", 301 | "type" 302 | ] 303 | } 304 | }, 305 | "constants": { 306 | "type": "array", 307 | "items": { 308 | "type": "object", 309 | "additionalProperties": false, 310 | "properties": { 311 | "name": { 312 | "$ref": "#/definitions/Name", 313 | "description": "Name of the constant variable/define" 314 | }, 315 | "namespace": { 316 | "type": "string", 317 | "description": "Optional property, specifying the namespace where this constant is defined", 318 | "pattern": "^[a-z]+$" 319 | }, 320 | "value": { 321 | "$ref": "#/definitions/Value64", 322 | "description": "An enum of predefined max constants or a 64-bit unsigned integer, or float NaN value." 323 | }, 324 | "doc": { 325 | "type": "string" 326 | } 327 | }, 328 | "required": [ 329 | "name", 330 | "value", 331 | "doc" 332 | ] 333 | } 334 | }, 335 | "enums": { 336 | "type": "array", 337 | "items": { 338 | "type": "object", 339 | "additionalProperties": false, 340 | "properties": { 341 | "name": { 342 | "$ref": "#/definitions/Name", 343 | "description": "Name of the enum" 344 | }, 345 | "namespace": { 346 | "type": "string", 347 | "description": "Optional property, specifying the namespace where this enum is defined", 348 | "pattern": "^[a-z]+$" 349 | }, 350 | "doc": { 351 | "type": "string" 352 | }, 353 | "extended": { 354 | "type": "boolean", 355 | "description": "Optional property, an indicator that this enum is an extension of an already present enum" 356 | }, 357 | "entries": { 358 | "type": "array", 359 | "items": { 360 | "anyOf": [ 361 | { 362 | "type": "null", 363 | "description": "Reserves a space in the enum numbering" 364 | }, 365 | { 366 | "type": "object", 367 | "additionalProperties": false, 368 | "properties": { 369 | "name": { 370 | "$ref": "#/definitions/Name", 371 | "description": "Name of the enum entry" 372 | }, 373 | "namespace": { 374 | "type": "string", 375 | "description": "Optional property, specifying the namespace where this enum entry is defined", 376 | "pattern": "^[a-z]+$" 377 | }, 378 | "doc": { 379 | "type": "string" 380 | }, 381 | "value": { 382 | "$ref": "#/definitions/Value16", 383 | "description": "Optional property, a 16-bit unsigned integer" 384 | } 385 | }, 386 | "required": [ 387 | "name", 388 | "doc" 389 | ] 390 | } 391 | ] 392 | } 393 | } 394 | }, 395 | "required": [ 396 | "name", 397 | "doc" 398 | ] 399 | } 400 | }, 401 | "bitflags": { 402 | "type": "array", 403 | "items": { 404 | "type": "object", 405 | "additionalProperties": false, 406 | "properties": { 407 | "name": { 408 | "$ref": "#/definitions/Name", 409 | "description": "Name of the bitflag" 410 | }, 411 | "namespace": { 412 | "type": "string", 413 | "description": "Optional property, specifying the namespace where this bitflag is defined", 414 | "pattern": "^[a-z]+$" 415 | }, 416 | "doc": { 417 | "type": "string" 418 | }, 419 | "extended": { 420 | "type": "boolean", 421 | "description": "Optional property, an indicator that this bitflag is an extension of an already present bitflag" 422 | }, 423 | "entries": { 424 | "type": "array", 425 | "items": { 426 | "type": "object", 427 | "additionalProperties": false, 428 | "properties": { 429 | "name": { 430 | "$ref": "#/definitions/Name", 431 | "description": "Name of the bitflag entry" 432 | }, 433 | "namespace": { 434 | "type": "string", 435 | "description": "Optional property, specifying the namespace where this bitmask entry is defined", 436 | "pattern": "^[a-z]+$" 437 | }, 438 | "doc": { 439 | "type": "string" 440 | }, 441 | "value": { 442 | "$ref": "#/definitions/Value64", 443 | "description": "Optional property, a 64-bit unsigned integer" 444 | }, 445 | "value_combination": { 446 | "type": "array", 447 | "description": "Optional property, an array listing the names of bitflag entries to be OR-ed", 448 | "items": { 449 | "$ref": "#/definitions/Name" 450 | } 451 | } 452 | }, 453 | "required": [ 454 | "name", 455 | "doc" 456 | ] 457 | } 458 | } 459 | }, 460 | "required": [ 461 | "name", 462 | "doc" 463 | ] 464 | } 465 | }, 466 | "structs": { 467 | "type": "array", 468 | "items": { 469 | "type": "object", 470 | "additionalProperties": false, 471 | "properties": { 472 | "name": { 473 | "$ref": "#/definitions/Name", 474 | "description": "Name of the structure" 475 | }, 476 | "namespace": { 477 | "type": "string", 478 | "description": "Optional property, specifying the namespace where this struct is defined", 479 | "pattern": "^[a-z]+$" 480 | }, 481 | "doc": { 482 | "type": "string" 483 | }, 484 | "type": { 485 | "type": "string", 486 | "description": "Type of the structure", 487 | "enum": [ 488 | "extensible", 489 | "extensible_callback_arg", 490 | "extension", 491 | "standalone" 492 | ] 493 | }, 494 | "extends": { 495 | "type": "array", 496 | "description": "Optional property, list of names of the structs that this extension structure extends", 497 | "items": { 498 | "type": "string" 499 | } 500 | }, 501 | "free_members": { 502 | "type": "boolean", 503 | "description": "Optional property, to indicate if a free members function be emitted for the struct" 504 | }, 505 | "members": { 506 | "type": "array", 507 | "description": "Optional property, list of struct members", 508 | "items": { 509 | "$ref": "#/definitions/ParameterType" 510 | } 511 | } 512 | }, 513 | "required": [ 514 | "name", 515 | "doc", 516 | "type" 517 | ] 518 | } 519 | }, 520 | "callbacks": { 521 | "type": "array", 522 | "items": { 523 | "$ref": "#/definitions/Callback" 524 | } 525 | }, 526 | "functions": { 527 | "type": "array", 528 | "items": { 529 | "$ref": "#/definitions/Function" 530 | } 531 | }, 532 | "objects": { 533 | "type": "array", 534 | "items": { 535 | "type": "object", 536 | "additionalProperties": false, 537 | "properties": { 538 | "name": { 539 | "$ref": "#/definitions/Name", 540 | "description": "Name of the object" 541 | }, 542 | "namespace": { 543 | "type": "string", 544 | "description": "Optional property, specifying the namespace where this object is defined", 545 | "pattern": "^[a-z]+$" 546 | }, 547 | "doc": { 548 | "type": "string" 549 | }, 550 | "extended": { 551 | "type": "boolean", 552 | "description": "Optional property, an indicator that this object is an extension of an already present object" 553 | }, 554 | "methods": { 555 | "type": "array", 556 | "items": { 557 | "$ref": "#/definitions/Function" 558 | } 559 | } 560 | } 561 | } 562 | } 563 | }, 564 | "required": [ 565 | "copyright", 566 | "name", 567 | "enum_prefix", 568 | "doc", 569 | "constants", 570 | "typedefs", 571 | "enums", 572 | "bitflags", 573 | "callbacks", 574 | "structs", 575 | "functions", 576 | "objects" 577 | ] 578 | } 579 | -------------------------------------------------------------------------------- /tests/compile/.gitignore: -------------------------------------------------------------------------------- 1 | *.out 2 | windows/*.exe 3 | windows/*.obj 4 | -------------------------------------------------------------------------------- /tests/compile/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for GNU make 2 | 3 | # Always rebuild all targets. 4 | .PHONY: all clean main-c.out main-cpp.out 5 | 6 | all: main-c.out main-cpp.out 7 | 8 | clean: 9 | rm -f main-c.out main-cpp.out 10 | 11 | # Enable all but a few warnings, then also enable a few extras that clang on Mac 12 | # forces off by default even with -Weverything 13 | CLANG_WARNINGS = -Werror -Weverything \ 14 | -Wno-unused-variable \ 15 | -Wno-padded -Wno-poison-system-directories -Wno-c++98-compat-pedantic \ 16 | -Wc99-designator \ 17 | -Welaborated-enum-base \ 18 | -Wenum-enum-conversion \ 19 | -Wenum-float-conversion \ 20 | -Wextra-semi-stmt \ 21 | -Wfinal-dtor-non-final-class \ 22 | -Wgnu-folding-constant \ 23 | -Wimplicit-fallthrough \ 24 | -Wimplicit-int-float-conversion \ 25 | -Wmisleading-indentation \ 26 | -Wquoted-include-in-framework-header \ 27 | -Wreorder-init-list \ 28 | -Wreserved-identifier \ 29 | # phew. 30 | GCC_WARNINGS = -Werror -Wall -Wextra \ 31 | -Wno-unused-variable -Wno-unused-but-set-variable 32 | 33 | main-c.out: main.c main.inl ../../webgpu.h Makefile 34 | # Compile as C 35 | clang -o $@ $< -std=c99 $(CLANG_WARNINGS) 36 | gcc -o $@ $< -std=c99 $(GCC_WARNINGS) 37 | clang -o $@ $< -std=c11 $(CLANG_WARNINGS) 38 | gcc -o $@ $< -std=c11 $(GCC_WARNINGS) 39 | clang -o $@ $< -std=c17 $(CLANG_WARNINGS) 40 | gcc -o $@ $< -std=c17 $(GCC_WARNINGS) 41 | # Pre-release C23 42 | clang -o $@ $< -std=c2x $(CLANG_WARNINGS) 43 | gcc -o $@ $< -std=c2x $(GCC_WARNINGS) 44 | 45 | main-cpp.out: main.cpp main.inl ../../webgpu.h Makefile 46 | # Compile as C++ 47 | clang++ -o $@ $< -std=c++98 $(CLANG_WARNINGS) -Wno-c++11-long-long 48 | g++ -o $@ $< -std=c++98 $(GCC_WARNINGS) 49 | clang++ -o $@ $< -std=c++03 $(CLANG_WARNINGS) -Wno-c++11-long-long 50 | g++ -o $@ $< -std=c++03 $(GCC_WARNINGS) 51 | clang++ -o $@ $< -std=c++11 $(CLANG_WARNINGS) 52 | g++ -o $@ $< -std=c++11 $(GCC_WARNINGS) 53 | clang++ -o $@ $< -std=c++14 $(CLANG_WARNINGS) 54 | g++ -o $@ $< -std=c++14 $(GCC_WARNINGS) 55 | clang++ -o $@ $< -std=c++17 $(CLANG_WARNINGS) 56 | g++ -o $@ $< -std=c++17 $(GCC_WARNINGS) 57 | clang++ -o $@ $< -std=c++20 $(CLANG_WARNINGS) 58 | g++ -o $@ $< -std=c++20 $(GCC_WARNINGS) 59 | # Pre-release C++23 60 | clang++ -o $@ $< -std=c++2b $(CLANG_WARNINGS) 61 | g++ -o $@ $< -std=c++2b $(GCC_WARNINGS) 62 | -------------------------------------------------------------------------------- /tests/compile/main.c: -------------------------------------------------------------------------------- 1 | #include "main.inl" 2 | -------------------------------------------------------------------------------- /tests/compile/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.inl" 2 | -------------------------------------------------------------------------------- /tests/compile/main.inl: -------------------------------------------------------------------------------- 1 | #include "../../webgpu.h" 2 | 3 | // Compile-test the instantiation of all of the macros, and spot-check types 4 | int main(void) { 5 | { 6 | WGPUStringView s = WGPU_STRING_VIEW_INIT; 7 | s.length = WGPU_STRLEN; 8 | } 9 | { 10 | WGPUTextureViewDescriptor a; 11 | a.mipLevelCount = WGPU_MIP_LEVEL_COUNT_UNDEFINED; 12 | a.arrayLayerCount = WGPU_ARRAY_LAYER_COUNT_UNDEFINED; 13 | } 14 | { 15 | WGPUTexelCopyBufferLayout a; 16 | uint32_t x = a.bytesPerRow = WGPU_COPY_STRIDE_UNDEFINED; 17 | uint32_t y = a.rowsPerImage = WGPU_COPY_STRIDE_UNDEFINED; 18 | } 19 | { 20 | WGPURenderPassColorAttachment a; 21 | a.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; 22 | } 23 | { 24 | WGPUBindGroupEntry a; 25 | uint64_t x = a.size = WGPU_WHOLE_SIZE; 26 | } 27 | { 28 | uint64_t x = WGPU_WHOLE_MAP_SIZE; 29 | } 30 | { 31 | WGPULimits a; 32 | uint32_t x = a.maxTextureDimension2D = WGPU_LIMIT_U32_UNDEFINED; 33 | uint64_t y = a.maxBufferSize = WGPU_LIMIT_U64_UNDEFINED; 34 | } 35 | { 36 | WGPUPassTimestampWrites a; 37 | a.beginningOfPassWriteIndex = WGPU_QUERY_SET_INDEX_UNDEFINED; 38 | a.endOfPassWriteIndex = WGPU_QUERY_SET_INDEX_UNDEFINED; 39 | } 40 | 41 | // Simple chaining smoke test 42 | { 43 | // It's not valid to use both WGSL and SPIRV but this test doesn't care. 44 | WGPUShaderSourceSPIRV descSPIRV = WGPU_SHADER_SOURCE_SPIRV_INIT; 45 | WGPUShaderSourceWGSL descWGSL = WGPU_SHADER_SOURCE_WGSL_INIT; 46 | WGPUShaderModuleDescriptor desc = WGPU_SHADER_MODULE_DESCRIPTOR_INIT; 47 | 48 | // Test of linking one extension to another. 49 | descWGSL.chain.next = &descSPIRV.chain; 50 | // Test of linking base struct to an extension. 51 | desc.nextInChain = &descWGSL.chain; 52 | 53 | // Also test the alternate linking style using a cast. 54 | #ifdef __cplusplus 55 | # if __cplusplus >= 201103L 56 | static_assert(offsetof(WGPUShaderSourceWGSL, chain) == 0, ""); 57 | # endif 58 | descWGSL.chain.next = reinterpret_cast(&descSPIRV); 59 | desc.nextInChain = reinterpret_cast(&descWGSL); 60 | #else 61 | descWGSL.chain.next = (WGPUChainedStruct*) &descSPIRV; 62 | desc.nextInChain = (WGPUChainedStruct*) &descWGSL; 63 | #endif 64 | } 65 | 66 | // Check that generated initializers are valid 67 | // TODO: Would be nice to autogenerate this so we don't forget to test any new structs. 68 | { WGPUBufferMapCallbackInfo x = WGPU_BUFFER_MAP_CALLBACK_INFO_INIT; } 69 | { WGPUCompilationInfoCallbackInfo x = WGPU_COMPILATION_INFO_CALLBACK_INFO_INIT; } 70 | { WGPUCreateComputePipelineAsyncCallbackInfo x = WGPU_CREATE_COMPUTE_PIPELINE_ASYNC_CALLBACK_INFO_INIT; } 71 | { WGPUCreateRenderPipelineAsyncCallbackInfo x = WGPU_CREATE_RENDER_PIPELINE_ASYNC_CALLBACK_INFO_INIT; } 72 | { WGPUDeviceLostCallbackInfo x = WGPU_DEVICE_LOST_CALLBACK_INFO_INIT; } 73 | { WGPUPopErrorScopeCallbackInfo x = WGPU_POP_ERROR_SCOPE_CALLBACK_INFO_INIT; } 74 | { WGPUQueueWorkDoneCallbackInfo x = WGPU_QUEUE_WORK_DONE_CALLBACK_INFO_INIT; } 75 | { WGPURequestAdapterCallbackInfo x = WGPU_REQUEST_ADAPTER_CALLBACK_INFO_INIT; } 76 | { WGPURequestDeviceCallbackInfo x = WGPU_REQUEST_DEVICE_CALLBACK_INFO_INIT; } 77 | { WGPUUncapturedErrorCallbackInfo x = WGPU_UNCAPTURED_ERROR_CALLBACK_INFO_INIT; } 78 | { WGPUAdapterInfo x = WGPU_ADAPTER_INFO_INIT; } 79 | { WGPUBindGroupEntry x = WGPU_BIND_GROUP_ENTRY_INIT; } 80 | { WGPUBlendComponent x = WGPU_BLEND_COMPONENT_INIT; } 81 | { WGPUBufferBindingLayout x = WGPU_BUFFER_BINDING_LAYOUT_INIT; } 82 | { WGPUBufferDescriptor x = WGPU_BUFFER_DESCRIPTOR_INIT; } 83 | { WGPUColor x = WGPU_COLOR_INIT; } 84 | { WGPUCommandBufferDescriptor x = WGPU_COMMAND_BUFFER_DESCRIPTOR_INIT; } 85 | { WGPUCommandEncoderDescriptor x = WGPU_COMMAND_ENCODER_DESCRIPTOR_INIT; } 86 | { WGPUCompilationMessage x = WGPU_COMPILATION_MESSAGE_INIT; } 87 | { WGPUConstantEntry x = WGPU_CONSTANT_ENTRY_INIT; } 88 | { WGPUFuture x = WGPU_FUTURE_INIT; } 89 | { WGPUInstanceLimits x = WGPU_INSTANCE_LIMITS_INIT; } 90 | { WGPULimits x = WGPU_LIMITS_INIT; } 91 | { WGPUMultisampleState x = WGPU_MULTISAMPLE_STATE_INIT; } 92 | { WGPUPassTimestampWrites x = WGPU_PASS_TIMESTAMP_WRITES_INIT; } 93 | { WGPUPipelineLayoutDescriptor x = WGPU_PIPELINE_LAYOUT_DESCRIPTOR_INIT; } 94 | { WGPUPrimitiveState x = WGPU_PRIMITIVE_STATE_INIT; } 95 | { WGPUQuerySetDescriptor x = WGPU_QUERY_SET_DESCRIPTOR_INIT; } 96 | { WGPUQueueDescriptor x = WGPU_QUEUE_DESCRIPTOR_INIT; } 97 | { WGPURenderBundleDescriptor x = WGPU_RENDER_BUNDLE_DESCRIPTOR_INIT; } 98 | { WGPURenderBundleEncoderDescriptor x = WGPU_RENDER_BUNDLE_ENCODER_DESCRIPTOR_INIT; } 99 | { WGPURenderPassDepthStencilAttachment x = WGPU_RENDER_PASS_DEPTH_STENCIL_ATTACHMENT_INIT; } 100 | { WGPURenderPassMaxDrawCount x = WGPU_RENDER_PASS_MAX_DRAW_COUNT_INIT; } 101 | { WGPURequestAdapterOptions x = WGPU_REQUEST_ADAPTER_OPTIONS_INIT; } 102 | { WGPUSamplerBindingLayout x = WGPU_SAMPLER_BINDING_LAYOUT_INIT; } 103 | { WGPUSamplerDescriptor x = WGPU_SAMPLER_DESCRIPTOR_INIT; } 104 | { WGPUShaderModuleDescriptor x = WGPU_SHADER_MODULE_DESCRIPTOR_INIT; } 105 | { WGPUShaderSourceSPIRV x = WGPU_SHADER_SOURCE_SPIRV_INIT; } 106 | { WGPUShaderSourceWGSL x = WGPU_SHADER_SOURCE_WGSL_INIT; } 107 | { WGPUStencilFaceState x = WGPU_STENCIL_FACE_STATE_INIT; } 108 | { WGPUStorageTextureBindingLayout x = WGPU_STORAGE_TEXTURE_BINDING_LAYOUT_INIT; } 109 | { WGPUSupportedFeatures x = WGPU_SUPPORTED_FEATURES_INIT; } 110 | { WGPUSupportedInstanceFeatures x = WGPU_SUPPORTED_INSTANCE_FEATURES_INIT; } 111 | { WGPUSupportedWGSLLanguageFeatures x = WGPU_SUPPORTED_WGSL_LANGUAGE_FEATURES_INIT; } 112 | { WGPUSurfaceCapabilities x = WGPU_SURFACE_CAPABILITIES_INIT; } 113 | { WGPUSurfaceConfiguration x = WGPU_SURFACE_CONFIGURATION_INIT; } 114 | { WGPUSurfaceDescriptor x = WGPU_SURFACE_DESCRIPTOR_INIT; } 115 | { WGPUSurfaceSourceAndroidNativeWindow x = WGPU_SURFACE_SOURCE_ANDROID_NATIVE_WINDOW_INIT; } 116 | { WGPUSurfaceSourceMetalLayer x = WGPU_SURFACE_SOURCE_METAL_LAYER_INIT; } 117 | { WGPUSurfaceSourceWaylandSurface x = WGPU_SURFACE_SOURCE_WAYLAND_SURFACE_INIT; } 118 | { WGPUSurfaceSourceWindowsHWND x = WGPU_SURFACE_SOURCE_WINDOWS_HWND_INIT; } 119 | { WGPUSurfaceSourceXCBWindow x = WGPU_SURFACE_SOURCE_XCB_WINDOW_INIT; } 120 | { WGPUSurfaceSourceXlibWindow x = WGPU_SURFACE_SOURCE_XLIB_WINDOW_INIT; } 121 | { WGPUSurfaceTexture x = WGPU_SURFACE_TEXTURE_INIT; } 122 | { WGPUTexelCopyBufferLayout x = WGPU_TEXEL_COPY_BUFFER_LAYOUT_INIT; } 123 | { WGPUTextureBindingLayout x = WGPU_TEXTURE_BINDING_LAYOUT_INIT; } 124 | { WGPUTextureViewDescriptor x = WGPU_TEXTURE_VIEW_DESCRIPTOR_INIT; } 125 | { WGPUVertexAttribute x = WGPU_VERTEX_ATTRIBUTE_INIT; } 126 | { WGPUBindGroupDescriptor x = WGPU_BIND_GROUP_DESCRIPTOR_INIT; } 127 | { WGPUBindGroupLayoutEntry x = WGPU_BIND_GROUP_LAYOUT_ENTRY_INIT; } 128 | { WGPUBlendState x = WGPU_BLEND_STATE_INIT; } 129 | { WGPUCompilationInfo x = WGPU_COMPILATION_INFO_INIT; } 130 | { WGPUComputePassDescriptor x = WGPU_COMPUTE_PASS_DESCRIPTOR_INIT; } 131 | { WGPUComputeState x = WGPU_COMPUTE_STATE_INIT; } 132 | { WGPUDepthStencilState x = WGPU_DEPTH_STENCIL_STATE_INIT; } 133 | { WGPUDeviceDescriptor x = WGPU_DEVICE_DESCRIPTOR_INIT; } 134 | { WGPUFutureWaitInfo x = WGPU_FUTURE_WAIT_INFO_INIT; } 135 | { WGPUInstanceDescriptor x = WGPU_INSTANCE_DESCRIPTOR_INIT; } 136 | { WGPURenderPassColorAttachment x = WGPU_RENDER_PASS_COLOR_ATTACHMENT_INIT; } 137 | { WGPUTexelCopyBufferInfo x = WGPU_TEXEL_COPY_BUFFER_INFO_INIT; } 138 | { WGPUTexelCopyTextureInfo x = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT; } 139 | { WGPUTextureDescriptor x = WGPU_TEXTURE_DESCRIPTOR_INIT; } 140 | { WGPUVertexBufferLayout x = WGPU_VERTEX_BUFFER_LAYOUT_INIT; } 141 | { WGPUBindGroupLayoutDescriptor x = WGPU_BIND_GROUP_LAYOUT_DESCRIPTOR_INIT; } 142 | { WGPUColorTargetState x = WGPU_COLOR_TARGET_STATE_INIT; } 143 | { WGPUComputePipelineDescriptor x = WGPU_COMPUTE_PIPELINE_DESCRIPTOR_INIT; } 144 | { WGPURenderPassDescriptor x = WGPU_RENDER_PASS_DESCRIPTOR_INIT; } 145 | { WGPUVertexState x = WGPU_VERTEX_STATE_INIT; } 146 | { WGPUFragmentState x = WGPU_FRAGMENT_STATE_INIT; } 147 | { WGPURenderPipelineDescriptor x = WGPU_RENDER_PIPELINE_DESCRIPTOR_INIT; } 148 | } 149 | -------------------------------------------------------------------------------- /tests/compile/windows/makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Microsoft NMAKE 2 | 3 | # These target names are not real files so they will always get rebuilt 4 | # (they are nmake "pseudotargets"). 5 | all: build-c build-cpp 6 | 7 | clean: 8 | rm -f main-c.exe main-cpp.exe main.obj 9 | 10 | MSVC_WARNINGS = /Wall /WX /options:strict /wd4820 /wd4464 /wd4189 /wd4101 11 | 12 | build-c: ../main.c ../main.inl ../../../webgpu.h Makefile 13 | cl.exe /Fe:main-c.exe ../main.c /std:c11 $(MSVC_WARNINGS) 14 | cl.exe /Fe:main-c.exe ../main.c /std:c17 $(MSVC_WARNINGS) 15 | cl.exe /Fe:main-c.exe ../main.c $(MSVC_WARNINGS) 16 | # Docs say /std:clatest should work but it does not in VS2022. 17 | # cl.exe /Fe:main-c.exe ../main.c /std:clatest $(MSVC_WARNINGS) 18 | 19 | build-cpp: ../main.cpp ../main.inl ../../../webgpu.h Makefile 20 | cl.exe /Fe:main-cpp.exe ../main.cpp /std:c++14 $(MSVC_WARNINGS) 21 | cl.exe /Fe:main-cpp.exe ../main.cpp /std:c++17 $(MSVC_WARNINGS) 22 | cl.exe /Fe:main-cpp.exe ../main.cpp /std:c++20 $(MSVC_WARNINGS) 23 | cl.exe /Fe:main-cpp.exe ../main.cpp /std:c++latest $(MSVC_WARNINGS) 24 | -------------------------------------------------------------------------------- /tests/extensions/extension.yml: -------------------------------------------------------------------------------- 1 | copyright: | 2 | Copyright 2025 WebGPU-Native developers 3 | 4 | SPDX-License-Identifier: BSD-3-Clause 5 | name: prefix 6 | enum_prefix: 0x7FFF 7 | doc: | 8 | This is a bare minimum extensions file to verify all extension types. 9 | constants: 10 | - name: new_constant1 11 | value: uint32_max 12 | doc: | 13 | New constant should have the namespace prefix in the name by default. 14 | - name: new_constant2 15 | namespace: webgpu 16 | value: uint64_max 17 | doc: | 18 | New constant can be declared in the 'webgpu' namespace explicitly. 19 | typedefs: 20 | - name: new_typedef1 21 | type: uint32 22 | doc: | 23 | New typedef should have the namespace prefix in the name by default. 24 | - name: new_typedef2 25 | namespace: webgpu 26 | type: uint64 27 | doc: | 28 | New typedef can be declared in the 'webgpu' namespace explicitly. 29 | enums: 30 | - name: new_enum1 31 | doc: | 32 | New enum should have the namespace prefix in the name by default. 33 | entries: 34 | - name: new_value 35 | doc: | 36 | New enum entries for a new enum should not duplicate prefix. 37 | - name: new_enum2 38 | namespace: webgpu 39 | doc: | 40 | New enum can be declared in the 'webgpu' namespace explicitly. 41 | entries: 42 | - name: new_value 43 | doc: | 44 | New enum entries for a new enum should not duplicate prefix. 45 | - name: old_enum 46 | doc: | 47 | Extended enum shouldn't have the namespace prefix in the name by default. 48 | extended: True 49 | entries: 50 | - name: new_value 51 | doc: | 52 | New enum entries that extend should have the prefix in the name by default. 53 | bitflags: 54 | - name: new_bitflag1 55 | doc: | 56 | New bitflag should have the namespace prefix in the name by default. 57 | entries: 58 | - name: none 59 | doc: | 60 | TODO 61 | - name: new_value 62 | doc: | 63 | New bitflag entries shouldn't have the namespace prefix in the name by default. 64 | - name: new_bitflag2 65 | namespace: webgpu 66 | doc: | 67 | New bitflag can be declared in the 'webgpu' namespace explicitly. 68 | entries: 69 | - name: none 70 | doc: | 71 | TODO 72 | - name: new_value 73 | doc: | 74 | New bitflag entries shouldn't have the namespace prefix in the name by default. 75 | - name: old_bitflag 76 | doc: | 77 | Extended bitflag shouldn't have the namespace prefix in the name by default. 78 | extended: True 79 | entries: 80 | - name: new_value 81 | doc: | 82 | New bitflag entries that extend should have the prefix in the name by default. 83 | value: 0x1000000000000000 84 | structs: 85 | - name: new_struct1 86 | doc: | 87 | New struct should have the namespace prefix in the name by default. 88 | type: standalone 89 | members: 90 | - name: member1 91 | doc: | 92 | New struct members should not have namespace prefix in the name. 93 | type: uint32 94 | default: constant.new_constant1 95 | - name: member2 96 | doc: | 97 | TODO 98 | type: uint64 99 | default: constant.new_constant2 100 | - name: new_struct2 101 | namespace: webgpu 102 | doc: | 103 | New struct can be declared in the 'webgpu' namespace explicitly. 104 | type: extensible 105 | members: 106 | - name: struct_member 107 | doc: | 108 | TODO 109 | type: struct.new_struct1 110 | callbacks: 111 | - name: new_callback1 112 | doc: | 113 | New callback type should have the namespace prefix in the names by default. 114 | style: callback_mode 115 | args: 116 | - name: message 117 | doc: | 118 | TODO 119 | type: out_string 120 | passed_with_ownership: false 121 | - name: new_callback2 122 | namespace: webgpu 123 | doc: | 124 | New callback type can be declared in the 'webgpu' namespace explicitly. 125 | style: callback_mode 126 | args: 127 | - name: message 128 | doc: | 129 | TODO 130 | type: out_string 131 | passed_with_ownership: false 132 | functions: 133 | - name: new_function1 134 | doc: | 135 | New function should have the namespace prefix in the name by default. 136 | - name: new_function2 137 | namespace: webgpu 138 | doc: | 139 | New function can be declared in the 'webgpu' namespace explicitly. 140 | objects: 141 | - name: new_object1 142 | doc: | 143 | New object should have the namespace prefix in the name by default. 144 | methods: 145 | - name: new_method 146 | doc: | 147 | Method on new object should not have the namespace prefix in the name by default. 148 | - name: new_object2 149 | namespace: webgpu 150 | doc: | 151 | New object can be declared in the 'webgpu' namespace explicitly. 152 | methods: 153 | - name: new_method 154 | doc: | 155 | Method on new object should not have the namespace prefix in the name by default. 156 | - name: old_object 157 | doc: | 158 | Extended object shouldn't have the namespace prefix in the name by default. 159 | extended: True 160 | methods: 161 | - name: new_method1 162 | doc: | 163 | New method on old object should have the namespace prefix in the name by default. 164 | - name: new_method2 165 | namespace: webgpu 166 | doc: | 167 | New method on old object can be declared in the 'webgpu' namespace explicitly. 168 | -------------------------------------------------------------------------------- /tests/extensions/webgpu_extension.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 WebGPU-Native developers 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | /** @file */ 8 | 9 | /** 10 | * \mainpage 11 | * 12 | * This is a bare minimum extensions file to verify all extension types. 13 | */ 14 | 15 | #ifndef WEBGPU_EXTENSION_H_ 16 | #define WEBGPU_EXTENSION_H_ 17 | 18 | #include "webgpu.h" 19 | 20 | #if !defined(_wgpu_EXTEND_ENUM) 21 | #ifdef __cplusplus 22 | #define _wgpu_EXTEND_ENUM(E, N, V) static const E N = E(V) 23 | #else 24 | #define _wgpu_EXTEND_ENUM(E, N, V) static const E N = (E)(V) 25 | #endif 26 | #endif // !defined(_wgpu_EXTEND_ENUM) 27 | 28 | /** 29 | * \defgroup Constants Constants 30 | * \brief Constants. 31 | * 32 | * @{ 33 | */ 34 | 35 | /** 36 | * 'True' value of @ref WGPUBool. 37 | * 38 | * @remark It's not usually necessary to use this, as `true` (from 39 | * `stdbool.h` or C++) casts to the same value. 40 | */ 41 | #define WGPU_TRUE (UINT32_C(1)) 42 | /** 43 | * 'False' value of @ref WGPUBool. 44 | * 45 | * @remark It's not usually necessary to use this, as `false` (from 46 | * `stdbool.h` or C++) casts to the same value. 47 | */ 48 | #define WGPU_FALSE (UINT32_C(0)) 49 | /** 50 | * New constant should have the namespace prefix in the name by default. 51 | */ 52 | #define WGPU_PREFIX_NEW_CONSTANT1 (UINT32_MAX) 53 | /** 54 | * New constant can be declared in the 'webgpu' namespace explicitly. 55 | */ 56 | #define WGPU_NEW_CONSTANT2 (UINT64_MAX) 57 | 58 | /** @} */ 59 | 60 | /** 61 | * \defgroup UtilityTypes Utility Types 62 | * 63 | * @{ 64 | */ 65 | 66 | /** 67 | * New typedef should have the namespace prefix in the name by default. 68 | */ 69 | typedef uint32_t WGPUPrefixNewTypedef1; 70 | /** 71 | * New typedef can be declared in the 'webgpu' namespace explicitly. 72 | */ 73 | typedef uint64_t WGPUNewTypedef2; 74 | 75 | /** @} */ 76 | 77 | /** 78 | * \defgroup Objects Objects 79 | * \brief Opaque, non-dispatchable handles to WebGPU objects. 80 | * 81 | * @{ 82 | */ 83 | /** 84 | * New object should have the namespace prefix in the name by default. 85 | */ 86 | typedef struct WGPUPrefixNewObject1Impl* WGPUPrefixNewObject1 WGPU_OBJECT_ATTRIBUTE; 87 | /** 88 | * New object can be declared in the 'webgpu' namespace explicitly. 89 | */ 90 | typedef struct WGPUNewObject2Impl* WGPUNewObject2 WGPU_OBJECT_ATTRIBUTE; 91 | 92 | /** @} */ 93 | 94 | // Structure forward declarations 95 | struct WGPUPrefixNewStruct1; 96 | struct WGPUNewStruct2; 97 | 98 | // Callback info structure forward declarations 99 | struct WGPUPrefixNewCallback1CallbackInfo; 100 | struct WGPUNewCallback2CallbackInfo; 101 | 102 | /** 103 | * \defgroup Enumerations Enumerations 104 | * \brief Enums. 105 | * 106 | * @{ 107 | */ 108 | 109 | /** 110 | * Extended enum shouldn't have the namespace prefix in the name by default. 111 | */ 112 | /** 113 | * New enum entries that extend should have the prefix in the name by default. 114 | */ 115 | _wgpu_EXTEND_ENUM(WGPUOldEnum, WGPUOldEnum_PrefixNewValue, 0x7FFF0000); 116 | 117 | /** 118 | * New enum should have the namespace prefix in the name by default. 119 | */ 120 | typedef enum WGPUPrefixNewEnum1 { 121 | /** 122 | * New enum entries for a new enum should not duplicate prefix. 123 | */ 124 | WGPUPrefixNewEnum1_NewValue = 0x7FFF0000, 125 | WGPUPrefixNewEnum1_Force32 = 0x7FFFFFFF 126 | } WGPUPrefixNewEnum1 WGPU_ENUM_ATTRIBUTE; 127 | 128 | /** 129 | * New enum can be declared in the 'webgpu' namespace explicitly. 130 | */ 131 | typedef enum WGPUNewEnum2 { 132 | /** 133 | * New enum entries for a new enum should not duplicate prefix. 134 | */ 135 | WGPUNewEnum2_NewValue = 0x7FFF0000, 136 | WGPUNewEnum2_Force32 = 0x7FFFFFFF 137 | } WGPUNewEnum2 WGPU_ENUM_ATTRIBUTE; 138 | 139 | /** @} */ 140 | 141 | /** 142 | * \defgroup Bitflags Bitflags 143 | * \brief Type and constant definitions for bitflag types. 144 | * 145 | * @{ 146 | */ 147 | 148 | /** 149 | * Extended bitflag shouldn't have the namespace prefix in the name by default. 150 | * 151 | * For reserved non-standard bitflag values, see @ref BitflagRegistry. 152 | */ 153 | /** 154 | * New bitflag entries that extend should have the prefix in the name by default. 155 | */ 156 | static const WGPUOldBitflag WGPUOldBitflag_PrefixNewValue = 0x1000000000000000; 157 | 158 | /** 159 | * New bitflag should have the namespace prefix in the name by default. 160 | * 161 | * For reserved non-standard bitflag values, see @ref BitflagRegistry. 162 | */ 163 | typedef WGPUFlags WGPUPrefixNewBitflag1; 164 | /** 165 | * `0`. 166 | */ 167 | static const WGPUPrefixNewBitflag1 WGPUPrefixNewBitflag1_None = 0x0000000000000000; 168 | /** 169 | * New bitflag entries shouldn't have the namespace prefix in the name by default. 170 | */ 171 | static const WGPUPrefixNewBitflag1 WGPUPrefixNewBitflag1_NewValue = 0x0000000000000001; 172 | 173 | /** 174 | * New bitflag can be declared in the 'webgpu' namespace explicitly. 175 | * 176 | * For reserved non-standard bitflag values, see @ref BitflagRegistry. 177 | */ 178 | typedef WGPUFlags WGPUNewBitflag2; 179 | /** 180 | * `0`. 181 | */ 182 | static const WGPUNewBitflag2 WGPUNewBitflag2_None = 0x0000000000000000; 183 | /** 184 | * New bitflag entries shouldn't have the namespace prefix in the name by default. 185 | */ 186 | static const WGPUNewBitflag2 WGPUNewBitflag2_NewValue = 0x0000000000000001; 187 | 188 | /** @} */ 189 | 190 | /** 191 | * \defgroup Callbacks Callbacks 192 | * \brief Callbacks through which asynchronous functions return. 193 | * 194 | * @{ 195 | */ 196 | 197 | /** 198 | * New callback type should have the namespace prefix in the names by default. 199 | * 200 | * See also @ref CallbackError. 201 | * 202 | * @param message 203 | * This parameter is @ref PassedWithoutOwnership. 204 | */ 205 | typedef void (*WGPUPrefixNewCallback1Callback)(WGPUStringView message, WGPU_NULLABLE void* userdata1, WGPU_NULLABLE void* userdata2) WGPU_FUNCTION_ATTRIBUTE; 206 | 207 | /** 208 | * New callback type can be declared in the 'webgpu' namespace explicitly. 209 | * 210 | * See also @ref CallbackError. 211 | * 212 | * @param message 213 | * This parameter is @ref PassedWithoutOwnership. 214 | */ 215 | typedef void (*WGPUNewCallback2Callback)(WGPUStringView message, WGPU_NULLABLE void* userdata1, WGPU_NULLABLE void* userdata2) WGPU_FUNCTION_ATTRIBUTE; 216 | 217 | /** @} */ 218 | 219 | /** 220 | * \defgroup Structures Structures 221 | * \brief Descriptors and other transparent structures. 222 | * 223 | * @{ 224 | */ 225 | 226 | /** 227 | * \defgroup CallbackInfoStructs Callback Info Structs 228 | * \brief Callback info structures that are used in asynchronous functions. 229 | * 230 | * @{ 231 | */ 232 | 233 | /** 234 | * New callback type should have the namespace prefix in the names by default. 235 | */ 236 | typedef struct WGPUPrefixNewCallback1CallbackInfo { 237 | WGPUChainedStruct * nextInChain; 238 | /** 239 | * Controls when the callback may be called. 240 | * 241 | * Has no default. The `INIT` macro sets this to (@ref WGPUCallbackMode)0. 242 | */ 243 | WGPUCallbackMode mode; 244 | WGPUPrefixNewCallback1Callback callback; 245 | WGPU_NULLABLE void* userdata1; 246 | WGPU_NULLABLE void* userdata2; 247 | } WGPUPrefixNewCallback1CallbackInfo WGPU_STRUCTURE_ATTRIBUTE; 248 | 249 | /** 250 | * Initializer for @ref WGPUPrefixNewCallback1CallbackInfo. 251 | */ 252 | #define WGPU_PREFIX_NEW_CALLBACK1_CALLBACK_INFO_INIT _wgpu_MAKE_INIT_STRUCT(WGPUPrefixNewCallback1CallbackInfo, { \ 253 | /*.nextInChain=*/NULL _wgpu_COMMA \ 254 | /*.mode=*/_wgpu_ENUM_ZERO_INIT(WGPUCallbackMode) _wgpu_COMMA \ 255 | /*.callback=*/NULL _wgpu_COMMA \ 256 | /*.userdata1=*/NULL _wgpu_COMMA \ 257 | /*.userdata2=*/NULL _wgpu_COMMA \ 258 | }) 259 | 260 | /** 261 | * New callback type can be declared in the 'webgpu' namespace explicitly. 262 | */ 263 | typedef struct WGPUNewCallback2CallbackInfo { 264 | WGPUChainedStruct * nextInChain; 265 | /** 266 | * Controls when the callback may be called. 267 | * 268 | * Has no default. The `INIT` macro sets this to (@ref WGPUCallbackMode)0. 269 | */ 270 | WGPUCallbackMode mode; 271 | WGPUNewCallback2Callback callback; 272 | WGPU_NULLABLE void* userdata1; 273 | WGPU_NULLABLE void* userdata2; 274 | } WGPUNewCallback2CallbackInfo WGPU_STRUCTURE_ATTRIBUTE; 275 | 276 | /** 277 | * Initializer for @ref WGPUNewCallback2CallbackInfo. 278 | */ 279 | #define WGPU_NEW_CALLBACK2_CALLBACK_INFO_INIT _wgpu_MAKE_INIT_STRUCT(WGPUNewCallback2CallbackInfo, { \ 280 | /*.nextInChain=*/NULL _wgpu_COMMA \ 281 | /*.mode=*/_wgpu_ENUM_ZERO_INIT(WGPUCallbackMode) _wgpu_COMMA \ 282 | /*.callback=*/NULL _wgpu_COMMA \ 283 | /*.userdata1=*/NULL _wgpu_COMMA \ 284 | /*.userdata2=*/NULL _wgpu_COMMA \ 285 | }) 286 | 287 | /** @} */ 288 | 289 | /** 290 | * New struct should have the namespace prefix in the name by default. 291 | * 292 | * Default values can be set using @ref WGPU_PREFIX_NEW_STRUCT1_INIT as initializer. 293 | */ 294 | typedef struct WGPUPrefixNewStruct1 { 295 | /** 296 | * New struct members should not have namespace prefix in the name. 297 | * 298 | * The `INIT` macro sets this to @ref WGPU_PREFIX_NEW_CONSTANT1. 299 | */ 300 | uint32_t member1; 301 | /** 302 | * The `INIT` macro sets this to @ref WGPU_NEW_CONSTANT2. 303 | */ 304 | uint64_t member2; 305 | } WGPUPrefixNewStruct1 WGPU_STRUCTURE_ATTRIBUTE; 306 | 307 | /** 308 | * Initializer for @ref WGPUPrefixNewStruct1. 309 | */ 310 | #define WGPU_PREFIX_NEW_STRUCT1_INIT _wgpu_MAKE_INIT_STRUCT(WGPUPrefixNewStruct1, { \ 311 | /*.member1=*/WGPU_PREFIX_NEW_CONSTANT1 _wgpu_COMMA \ 312 | /*.member2=*/WGPU_NEW_CONSTANT2 _wgpu_COMMA \ 313 | }) 314 | 315 | /** 316 | * New struct can be declared in the 'webgpu' namespace explicitly. 317 | * 318 | * Default values can be set using @ref WGPU_NEW_STRUCT2_INIT as initializer. 319 | */ 320 | typedef struct WGPUNewStruct2 { 321 | WGPUChainedStruct * nextInChain; 322 | /** 323 | * The `INIT` macro sets this to @ref WGPU_PREFIX_NEW_STRUCT1_INIT. 324 | */ 325 | WGPUPrefixNewStruct1 structMember; 326 | } WGPUNewStruct2 WGPU_STRUCTURE_ATTRIBUTE; 327 | 328 | /** 329 | * Initializer for @ref WGPUNewStruct2. 330 | */ 331 | #define WGPU_NEW_STRUCT2_INIT _wgpu_MAKE_INIT_STRUCT(WGPUNewStruct2, { \ 332 | /*.nextInChain=*/NULL _wgpu_COMMA \ 333 | /*.structMember=*/WGPU_PREFIX_NEW_STRUCT1_INIT _wgpu_COMMA \ 334 | }) 335 | 336 | /** @} */ 337 | 338 | #ifdef __cplusplus 339 | extern "C" { 340 | #endif 341 | 342 | #if !defined(WGPU_SKIP_PROCS) 343 | // Global procs 344 | /** 345 | * Proc pointer type for @ref wgpuPrefixNewFunction1: 346 | * > @copydoc wgpuPrefixNewFunction1 347 | */ 348 | typedef void (*WGPUProcPrefixNewFunction1)() WGPU_FUNCTION_ATTRIBUTE; 349 | /** 350 | * Proc pointer type for @ref wgpuNewFunction2: 351 | * > @copydoc wgpuNewFunction2 352 | */ 353 | typedef void (*WGPUProcNewFunction2)() WGPU_FUNCTION_ATTRIBUTE; 354 | 355 | // Procs of PrefixNewObject1 356 | /** 357 | * Proc pointer type for @ref wgpuPrefixNewObject1NewMethod: 358 | * > @copydoc wgpuPrefixNewObject1NewMethod 359 | */ 360 | typedef void (*WGPUProcPrefixNewObject1NewMethod)(WGPUPrefixNewObject1 newObject1) WGPU_FUNCTION_ATTRIBUTE; 361 | /** 362 | * Proc pointer type for @ref wgpuPrefixNewObject1AddRef: 363 | * > @copydoc wgpuPrefixNewObject1AddRef 364 | */ 365 | typedef void (*WGPUProcPrefixNewObject1AddRef)(WGPUPrefixNewObject1 newObject1) WGPU_FUNCTION_ATTRIBUTE; 366 | /** 367 | * Proc pointer type for @ref wgpuPrefixNewObject1Release: 368 | * > @copydoc wgpuPrefixNewObject1Release 369 | */ 370 | typedef void (*WGPUProcPrefixNewObject1Release)(WGPUPrefixNewObject1 newObject1) WGPU_FUNCTION_ATTRIBUTE; 371 | 372 | // Procs of NewObject2 373 | /** 374 | * Proc pointer type for @ref wgpuNewObject2NewMethod: 375 | * > @copydoc wgpuNewObject2NewMethod 376 | */ 377 | typedef void (*WGPUProcNewObject2NewMethod)(WGPUNewObject2 newObject2) WGPU_FUNCTION_ATTRIBUTE; 378 | /** 379 | * Proc pointer type for @ref wgpuNewObject2AddRef: 380 | * > @copydoc wgpuNewObject2AddRef 381 | */ 382 | typedef void (*WGPUProcNewObject2AddRef)(WGPUNewObject2 newObject2) WGPU_FUNCTION_ATTRIBUTE; 383 | /** 384 | * Proc pointer type for @ref wgpuNewObject2Release: 385 | * > @copydoc wgpuNewObject2Release 386 | */ 387 | typedef void (*WGPUProcNewObject2Release)(WGPUNewObject2 newObject2) WGPU_FUNCTION_ATTRIBUTE; 388 | 389 | // Procs of OldObject 390 | /** 391 | * Proc pointer type for @ref wgpuOldObjectPrefixNewMethod1: 392 | * > @copydoc wgpuOldObjectPrefixNewMethod1 393 | */ 394 | typedef void (*WGPUProcOldObjectPrefixNewMethod1)(WGPUOldObject oldObject) WGPU_FUNCTION_ATTRIBUTE; 395 | /** 396 | * Proc pointer type for @ref wgpuOldObjectNewMethod2: 397 | * > @copydoc wgpuOldObjectNewMethod2 398 | */ 399 | typedef void (*WGPUProcOldObjectNewMethod2)(WGPUOldObject oldObject) WGPU_FUNCTION_ATTRIBUTE; 400 | 401 | #endif // !defined(WGPU_SKIP_PROCS) 402 | 403 | #if !defined(WGPU_SKIP_DECLARATIONS) 404 | /** 405 | * \defgroup GlobalFunctions Global Functions 406 | * \brief Functions that are not specific to an object. 407 | * 408 | * @{ 409 | */ 410 | /** 411 | * New function should have the namespace prefix in the name by default. 412 | */ 413 | WGPU_EXPORT void wgpuPrefixNewFunction1() WGPU_FUNCTION_ATTRIBUTE; 414 | /** 415 | * New function can be declared in the 'webgpu' namespace explicitly. 416 | */ 417 | WGPU_EXPORT void wgpuNewFunction2() WGPU_FUNCTION_ATTRIBUTE; 418 | 419 | /** @} */ 420 | 421 | /** 422 | * \defgroup Methods Methods 423 | * \brief Functions that are relative to a specific object. 424 | * 425 | * @{ 426 | */ 427 | 428 | /** 429 | * \defgroup WGPUPrefixNewObject1Methods WGPUPrefixNewObject1 methods 430 | * \brief Functions whose first argument has type WGPUPrefixNewObject1. 431 | * 432 | * @{ 433 | */ 434 | /** 435 | * Method on new object should not have the namespace prefix in the name by default. 436 | */ 437 | WGPU_EXPORT void wgpuPrefixNewObject1NewMethod(WGPUPrefixNewObject1 newObject1) WGPU_FUNCTION_ATTRIBUTE; 438 | WGPU_EXPORT void wgpuPrefixNewObject1AddRef(WGPUPrefixNewObject1 newObject1) WGPU_FUNCTION_ATTRIBUTE; 439 | WGPU_EXPORT void wgpuPrefixNewObject1Release(WGPUPrefixNewObject1 newObject1) WGPU_FUNCTION_ATTRIBUTE; 440 | 441 | /** @} */ 442 | 443 | /** 444 | * \defgroup WGPUNewObject2Methods WGPUNewObject2 methods 445 | * \brief Functions whose first argument has type WGPUNewObject2. 446 | * 447 | * @{ 448 | */ 449 | /** 450 | * Method on new object should not have the namespace prefix in the name by default. 451 | */ 452 | WGPU_EXPORT void wgpuNewObject2NewMethod(WGPUNewObject2 newObject2) WGPU_FUNCTION_ATTRIBUTE; 453 | WGPU_EXPORT void wgpuNewObject2AddRef(WGPUNewObject2 newObject2) WGPU_FUNCTION_ATTRIBUTE; 454 | WGPU_EXPORT void wgpuNewObject2Release(WGPUNewObject2 newObject2) WGPU_FUNCTION_ATTRIBUTE; 455 | 456 | /** @} */ 457 | 458 | /** 459 | * \defgroup WGPUOldObjectMethods WGPUOldObject methods 460 | * \brief Functions whose first argument has type WGPUOldObject. 461 | * 462 | * @{ 463 | */ 464 | /** 465 | * New method on old object should have the namespace prefix in the name by default. 466 | */ 467 | WGPU_EXPORT void wgpuOldObjectPrefixNewMethod1(WGPUOldObject oldObject) WGPU_FUNCTION_ATTRIBUTE; 468 | /** 469 | * New method on old object can be declared in the 'webgpu' namespace explicitly. 470 | */ 471 | WGPU_EXPORT void wgpuOldObjectNewMethod2(WGPUOldObject oldObject) WGPU_FUNCTION_ATTRIBUTE; 472 | 473 | /** @} */ 474 | 475 | /** @} */ 476 | 477 | #endif // !defined(WGPU_SKIP_DECLARATIONS) 478 | 479 | #ifdef __cplusplus 480 | } // extern "C" 481 | #endif 482 | 483 | #endif // WEBGPU_EXTENSION_H_ 484 | --------------------------------------------------------------------------------