diff --git a/CHANGELOG.md b/CHANGELOG.md index b0af530e..4afc04fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,15 @@ Possible sections in each release: * Fixed: for any bug fixes. * Security: in case of vulnerabilities. +### [v0.10.1] - tdb + +In this release the API is aligned with the latest webgpu.idl. + +Added: + +* New `wgpu.wgsl_language_features` property, which for now always returns an empty set. +* The `GPUShaderModule.compilation_info` property (and its async version) are replaced with a `get_compilation_info()` method. + ### [v0.9.5] - 02-10-2023 diff --git a/README.md b/README.md index e878380d..affbd585 100644 --- a/README.md +++ b/README.md @@ -112,12 +112,12 @@ This code is distributed under the 2-clause BSD license. * Use `pip wheel --no-deps .` to build a wheel. -### Changing the upstream wgpu-native version +### Updating to a later version of WebGPU or wgpu-native + +To update to upstream changes, we use a combination of automatic code +generation and manual updating. See [the codegen utility](codegen/README.md) +for more information. -* Use the optional arguments to `python download-wgpu-native.py --help` to - download a different version of the upstream wgpu-native binaries. -* The file `wgpu/resources/wgpu_native-version` will be updated by the script to - track which version we depend upon. ## Testing diff --git a/codegen/README.md b/codegen/README.md index e3493497..b757d8ab 100644 --- a/codegen/README.md +++ b/codegen/README.md @@ -10,11 +10,12 @@ The purpose of this helper package is to: * To validate that our calls into wgpu-native are correct. We try to hit a balance between automatic code generation and providing -hints to help with manual updating. It should *not* be necessarry to check -the diffs of `webgpu.idl` or `wgpu.h`; any relevant differences should +hints to help with manual updating. It should *not* be necessarry to +check the diffs of `webgpu.idl` or `wgpu.h`. Instead, by running the +codegen, any relevant differences (in webgpu.idl and wgpu.h) should result in changes (of code or annotations) in the respective `.py` -files. That said, during development it can be helpful to use the -WebGPU spec and the header file as a reference. +files. That said, during development it can be helpful to use the WebGPU +spec and the header file as a reference. This package is *not* part of the wgpu-lib - it is a tool to help maintain it. It has its own tests, which try to cover the utils well, @@ -39,7 +40,7 @@ tests, because we are the only users. If it breaks, we fix it. flag/enum mismatches between IDL and wgpu.h. -## Updating the base API +## Updating the base API (`base.py`) The WebGPU API is specified by `webgpu.idl` (in the resources directory). We parse this file with a custom parser (`idlparser.py`) to obtain a description @@ -55,37 +56,42 @@ Next, the Python base API (`base.py`) is updated: The update process to follow: -* Download the latest `webgpu.idl`. +* Download the latest `webgpu.idl` (see link above) and place in the resources folder. * Run `python codegen` to apply the automatic patches to the code. -* Now go through all FIXME comments that were added, and apply any necessary - changes. Remove the FIXME comment if no further action is needed. Note that all - new classes/methods/properties (instead those marked as hidden) need a docstring. -* Also check the diff of `flags.py`, `enums.py`, `structs.py` for any changes that might need manual work. -* Run `python wgpu.codegen` again to validate that all is well. +* It may be necessary to tweak the `idlparser.py` to adjust it to new formatting. +* Check the diff of `flags.py`, `enums.py`, `structs.py` for any changes that might need manual work. +* Go through all FIXME comments that were added in `base.py`: + * Apply any necessary changes. + * Remove the FIXME comment if no further action is needed, or turn into a TODO for later. + * Note that all new classes/methods/properties (instead those marked as hidden) need a docstring. +* Run `python codegen` again to validate that all is well. Repeat the step above if necessary. * Make a summary of the API changes to put in the release notes. * Update downstream code, like our own tests and examples, but also e.g. pygfx. -In some cases we may want to deviate from the WebGPU API, because well ... Python -is not JavaScript. To tell the patcher logic how we deviate from the WebGPU spec: +In some cases we may want to deviate from the WebGPU API, because well ... +Python is not JavaScript. There is a simple system in place to mark any +such differences, that also makes sure that these changes are listed +in the docs. To mark how the py API deviates from the WebGPU spec: * Decorate a method with `@apidiff.hide` to mark it as not supported by our API. * Decorate a method with `@apidiff.add` to mark it as intended even though it does not match the WebGPU spec. * Decorate a method with `@apidiff.change` to mark that our method has a different signature. +While `base.py` defines the API (and corresponding docstrings), the implementation +of the majority of methods occurs in the backends. + ## Updating the API of the backend implementations The backend implementations of the API (e.g. `rs.py`) are also patched. -In this case the source is the base API (instead of the IDL). - -The update process is similar to the generation of the base API, except -that methods are only added if they `raise NotImplementedError()` in -the base implementation. Another difference is that this API should not -deviate from the base API - only additions are allowed (which should -be used sparingly). +The backends are almost a copy of `base.py`: all methods in `base.py` +that `raise NotImplementedError()` must be implemented. + The API of the backends should not +deviate from the base API - only additions are allowed (and should be +used sparingly). -You'd typically update the backends while you're updating `base.py`. +You'll typically need to update the backends while you're updating `base.py`. ## Updating the Rust backend (`rs.py`) @@ -93,10 +99,9 @@ You'd typically update the backends while you're updating `base.py`. The `rs.py` backend calls into a C library (wgpu-native). The codegen helps here, by parsing the corresponding `wgpu.h` and: -* Detect and report missing flags and flag fields. -* Detect and report missing enums and enum fields. +* Detect and report missing flags and enum fields. * Generate mappings for enum field names to ints. -* Validate and annotate struct creations. +* Validate and annotate struct creations (missing struct fields are filled in). * Validate and annotate function calls into the lib. The update process to follow: @@ -107,10 +112,10 @@ The update process to follow: * Diff `rs.py` to see what structs and functions have changed. Lines marked with a FIXME comment should be fixed. Others may or may not. Use `wgpu.h` as a reference to check available functions and structs. -* Run `python wgpu.codegen` again to validate that all is well. +* Run `python codegen` again to validate that all is well. * Make sure that the tests run and provide full coverage. * This process typically does not introduce changes to the API, but certain - features that were previously not supported could be after an update. + features that were previously not supported could now be withing reach. ## Further tips diff --git a/codegen/apipatcher.py b/codegen/apipatcher.py index f402fab5..b376ee27 100644 --- a/codegen/apipatcher.py +++ b/codegen/apipatcher.py @@ -313,11 +313,18 @@ def get_method_def(self, classname, methodname): # Get arg names and types args = idl_line.split("(", 1)[1].split(")", 1)[0].split(",") args = [arg.strip() for arg in args if arg.strip()] - defaults = [arg.partition("=")[2].strip() for arg in args] - defaults = [ - default or (arg.startswith("optional ") and "None") - for default, arg in zip(defaults, args) - ] + raw_defaults = [arg.partition("=")[2].strip() for arg in args] + place_holder_default = False + defaults = [] + for default, arg in zip(raw_defaults, args): + if default: + place_holder_default = "None" # any next args must have a default + elif arg.startswith("optional "): + default = "None" + else: + default = place_holder_default + defaults.append(default) + argnames = [arg.split("=")[0].split()[-1] for arg in args] argnames = [to_snake_case(argname) for argname in argnames] argnames = [(f"{n}={v}" if v else n) for n, v in zip(argnames, defaults)] diff --git a/codegen/files.py b/codegen/files.py index 69607c55..23b424f6 100644 --- a/codegen/files.py +++ b/codegen/files.py @@ -1,3 +1,7 @@ +""" +Simple utilities to handle files, including a mini virtual file system. +""" + import os diff --git a/codegen/idlparser.py b/codegen/idlparser.py index 62f2be99..33b25496 100644 --- a/codegen/idlparser.py +++ b/codegen/idlparser.py @@ -198,6 +198,8 @@ def resolve_type(self, typename): "boolean": "bool", "object": "dict", "ImageBitmap": "memoryview", + "ImageData": "memoryview", + "VideoFrame": "memoryview", "GPUPipelineConstantValue": "float", } name = pythonmap.get(name, name) @@ -255,6 +257,8 @@ def _parse(self): value = value.split("]")[-1] # Parse if value.startswith("("): # Union type + while ")" not in value: + value = value.rstrip() + " " + self.read_line().lstrip() assert value.count("(") == 1 and value.count(")") == 1 value = value.split("(")[1] val, _, key = value.partition(")") @@ -265,6 +269,8 @@ def _parse(self): elif line.startswith(("namespace ", "interface ", "partial interface ")): # A class or a set of flags # Collect lines that define this interface + while "{" not in line: + line = line.rstrip() + " " + self.read_line().lstrip() lines = [line] while not line.startswith("};"): line = self.read_line() @@ -344,6 +350,8 @@ def _parse(self): d[key] = val self.enums[name] = d elif line.startswith("dictionary "): + while "{" not in line: + line = line.rstrip() + self.read_line() assert line.count("{") == 1 and line.count("}") == 0 lines = [line] while not line.startswith("};"): @@ -390,7 +398,12 @@ def _post_process(self): """ # Drop some toplevel names - for name in ["NavigatorGPU", "GPUSupportedLimits", "GPUSupportedFeatures"]: + for name in [ + "NavigatorGPU", + "GPUSupportedLimits", + "GPUSupportedFeatures", + "WGSLLanguageFeatures", + ]: self._interfaces.pop(name, None) # Divide flags and actual class definitions diff --git a/tests/test_api.py b/tests/test_api.py index 1dfd4337..046da9f8 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -166,6 +166,7 @@ class GPU: wgpu._register_backend(GPU) GPU.request_adapter_async = lambda self: None + GPU.wgsl_language_features = set() wgpu._register_backend(GPU) assert wgpu.GPU is GPU diff --git a/tests/test_rs_basics.py b/tests/test_rs_basics.py index 27d52793..9c339e5c 100644 --- a/tests/test_rs_basics.py +++ b/tests/test_rs_basics.py @@ -156,7 +156,7 @@ def test_shader_module_creation_spirv(): code4 = type("CodeObject", (object,), {}) m1 = device.create_shader_module(code=code1) - assert m1.compilation_info() == [] + assert m1.get_compilation_info() == [] with raises(TypeError): device.create_shader_module(code=code4) diff --git a/wgpu/__init__.py b/wgpu/__init__.py index 602da878..f563b5f8 100644 --- a/wgpu/__init__.py +++ b/wgpu/__init__.py @@ -33,6 +33,7 @@ def _register_backend(cls): globals()["GPU"] = GPU globals()["request_adapter"] = gpu.request_adapter globals()["request_adapter_async"] = gpu.request_adapter_async + globals()["wgsl_language_features"] = gpu.wgsl_language_features if hasattr(gpu, "print_report"): globals()["print_report"] = gpu.print_report else: diff --git a/wgpu/backends/rs.py b/wgpu/backends/rs.py index a9b9370e..111af27f 100644 --- a/wgpu/backends/rs.py +++ b/wgpu/backends/rs.py @@ -1,11 +1,11 @@ """ WGPU backend implementation based on wgpu-native -The wgpu-native project (https://github.com/gfx-rs/wgpu) is a Rust -library based on gfx-hal, which wraps Metal, Vulkan, DX12 and more in -the future. It compiles to a dynamic library exposing a C-API, -accompanied by a C header file. We wrap this using cffi, which uses the -header file to do most type conversions for us. +The wgpu-native project (https://github.com/gfx-rs/wgpu-native) is a Rust +library based on wgou-core, which wraps Metal, Vulkan, DX12, and more. +It compiles to a dynamic library exposing a C-API, accompanied by a C +header file. We wrap this using cffi, which uses the header file to do +most type conversions for us. Developer notes and tips: @@ -15,7 +15,7 @@ this can be automated, and this would indeed be possible for 80-90% of the methods. However, the API's do not always line up, and there's async stuff to take into account too. Therefore we do it manually. - In the end, I think that this will make the code easier to maintain. + In the end, I think that this makes the code easier to maintain. * Use new_struct() and new_struct_p() to create a C structure with minimal boilerplate. It also converts string enum values to their corresponding integers. @@ -70,6 +70,14 @@ WGPU_LIMIT_U32_UNDEFINED = 0xFFFFFFFF WGPU_LIMIT_U64_UNDEFINED = 0xFFFFFFFFFFFFFFFF + +# Features in WebGPU that don't map to wgpu-native yet +KNOWN_MISSING_FEATURES = [ + "bgra8unorm-storage", + "float32-filterable", +] + +# Features that wgpu-native supports that are not part of WebGPU NATIVE_FEATURES = ( "multi_draw_indirect", "push_constants", @@ -279,7 +287,8 @@ def callback(status, result, message, userdata): # For now, Rust will call the callback immediately # todo: when wgpu gets an event loop -> while run wgpu event loop or something - assert adapter_id is not None + if adapter_id is None: # pragma: no cover + raise RuntimeError("Could not obtain new adapter id.") # ----- Get adapter info @@ -339,7 +348,12 @@ def to_py_str(key): # WebGPU features features = set() for f in sorted(enums.FeatureName): - i = enummap[f"FeatureName.{f}"] + key = f"FeatureName.{f}" + if key not in enummap: + if f not in KNOWN_MISSING_FEATURES: # pragma: no cover + raise RuntimeError(f"Unexpected feature {f}") + continue + i = enummap[key] # H: bool f(WGPUAdapter adapter, WGPUFeatureName feature) if lib.wgpuAdapterHasFeature(adapter_id, i): features.add(f) @@ -450,7 +464,7 @@ def __init__(self, canvas): self._current_texture = None def get_current_texture(self): - if self._device is None: + if self._device is None: # pragma: no cover raise RuntimeError( "Preset context must be configured before get_current_texture()." ) @@ -658,7 +672,7 @@ def _request_device( i1 = enummap.get(f"FeatureName.{f}", None) i2 = getattr(lib, f"WGPUNativeFeature_{f.upper()}", None) i = i2 if i1 is None else i1 - if i is None: + if i is None: # pragma: no cover raise KeyError(f"Unknown feature: '{f}'") c_features.add(i) @@ -735,7 +749,8 @@ def callback(status, result, message, userdata): # H: void f(WGPUAdapter adapter, WGPUDeviceDescriptor const * descriptor /* nullable */, WGPURequestDeviceCallback callback, void * userdata) lib.wgpuAdapterRequestDevice(self._internal, struct, callback, ffi.NULL) - assert device_id is not None + if device_id is None: # pragma: no cover + raise RuntimeError("Could not obtain new device id.") # ----- Get device limits @@ -755,7 +770,12 @@ def callback(status, result, message, userdata): # WebGPU features features = set() for f in sorted(enums.FeatureName): - i = enummap[f"FeatureName.{f}"] + key = f"FeatureName.{f}" + if key not in enummap: + if f not in KNOWN_MISSING_FEATURES: # pragma: no cover + raise RuntimeError(f"Unexpected feature {f}") + continue + i = enummap[key] # H: bool f(WGPUDevice device, WGPUFeatureName feature) if lib.wgpuDeviceHasFeature(device_id, i): features.add(f) @@ -1377,9 +1397,8 @@ def create_render_pipeline( c_depth_stencil_state = ffi.NULL if depth_stencil: - assert ( - depth_stencil.get("format", None) is not None - ), "depth_stencil needs format" + if depth_stencil.get("format", None) is None: + raise ValueError("depth_stencil needs format") stencil_front = depth_stencil.get("stencil_front", {}) check_struct("StencilFaceState", stencil_front) # H: compare: WGPUCompareFunction, failOp: WGPUStencilOperation, depthFailOp: WGPUStencilOperation, passOp: WGPUStencilOperation @@ -1600,7 +1619,10 @@ def map_write(self, data): size = self.size data = memoryview(data).cast("B") - assert data.nbytes == self.size + if data.nbytes != self.size: # pragma: no cover + raise ValueError( + "Data passed to map_write() does not have the correct size." + ) # Prepare status = 99 @@ -1749,8 +1771,8 @@ def _destroy(self): class GPUShaderModule(base.GPUShaderModule, GPUObjectBase): - def compilation_info(self): - return super().compilation_info() + def get_compilation_info(self): + return super().get_compilation_info() def _destroy(self): if self._internal is not None and lib is not None: @@ -1935,13 +1957,10 @@ class GPUCommandEncoder( base.GPUCommandEncoder, GPUCommandsMixin, GPUDebugCommandsMixin, GPUObjectBase ): def begin_compute_pass( - self, - *, - label="", - timestamp_writes: "List[structs.ComputePassTimestampWrite]" = [], + self, *, label="", timestamp_writes: "structs.ComputePassTimestampWrites" = None ): - for val in timestamp_writes: - check_struct("ComputePassTimestampWrite", val) + if timestamp_writes is not None: + check_struct("ComputePassTimestampWrites", timestamp_writes) # H: nextInChain: WGPUChainedStruct *, label: char *, timestampWriteCount: int, timestampWrites: WGPUComputePassTimestampWrite * struct = new_struct_p( "WGPUComputePassDescriptor *", @@ -1961,17 +1980,18 @@ def begin_render_pass( color_attachments: "List[structs.RenderPassColorAttachment]", depth_stencil_attachment: "structs.RenderPassDepthStencilAttachment" = None, occlusion_query_set: "GPUQuerySet" = None, - timestamp_writes: "List[structs.RenderPassTimestampWrite]" = [], + timestamp_writes: "structs.RenderPassTimestampWrites" = None, max_draw_count: int = 50000000, ): # Note that occlusion_query_set is ignored because wgpu-native does not have it. - for val in timestamp_writes: - check_struct("RenderPassTimestampWrite", val) + if timestamp_writes is not None: + check_struct("RenderPassTimestampWrites", timestamp_writes) c_color_attachments_list = [] for color_attachment in color_attachments: check_struct("RenderPassColorAttachment", color_attachment) - assert isinstance(color_attachment["view"], GPUTextureView) + if not isinstance(color_attachment["view"], GPUTextureView): + raise TypeError("Color attachement view must be a GPUTextureView.") texture_view_id = color_attachment["view"]._internal c_resolve_target = ( ffi.NULL @@ -2045,13 +2065,17 @@ def begin_render_pass( def clear_buffer(self, buffer, offset=0, size=None): offset = int(offset) - assert offset % 4 == 0, "offset must be a multiple of 4" - if size is None: + if offset % 4 != 0: # pragma: no cover + raise ValueError("offset must be a multiple of 4") + if size is None: # pragma: no cover size = buffer.size - offset size = int(size) - assert size > 0, "clear_buffer size must be > 0" - assert size % 4 == 0, "size must be a multiple of 4" - assert offset + size <= buffer.size, "buffer size out of range" + if size <= 0: # pragma: no cover + raise ValueError("clear_buffer size must be > 0") + if size % 4 != 0: # pragma: no cover + raise ValueError("size must be a multiple of 4") + if offset + size > buffer.size: # pragma: no cover + raise ValueError("buffer size out of range") # H: void f(WGPUCommandEncoder commandEncoder, WGPUBuffer buffer, uint64_t offset, uint64_t size) lib.wgpuCommandEncoderClearBuffer( self._internal, buffer._internal, int(offset), size @@ -2060,12 +2084,17 @@ def clear_buffer(self, buffer, offset=0, size=None): def copy_buffer_to_buffer( self, source, source_offset, destination, destination_offset, size ): - assert source_offset % 4 == 0, "source_offsetmust be a multiple of 4" - assert destination_offset % 4 == 0, "destination_offset must be a multiple of 4" - assert size % 4 == 0, "size must be a multiple of 4" - - assert isinstance(source, GPUBuffer) - assert isinstance(destination, GPUBuffer) + if source_offset % 4 != 0: # pragma: no cover + raise ValueError("source_offset must be a multiple of 4") + if destination_offset % 4 != 0: # pragma: no cover + raise ValueError("destination_offset must be a multiple of 4") + if size % 4 != 0: # pragma: no cover + raise ValueError("size must be a multiple of 4") + + if not isinstance(source, GPUBuffer): # pragma: no cover + raise TypeError("copy_buffer_to_buffer() source must be a GPUBuffer.") + if not isinstance(destination, GPUBuffer): # pragma: no cover + raise TypeError("copy_buffer_to_buffer() destination must be a GPUBuffer.") # H: void f(WGPUCommandEncoder commandEncoder, WGPUBuffer source, uint64_t sourceOffset, WGPUBuffer destination, uint64_t destinationOffset, uint64_t size) lib.wgpuCommandEncoderCopyBufferToBuffer( self._internal, @@ -2435,10 +2464,14 @@ def write_buffer(self, buffer, buffer_offset, data, data_offset=0, size=None): else: data_length = int(size) - assert 0 <= buffer_offset < buffer.size - assert 0 <= data_offset < nbytes - assert 0 <= data_length <= (nbytes - data_offset) - assert data_length <= buffer.size - buffer_offset + if not (0 <= buffer_offset < buffer.size): # pragma: no cover + raise ValueError("Invalid buffer_offset") + if not (0 <= data_offset < nbytes): # pragma: no cover + raise ValueError("Invalid data_offset") + if not (0 <= data_length <= (nbytes - data_offset)): # pragma: no cover + raise ValueError("Invalid data_length") + if not (data_length <= buffer.size - buffer_offset): # pragma: no cover + raise ValueError("Invalid data_length") # Make the call. Note that this call copies the data - it's ok # if we lose our reference to the data once we leave this function. @@ -2458,8 +2491,10 @@ def read_buffer(self, buffer, buffer_offset=0, size=None): data_length = buffer.size - buffer_offset else: data_length = int(size) - assert 0 <= buffer_offset < buffer.size - assert data_length <= buffer.size - buffer_offset + if not (0 <= buffer_offset < buffer.size): # pragma: no cover + raise ValueError("Invalid buffer_offset") + if not (data_length <= buffer.size - buffer_offset): # pragma: no cover + raise ValueError("Invalid data_length") device = buffer._device @@ -2647,7 +2682,7 @@ class GPUUncapturedErrorEvent(base.GPUUncapturedErrorEvent): class GPUPipelineError(base.GPUPipelineError, Exception): - def __init__(self, message, options): + def __init__(self, message="", options=None): super().__init__(message, options) diff --git a/wgpu/backends/rs_mappings.py b/wgpu/backends/rs_mappings.py index 2d4cc3b8..5eed1e6f 100644 --- a/wgpu/backends/rs_mappings.py +++ b/wgpu/backends/rs_mappings.py @@ -4,7 +4,7 @@ # flake8: noqa -# There are 231 enum mappings +# There are 227 enum mappings enummap = { "AddressMode.clamp-to-edge": 2, @@ -42,8 +42,6 @@ "CompilationMessageType.error": 0, "CompilationMessageType.info": 2, "CompilationMessageType.warning": 1, - "ComputePassTimestampLocation.beginning": 0, - "ComputePassTimestampLocation.end": 1, "CullMode.back": 2, "CullMode.front": 1, "CullMode.none": 0, @@ -79,8 +77,6 @@ "PrimitiveTopology.triangle-strip": 4, "QueryType.occlusion": 0, "QueryType.timestamp": 2, - "RenderPassTimestampLocation.beginning": 0, - "RenderPassTimestampLocation.end": 1, "SamplerBindingType.comparison": 3, "SamplerBindingType.filtering": 1, "SamplerBindingType.non-filtering": 2, @@ -240,7 +236,7 @@ "VertexStepMode.vertex": 0, } -# There are 49 struct-field enum mappings +# There are 47 struct-field enum mappings cstructfield2enum = { "BlendComponent.dstFactor": "BlendFactor", @@ -249,7 +245,6 @@ "BufferBindingLayout.type": "BufferBindingType", "ColorTargetState.format": "TextureFormat", "CompilationMessage.type": "CompilationMessageType", - "ComputePassTimestampWrite.location": "ComputePassTimestampLocation", "DepthStencilState.depthCompare": "CompareFunction", "DepthStencilState.format": "TextureFormat", "ImageCopyTexture.aspect": "TextureAspect", @@ -265,7 +260,6 @@ "RenderPassDepthStencilAttachment.depthStoreOp": "StoreOp", "RenderPassDepthStencilAttachment.stencilLoadOp": "LoadOp", "RenderPassDepthStencilAttachment.stencilStoreOp": "StoreOp", - "RenderPassTimestampWrite.location": "RenderPassTimestampLocation", "RequestAdapterOptions.powerPreference": "PowerPreference", "SamplerBindingLayout.type": "SamplerBindingType", "SamplerDescriptor.addressModeU": "AddressMode", diff --git a/wgpu/base.py b/wgpu/base.py index 47fd79af..564c9f75 100644 --- a/wgpu/base.py +++ b/wgpu/base.py @@ -1,16 +1,16 @@ """ The classes representing the wgpu API. This module defines the classes, -properties, methods and documentation. The actual methods are implemented -in backend modules. +properties, methods and documentation. The majority of methods are +implemented in backend modules. Developer notes and tips: * We follow the IDL spec, with the exception that where in JS the input args are provided via a dict, we use kwargs directly. -* However, some input args have subdicts (and sub-sub-dicts). +* Nevertheless, some input args have subdicts (and sub-sub-dicts). * For methods that are async in IDL, we also provide sync methods. * The Async method names have an "_async" suffix. -* We will try hard not to rely on asyncio. +* We will try hard not to depend on asyncio specifically. """ @@ -114,9 +114,17 @@ def get_preferred_canvas_format(self): @apidiff.add("Usefull") def print_report(self): - """Print a report about the interals if the backend.""" + """Print a report about the interals of the backend.""" print(f"{self.__class__.__module__}.GPU: No report available.") + # IDL: [SameObject] readonly attribute WGSLLanguageFeatures wgslLanguageFeatures; + @property + def wgsl_language_features(self): + """A set of strings representing the WGSL language extensions supported by all adapters. + Returns an empty set for now.""" + # Looks like at the time of writing there are no definitions for extensions yet + return set() + class GPUCanvasContext: """Represents a context to configure a canvas. @@ -884,7 +892,11 @@ def pop_error_scope(self): # IDL: GPUExternalTexture importExternalTexture(GPUExternalTextureDescriptor descriptor); @apidiff.hide("Specific to browsers.") def import_external_texture( - self, *, label="", source: object, color_space: str = "srgb" + self, + *, + label="", + source: "Union[memoryview, object]", + color_space: str = "srgb", ): """For browsers only.""" raise NotImplementedError() @@ -913,13 +925,13 @@ def __init__(self, label, internal, device, size, usage): self._usage = usage self._map_state = enums.BufferMapState.unmapped - # IDL: readonly attribute GPUSize64 size; + # IDL: readonly attribute GPUSize64Out size; @property def size(self): """The length of the GPUBuffer allocation in bytes.""" return self._size - # IDL: readonly attribute GPUBufferUsageFlags usage; + # IDL: readonly attribute GPUFlagsConstant usage; @property def usage(self): """The allowed usages (int bitmap) for this GPUBuffer, specifying @@ -1012,31 +1024,31 @@ def size(self): """The size of the texture in mipmap level 0, as a 3-tuple of ints.""" return self._tex_info["size"] - # IDL: readonly attribute GPUIntegerCoordinate width; + # IDL: readonly attribute GPUIntegerCoordinateOut width; @property def width(self): """The texture's width. Also see ``.size``.""" return self._tex_info["size"][0] - # IDL: readonly attribute GPUIntegerCoordinate height; + # IDL: readonly attribute GPUIntegerCoordinateOut height; @property def height(self): """The texture's height. Also see ``.size``.""" return self._tex_info["size"][1] - # IDL: readonly attribute GPUIntegerCoordinate depthOrArrayLayers; + # IDL: readonly attribute GPUIntegerCoordinateOut depthOrArrayLayers; @property def depth_or_array_layers(self): """The texture's depth or number of layers. Also see ``.size``.""" return self._tex_info["size"][2] - # IDL: readonly attribute GPUIntegerCoordinate mipLevelCount; + # IDL: readonly attribute GPUIntegerCoordinateOut mipLevelCount; @property def mip_level_count(self): """The total number of the mipmap levels of the texture.""" return self._tex_info["mip_level_count"] - # IDL: readonly attribute GPUSize32 sampleCount; + # IDL: readonly attribute GPUSize32Out sampleCount; @property def sample_count(self): """The number of samples in each texel of the texture.""" @@ -1054,7 +1066,7 @@ def format(self): """The format of the texture.""" return self._tex_info["format"] - # IDL: readonly attribute GPUTextureUsageFlags usage; + # IDL: readonly attribute GPUFlagsConstant usage; @property def usage(self): """The allowed usages for this texture.""" @@ -1178,16 +1190,11 @@ class GPUShaderModule(GPUObjectBase): Create a shader module using `GPUDevice.create_shader_module()`. """ - # IDL: Promise compilationInfo(); - def compilation_info(self): - """Get shader compilation info. Always returns empty string at the moment.""" + # IDL: Promise getCompilationInfo(); + def get_compilation_info(self): + """Get shader compilation info. Always returns empty list at the moment.""" return [] - # IDL: Promise compilationInfo(); - async def compilation_info_async(self): - """Async version of compilation_info()""" - return self.compilation_info() # no-cover - class GPUPipelineBase: """A mixin class for render and compute pipelines.""" @@ -1242,7 +1249,7 @@ class GPUCommandsMixin: class GPUBindingCommandsMixin: """Mixin for classes that defines bindings.""" - # IDL: undefined setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup, Uint32Array dynamicOffsetsData, GPUSize64 dynamicOffsetsDataStart, GPUSize32 dynamicOffsetsDataLength); + # IDL: undefined setBindGroup(GPUIndex32 index, GPUBindGroup? bindGroup, Uint32Array dynamicOffsetsData, GPUSize64 dynamicOffsetsDataStart, GPUSize32 dynamicOffsetsDataLength); def set_bind_group( self, index, @@ -1310,7 +1317,7 @@ def set_index_buffer(self, buffer, index_format, offset=0, size=None): """ raise NotImplementedError() - # IDL: undefined setVertexBuffer(GPUIndex32 slot, GPUBuffer buffer, optional GPUSize64 offset = 0, optional GPUSize64 size); + # IDL: undefined setVertexBuffer(GPUIndex32 slot, GPUBuffer? buffer, optional GPUSize64 offset = 0, optional GPUSize64 size); def set_vertex_buffer(self, slot, buffer, offset=0, size=None): """Associate a vertex buffer with a bind slot. @@ -1387,10 +1394,7 @@ class GPUCommandEncoder(GPUCommandsMixin, GPUDebugCommandsMixin, GPUObjectBase): # IDL: GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {}); def begin_compute_pass( - self, - *, - label="", - timestamp_writes: "List[structs.ComputePassTimestampWrite]" = [], + self, *, label="", timestamp_writes: "structs.ComputePassTimestampWrites" = None ): """Record the beginning of a compute pass. Returns a `GPUComputePassEncoder` object. @@ -1409,7 +1413,7 @@ def begin_render_pass( color_attachments: "List[structs.RenderPassColorAttachment]", depth_stencil_attachment: "structs.RenderPassDepthStencilAttachment" = None, occlusion_query_set: "GPUQuerySet" = None, - timestamp_writes: "List[structs.RenderPassTimestampWrite]" = [], + timestamp_writes: "structs.RenderPassTimestampWrites" = None, max_draw_count: int = 50000000, ): """Record the beginning of a render pass. Returns a @@ -1674,7 +1678,7 @@ def submit(self, command_buffers): """ raise NotImplementedError() - # IDL: undefined writeBuffer( GPUBuffer buffer, GPUSize64 bufferOffset, [AllowShared] BufferSource data, optional GPUSize64 dataOffset = 0, optional GPUSize64 size); + # IDL: undefined writeBuffer( GPUBuffer buffer, GPUSize64 bufferOffset, AllowSharedBufferSource data, optional GPUSize64 dataOffset = 0, optional GPUSize64 size); def write_buffer(self, buffer, buffer_offset, data, data_offset=0, size=None): """Takes the data contents and schedules a write operation of these contents to the buffer. A snapshot of the data is taken; @@ -1713,7 +1717,7 @@ def read_buffer(self, buffer, buffer_offset=0, size=None): """ raise NotImplementedError() - # IDL: undefined writeTexture( GPUImageCopyTexture destination, [AllowShared] BufferSource data, GPUImageDataLayout dataLayout, GPUExtent3D size); + # IDL: undefined writeTexture( GPUImageCopyTexture destination, AllowSharedBufferSource data, GPUImageDataLayout dataLayout, GPUExtent3D size); def write_texture(self, destination, data, data_layout, size): """Takes the data contents and schedules a write operation of these contents to the destination texture in the queue. A @@ -1779,7 +1783,7 @@ def message(self): """The error message specifying the reason for the device being lost.""" return self._message - # IDL: readonly attribute (GPUDeviceLostReason or undefined) reason; + # IDL: readonly attribute GPUDeviceLostReason reason; @property def reason(self): """The reason (enums.GPUDeviceLostReason) for the device getting lost. Can be None.""" @@ -1818,9 +1822,9 @@ def __init__(self, message): class GPUPipelineError(Exception): """An error raised when a pipeline could not be created.""" - # IDL: constructor(DOMString message, GPUPipelineErrorInit options); - def __init__(self, message, options): - super().__init__(message) + # IDL: constructor(optional DOMString message = "", GPUPipelineErrorInit options); + def __init__(self, message="", options=None): + super().__init__(message or "") self._options = options # IDL: readonly attribute GPUPipelineErrorReason reason; @@ -1909,7 +1913,7 @@ def type(self): """The type of the queries managed by this queryset.""" raise NotImplementedError() - # IDL: readonly attribute GPUSize32 count; + # IDL: readonly attribute GPUSize32Out count; @property def count(self): """The type of the queries managed by this queryset.""" @@ -1919,12 +1923,6 @@ def count(self): class GPUExternalTexture(GPUObjectBase): """Ignore this - specific to browsers.""" - # IDL: readonly attribute boolean expired; - @property - def expired(self): - """Whether the external texture has been destroyed.""" - raise NotImplementedError() - class GPUUncapturedErrorEvent: """TODO""" diff --git a/wgpu/enums.py b/wgpu/enums.py index 2b99398e..5f36e8da 100644 --- a/wgpu/enums.py +++ b/wgpu/enums.py @@ -26,7 +26,7 @@ def __repr__(self): return f"<{self.__class__.__name__} {self._name}: {options}>" -# There are 35 enums +# There are 33 enums #: * "low_power" #: * "high_performance" @@ -45,6 +45,8 @@ def __repr__(self): #: * "indirect_first_instance" #: * "shader_f16" #: * "rg11b10ufloat_renderable" +#: * "bgra8unorm_storage" +#: * "float32_filterable" FeatureName = Enum( "FeatureName", depth_clip_control="depth-clip-control", @@ -56,6 +58,8 @@ def __repr__(self): indirect_first_instance="indirect-first-instance", shader_f16="shader-f16", rg11b10ufloat_renderable="rg11b10ufloat-renderable", + bgra8unorm_storage="bgra8unorm-storage", + float32_filterable="float32-filterable", ) #: * "unmapped" @@ -129,6 +133,7 @@ def __repr__(self): #: * "bgra8unorm" #: * "bgra8unorm_srgb" #: * "rgb9e5ufloat" +#: * "rgb10a2uint" #: * "rgb10a2unorm" #: * "rg11b10ufloat" #: * "rg32uint" @@ -225,6 +230,7 @@ def __repr__(self): bgra8unorm="bgra8unorm", bgra8unorm_srgb="bgra8unorm-srgb", rgb9e5ufloat="rgb9e5ufloat", + rgb10a2uint="rgb10a2uint", rgb10a2unorm="rgb10a2unorm", rg11b10ufloat="rg11b10ufloat", rg32uint="rg32uint", @@ -540,6 +546,7 @@ def __repr__(self): #: * "sint32x2" #: * "sint32x3" #: * "sint32x4" +#: * "unorm10_10_10_2" VertexFormat = Enum( "VertexFormat", uint8x2="uint8x2", @@ -572,6 +579,7 @@ def __repr__(self): sint32x2="sint32x2", sint32x3="sint32x3", sint32x4="sint32x4", + unorm10_10_10_2="unorm10-10-10-2", ) #: * "vertex" @@ -582,22 +590,6 @@ def __repr__(self): instance="instance", ) -#: * "beginning" -#: * "end" -ComputePassTimestampLocation = Enum( - "ComputePassTimestampLocation", - beginning="beginning", - end="end", -) - -#: * "beginning" -#: * "end" -RenderPassTimestampLocation = Enum( - "RenderPassTimestampLocation", - beginning="beginning", - end="end", -) - #: * "load" #: * "clear" LoadOp = Enum( @@ -630,9 +622,11 @@ def __repr__(self): premultiplied="premultiplied", ) +#: * "unknown" #: * "destroyed" DeviceLostReason = Enum( "DeviceLostReason", + unknown="unknown", destroyed="destroyed", ) diff --git a/wgpu/resources/codegen_report.md b/wgpu/resources/codegen_report.md index 2d91d985..292d5438 100644 --- a/wgpu/resources/codegen_report.md +++ b/wgpu/resources/codegen_report.md @@ -1,12 +1,12 @@ # Code generatation report ## Preparing * The webgpu.idl defines 39 classes with 78 functions -* The webgpu.idl defines 5 flags, 35 enums, 59 structs +* The webgpu.idl defines 5 flags, 33 enums, 59 structs * The wgpu.h defines 174 functions * The wgpu.h defines 6 flags, 47 enums, 86 structs ## Updating API * Wrote 5 flags to flags.py -* Wrote 35 enums to enums.py +* Wrote 33 enums to enums.py * Wrote 59 structs to structs.py ### Patching API for base.py * Diffs for GPU: add print_report, change get_preferred_canvas_format, change request_adapter, change request_adapter_async @@ -16,16 +16,21 @@ * Diffs for GPUTexture: add size * Diffs for GPUTextureView: add size, add texture * Diffs for GPUQueue: add read_buffer, add read_texture, hide copy_external_image_to_texture -* Validated 39 classes, 112 methods, 44 properties +* Validated 39 classes, 111 methods, 44 properties ### Patching API for backends/rs.py * Diffs for GPUAdapter: add request_device_tracing * Validated 39 classes, 100 methods, 0 properties ## Validating rs.py +* Enum field FeatureName.bgra8unorm-storage missing in wgpu.h +* Enum field FeatureName.float32-filterable missing in wgpu.h * Enum BufferMapState missing in wgpu.h +* Enum field TextureFormat.rgb10a2uint missing in wgpu.h * Enum PipelineErrorReason missing in wgpu.h * Enum AutoLayoutMode missing in wgpu.h +* Enum field VertexFormat.unorm10-10-10-2 missing in wgpu.h * Enum CanvasAlphaMode missing in wgpu.h -* Wrote 231 enum mappings and 49 struct-field mappings to rs_mappings.py +* Enum field DeviceLostReason.unknown missing in wgpu.h +* Wrote 227 enum mappings and 47 struct-field mappings to rs_mappings.py * Validated 92 C function calls * Not using 90 C functions * Validated 73 C structs diff --git a/wgpu/resources/webgpu.idl b/wgpu/resources/webgpu.idl index fd209314..4a2ff55e 100644 --- a/wgpu/resources/webgpu.idl +++ b/wgpu/resources/webgpu.idl @@ -16,7 +16,7 @@ interface mixin GPUObjectBase { }; dictionary GPUObjectDescriptorBase { - USVString label; + USVString label = ""; }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -26,6 +26,7 @@ interface GPUSupportedLimits { readonly attribute unsigned long maxTextureDimension3D; readonly attribute unsigned long maxTextureArrayLayers; readonly attribute unsigned long maxBindGroups; + readonly attribute unsigned long maxBindGroupsPlusVertexBuffers; readonly attribute unsigned long maxBindingsPerBindGroup; readonly attribute unsigned long maxDynamicUniformBuffersPerPipelineLayout; readonly attribute unsigned long maxDynamicStorageBuffersPerPipelineLayout; @@ -59,6 +60,11 @@ interface GPUSupportedFeatures { readonly setlike; }; +[Exposed=(Window, DedicatedWorker), SecureContext] +interface WGSLLanguageFeatures { + readonly setlike; +}; + [Exposed=(Window, DedicatedWorker), SecureContext] interface GPUAdapterInfo { readonly attribute DOMString vendor; @@ -77,6 +83,7 @@ WorkerNavigator includes NavigatorGPU; interface GPU { Promise requestAdapter(optional GPURequestAdapterOptions options = {}); GPUTextureFormat getPreferredCanvasFormat(); + [SameObject] readonly attribute WGSLLanguageFeatures wgslLanguageFeatures; }; dictionary GPURequestAdapterOptions { @@ -86,7 +93,7 @@ dictionary GPURequestAdapterOptions { enum GPUPowerPreference { "low-power", - "high-performance" + "high-performance", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -99,7 +106,8 @@ interface GPUAdapter { Promise requestAdapterInfo(optional sequence unmaskHints = []); }; -dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase { +dictionary GPUDeviceDescriptor + : GPUObjectDescriptorBase { sequence requiredFeatures = []; record requiredLimits = {}; GPUQueueDescriptor defaultQueue = {}; @@ -114,7 +122,9 @@ enum GPUFeatureName { "timestamp-query", "indirect-first-instance", "shader-f16", - "rg11b10ufloat-renderable" + "rg11b10ufloat-renderable", + "bgra8unorm-storage", + "float32-filterable", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -150,8 +160,8 @@ GPUDevice includes GPUObjectBase; [Exposed=(Window, DedicatedWorker), SecureContext] interface GPUBuffer { - readonly attribute GPUSize64 size; - readonly attribute GPUBufferUsageFlags usage; + readonly attribute GPUSize64Out size; + readonly attribute GPUFlagsConstant usage; readonly attribute GPUBufferMapState mapState; @@ -166,17 +176,18 @@ GPUBuffer includes GPUObjectBase; enum GPUBufferMapState { "unmapped", "pending", - "mapped" + "mapped", }; -dictionary GPUBufferDescriptor : GPUObjectDescriptorBase { +dictionary GPUBufferDescriptor + : GPUObjectDescriptorBase { required GPUSize64 size; required GPUBufferUsageFlags usage; boolean mappedAtCreation = false; }; typedef [EnforceRange] unsigned long GPUBufferUsageFlags; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] namespace GPUBufferUsage { const GPUFlagsConstant MAP_READ = 0x0001; const GPUFlagsConstant MAP_WRITE = 0x0002; @@ -191,7 +202,7 @@ namespace GPUBufferUsage { }; typedef [EnforceRange] unsigned long GPUMapModeFlags; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] namespace GPUMapMode { const GPUFlagsConstant READ = 0x0001; const GPUFlagsConstant WRITE = 0x0002; @@ -203,18 +214,19 @@ interface GPUTexture { undefined destroy(); - readonly attribute GPUIntegerCoordinate width; - readonly attribute GPUIntegerCoordinate height; - readonly attribute GPUIntegerCoordinate depthOrArrayLayers; - readonly attribute GPUIntegerCoordinate mipLevelCount; - readonly attribute GPUSize32 sampleCount; + readonly attribute GPUIntegerCoordinateOut width; + readonly attribute GPUIntegerCoordinateOut height; + readonly attribute GPUIntegerCoordinateOut depthOrArrayLayers; + readonly attribute GPUIntegerCoordinateOut mipLevelCount; + readonly attribute GPUSize32Out sampleCount; readonly attribute GPUTextureDimension dimension; readonly attribute GPUTextureFormat format; - readonly attribute GPUTextureUsageFlags usage; + readonly attribute GPUFlagsConstant usage; }; GPUTexture includes GPUObjectBase; -dictionary GPUTextureDescriptor : GPUObjectDescriptorBase { +dictionary GPUTextureDescriptor + : GPUObjectDescriptorBase { required GPUExtent3D size; GPUIntegerCoordinate mipLevelCount = 1; GPUSize32 sampleCount = 1; @@ -227,11 +239,11 @@ dictionary GPUTextureDescriptor : GPUObjectDescriptorBase { enum GPUTextureDimension { "1d", "2d", - "3d" + "3d", }; typedef [EnforceRange] unsigned long GPUTextureUsageFlags; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] namespace GPUTextureUsage { const GPUFlagsConstant COPY_SRC = 0x01; const GPUFlagsConstant COPY_DST = 0x02; @@ -245,7 +257,8 @@ interface GPUTextureView { }; GPUTextureView includes GPUObjectBase; -dictionary GPUTextureViewDescriptor : GPUObjectDescriptorBase { +dictionary GPUTextureViewDescriptor + : GPUObjectDescriptorBase { GPUTextureFormat format; GPUTextureViewDimension dimension; GPUTextureAspect aspect = "all"; @@ -261,13 +274,13 @@ enum GPUTextureViewDimension { "2d-array", "cube", "cube-array", - "3d" + "3d", }; enum GPUTextureAspect { "all", "stencil-only", - "depth-only" + "depth-only", }; enum GPUTextureFormat { @@ -302,6 +315,7 @@ enum GPUTextureFormat { "bgra8unorm-srgb", // Packed 32-bit formats "rgb9e5ufloat", + "rgb10a2uint", "rgb10a2unorm", "rg11b10ufloat", @@ -387,17 +401,17 @@ enum GPUTextureFormat { "astc-12x10-unorm", "astc-12x10-unorm-srgb", "astc-12x12-unorm", - "astc-12x12-unorm-srgb" + "astc-12x12-unorm-srgb", }; [Exposed=(Window, DedicatedWorker), SecureContext] interface GPUExternalTexture { - readonly attribute boolean expired; }; GPUExternalTexture includes GPUObjectBase; -dictionary GPUExternalTextureDescriptor : GPUObjectDescriptorBase { - required HTMLVideoElement source; +dictionary GPUExternalTextureDescriptor + : GPUObjectDescriptorBase { + required (HTMLVideoElement or VideoFrame) source; PredefinedColorSpace colorSpace = "srgb"; }; @@ -406,7 +420,8 @@ interface GPUSampler { }; GPUSampler includes GPUObjectBase; -dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase { +dictionary GPUSamplerDescriptor + : GPUObjectDescriptorBase { GPUAddressMode addressModeU = "clamp-to-edge"; GPUAddressMode addressModeV = "clamp-to-edge"; GPUAddressMode addressModeW = "clamp-to-edge"; @@ -422,17 +437,17 @@ dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase { enum GPUAddressMode { "clamp-to-edge", "repeat", - "mirror-repeat" + "mirror-repeat", }; enum GPUFilterMode { "nearest", - "linear" + "linear", }; enum GPUMipmapFilterMode { "nearest", - "linear" + "linear", }; enum GPUCompareFunction { @@ -443,7 +458,7 @@ enum GPUCompareFunction { "greater", "not-equal", "greater-equal", - "always" + "always", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -451,7 +466,8 @@ interface GPUBindGroupLayout { }; GPUBindGroupLayout includes GPUObjectBase; -dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase { +dictionary GPUBindGroupLayoutDescriptor + : GPUObjectDescriptorBase { required sequence entries; }; @@ -467,7 +483,7 @@ dictionary GPUBindGroupLayoutEntry { }; typedef [EnforceRange] unsigned long GPUShaderStageFlags; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] namespace GPUShaderStage { const GPUFlagsConstant VERTEX = 0x1; const GPUFlagsConstant FRAGMENT = 0x2; @@ -477,7 +493,7 @@ namespace GPUShaderStage { enum GPUBufferBindingType { "uniform", "storage", - "read-only-storage" + "read-only-storage", }; dictionary GPUBufferBindingLayout { @@ -489,7 +505,7 @@ dictionary GPUBufferBindingLayout { enum GPUSamplerBindingType { "filtering", "non-filtering", - "comparison" + "comparison", }; dictionary GPUSamplerBindingLayout { @@ -501,7 +517,7 @@ enum GPUTextureSampleType { "unfilterable-float", "depth", "sint", - "uint" + "uint", }; dictionary GPUTextureBindingLayout { @@ -511,7 +527,7 @@ dictionary GPUTextureBindingLayout { }; enum GPUStorageTextureAccess { - "write-only" + "write-only", }; dictionary GPUStorageTextureBindingLayout { @@ -528,7 +544,8 @@ interface GPUBindGroup { }; GPUBindGroup includes GPUObjectBase; -dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase { +dictionary GPUBindGroupDescriptor + : GPUObjectDescriptorBase { required GPUBindGroupLayout layout; required sequence entries; }; @@ -551,17 +568,19 @@ interface GPUPipelineLayout { }; GPUPipelineLayout includes GPUObjectBase; -dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase { +dictionary GPUPipelineLayoutDescriptor + : GPUObjectDescriptorBase { required sequence bindGroupLayouts; }; [Exposed=(Window, DedicatedWorker), SecureContext] interface GPUShaderModule { - Promise compilationInfo(); + Promise getCompilationInfo(); }; GPUShaderModule includes GPUObjectBase; -dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase { +dictionary GPUShaderModuleDescriptor + : GPUObjectDescriptorBase { required USVString code; object sourceMap; record hints; @@ -574,7 +593,7 @@ dictionary GPUShaderModuleCompilationHint { enum GPUCompilationMessageType { "error", "warning", - "info" + "info", }; [Exposed=(Window, DedicatedWorker), Serializable, SecureContext] @@ -594,7 +613,7 @@ interface GPUCompilationInfo { [Exposed=(Window, DedicatedWorker), SecureContext, Serializable] interface GPUPipelineError : DOMException { - constructor(DOMString message, GPUPipelineErrorInit options); + constructor(optional DOMString message = "", GPUPipelineErrorInit options); readonly attribute GPUPipelineErrorReason reason; }; @@ -604,14 +623,15 @@ dictionary GPUPipelineErrorInit { enum GPUPipelineErrorReason { "validation", - "internal" + "internal", }; enum GPUAutoLayoutMode { - "auto" + "auto", }; -dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase { +dictionary GPUPipelineDescriptorBase + : GPUObjectDescriptorBase { required (GPUPipelineLayout or GPUAutoLayoutMode) layout; }; @@ -633,7 +653,8 @@ interface GPUComputePipeline { GPUComputePipeline includes GPUObjectBase; GPUComputePipeline includes GPUPipelineBase; -dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase { +dictionary GPUComputePipelineDescriptor + : GPUPipelineDescriptorBase { required GPUProgrammableStage compute; }; @@ -643,7 +664,8 @@ interface GPURenderPipeline { GPURenderPipeline includes GPUObjectBase; GPURenderPipeline includes GPUPipelineBase; -dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase { +dictionary GPURenderPipelineDescriptor + : GPUPipelineDescriptorBase { required GPUVertexState vertex; GPUPrimitiveState primitive = {}; GPUDepthStencilState depthStencil; @@ -666,18 +688,18 @@ enum GPUPrimitiveTopology { "line-list", "line-strip", "triangle-list", - "triangle-strip" + "triangle-strip", }; enum GPUFrontFace { "ccw", - "cw" + "cw", }; enum GPUCullMode { "none", "front", - "back" + "back", }; dictionary GPUMultisampleState { @@ -686,7 +708,8 @@ dictionary GPUMultisampleState { boolean alphaToCoverageEnabled = false; }; -dictionary GPUFragmentState : GPUProgrammableStage { +dictionary GPUFragmentState + : GPUProgrammableStage { required sequence targets; }; @@ -703,7 +726,7 @@ dictionary GPUBlendState { }; typedef [EnforceRange] unsigned long GPUColorWriteFlags; -[Exposed=(Window, DedicatedWorker)] +[Exposed=(Window, DedicatedWorker), SecureContext] namespace GPUColorWrite { const GPUFlagsConstant RED = 0x1; const GPUFlagsConstant GREEN = 0x2; @@ -731,7 +754,7 @@ enum GPUBlendFactor { "one-minus-dst-alpha", "src-alpha-saturated", "constant", - "one-minus-constant" + "one-minus-constant", }; enum GPUBlendOperation { @@ -739,14 +762,14 @@ enum GPUBlendOperation { "subtract", "reverse-subtract", "min", - "max" + "max", }; dictionary GPUDepthStencilState { required GPUTextureFormat format; - boolean depthWriteEnabled = false; - GPUCompareFunction depthCompare = "always"; + required boolean depthWriteEnabled; + required GPUCompareFunction depthCompare; GPUStencilFaceState stencilFront = {}; GPUStencilFaceState stencilBack = {}; @@ -774,12 +797,12 @@ enum GPUStencilOperation { "increment-clamp", "decrement-clamp", "increment-wrap", - "decrement-wrap" + "decrement-wrap", }; enum GPUIndexFormat { "uint16", - "uint32" + "uint32", }; enum GPUVertexFormat { @@ -812,15 +835,17 @@ enum GPUVertexFormat { "sint32", "sint32x2", "sint32x3", - "sint32x4" + "sint32x4", + "unorm10-10-10-2", }; enum GPUVertexStepMode { "vertex", - "instance" + "instance", }; -dictionary GPUVertexState : GPUProgrammableStage { +dictionary GPUVertexState + : GPUProgrammableStage { sequence buffers = []; }; @@ -843,7 +868,8 @@ dictionary GPUImageDataLayout { GPUSize32 rowsPerImage; }; -dictionary GPUImageCopyBuffer : GPUImageDataLayout { +dictionary GPUImageCopyBuffer + : GPUImageDataLayout { required GPUBuffer buffer; }; @@ -854,13 +880,22 @@ dictionary GPUImageCopyTexture { GPUTextureAspect aspect = "all"; }; -dictionary GPUImageCopyTextureTagged : GPUImageCopyTexture { +dictionary GPUImageCopyTextureTagged + : GPUImageCopyTexture { PredefinedColorSpace colorSpace = "srgb"; boolean premultipliedAlpha = false; }; +typedef (ImageBitmap or + ImageData or + HTMLImageElement or + HTMLVideoElement or + VideoFrame or + HTMLCanvasElement or + OffscreenCanvas) GPUImageCopyExternalImageSource; + dictionary GPUImageCopyExternalImage { - required (ImageBitmap or HTMLVideoElement or HTMLCanvasElement or OffscreenCanvas) source; + required GPUImageCopyExternalImageSource source; GPUOrigin2D origin = {}; boolean flipY = false; }; @@ -870,7 +905,8 @@ interface GPUCommandBuffer { }; GPUCommandBuffer includes GPUObjectBase; -dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase { +dictionary GPUCommandBufferDescriptor + : GPUObjectDescriptorBase { }; interface mixin GPUCommandsMixin { @@ -923,14 +959,15 @@ GPUCommandEncoder includes GPUObjectBase; GPUCommandEncoder includes GPUCommandsMixin; GPUCommandEncoder includes GPUDebugCommandsMixin; -dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase { +dictionary GPUCommandEncoderDescriptor + : GPUObjectDescriptorBase { }; interface mixin GPUBindingCommandsMixin { - undefined setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup, + undefined setBindGroup(GPUIndex32 index, GPUBindGroup? bindGroup, optional sequence dynamicOffsets = []); - undefined setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup, + undefined setBindGroup(GPUIndex32 index, GPUBindGroup? bindGroup, Uint32Array dynamicOffsetsData, GPUSize64 dynamicOffsetsDataStart, GPUSize32 dynamicOffsetsDataLength); @@ -955,21 +992,15 @@ GPUComputePassEncoder includes GPUCommandsMixin; GPUComputePassEncoder includes GPUDebugCommandsMixin; GPUComputePassEncoder includes GPUBindingCommandsMixin; -enum GPUComputePassTimestampLocation { - "beginning", - "end" -}; - -dictionary GPUComputePassTimestampWrite { +dictionary GPUComputePassTimestampWrites { required GPUQuerySet querySet; - required GPUSize32 queryIndex; - required GPUComputePassTimestampLocation location; + GPUSize32 beginningOfPassWriteIndex; + GPUSize32 endOfPassWriteIndex; }; -typedef sequence GPUComputePassTimestampWrites; - -dictionary GPUComputePassDescriptor : GPUObjectDescriptorBase { - GPUComputePassTimestampWrites timestampWrites = []; +dictionary GPUComputePassDescriptor + : GPUObjectDescriptorBase { + GPUComputePassTimestampWrites timestampWrites; }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -996,24 +1027,18 @@ GPURenderPassEncoder includes GPUDebugCommandsMixin; GPURenderPassEncoder includes GPUBindingCommandsMixin; GPURenderPassEncoder includes GPURenderCommandsMixin; -enum GPURenderPassTimestampLocation { - "beginning", - "end" -}; - -dictionary GPURenderPassTimestampWrite { +dictionary GPURenderPassTimestampWrites { required GPUQuerySet querySet; - required GPUSize32 queryIndex; - required GPURenderPassTimestampLocation location; + GPUSize32 beginningOfPassWriteIndex; + GPUSize32 endOfPassWriteIndex; }; -typedef sequence GPURenderPassTimestampWrites; - -dictionary GPURenderPassDescriptor : GPUObjectDescriptorBase { +dictionary GPURenderPassDescriptor + : GPUObjectDescriptorBase { required sequence colorAttachments; GPURenderPassDepthStencilAttachment depthStencilAttachment; GPUQuerySet occlusionQuerySet; - GPURenderPassTimestampWrites timestampWrites = []; + GPURenderPassTimestampWrites timestampWrites; GPUSize64 maxDrawCount = 50000000; }; @@ -1029,7 +1054,7 @@ dictionary GPURenderPassColorAttachment { dictionary GPURenderPassDepthStencilAttachment { required GPUTextureView view; - float depthClearValue = 0; + float depthClearValue; GPULoadOp depthLoadOp; GPUStoreOp depthStoreOp; boolean depthReadOnly = false; @@ -1042,15 +1067,16 @@ dictionary GPURenderPassDepthStencilAttachment { enum GPULoadOp { "load", - "clear" + "clear", }; enum GPUStoreOp { "store", - "discard" + "discard", }; -dictionary GPURenderPassLayout : GPUObjectDescriptorBase { +dictionary GPURenderPassLayout + : GPUObjectDescriptorBase { required sequence colorFormats; GPUTextureFormat depthStencilFormat; GPUSize32 sampleCount = 1; @@ -1060,7 +1086,7 @@ interface mixin GPURenderCommandsMixin { undefined setPipeline(GPURenderPipeline pipeline); undefined setIndexBuffer(GPUBuffer buffer, GPUIndexFormat indexFormat, optional GPUSize64 offset = 0, optional GPUSize64 size); - undefined setVertexBuffer(GPUIndex32 slot, GPUBuffer buffer, optional GPUSize64 offset = 0, optional GPUSize64 size); + undefined setVertexBuffer(GPUIndex32 slot, GPUBuffer? buffer, optional GPUSize64 offset = 0, optional GPUSize64 size); undefined draw(GPUSize32 vertexCount, optional GPUSize32 instanceCount = 1, optional GPUSize32 firstVertex = 0, optional GPUSize32 firstInstance = 0); @@ -1078,7 +1104,8 @@ interface GPURenderBundle { }; GPURenderBundle includes GPUObjectBase; -dictionary GPURenderBundleDescriptor : GPUObjectDescriptorBase { +dictionary GPURenderBundleDescriptor + : GPUObjectDescriptorBase { }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -1091,12 +1118,14 @@ GPURenderBundleEncoder includes GPUDebugCommandsMixin; GPURenderBundleEncoder includes GPUBindingCommandsMixin; GPURenderBundleEncoder includes GPURenderCommandsMixin; -dictionary GPURenderBundleEncoderDescriptor : GPURenderPassLayout { +dictionary GPURenderBundleEncoderDescriptor + : GPURenderPassLayout { boolean depthReadOnly = false; boolean stencilReadOnly = false; }; -dictionary GPUQueueDescriptor : GPUObjectDescriptorBase { +dictionary GPUQueueDescriptor + : GPUObjectDescriptorBase { }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -1108,13 +1137,13 @@ interface GPUQueue { undefined writeBuffer( GPUBuffer buffer, GPUSize64 bufferOffset, - [AllowShared] BufferSource data, + AllowSharedBufferSource data, optional GPUSize64 dataOffset = 0, optional GPUSize64 size); undefined writeTexture( GPUImageCopyTexture destination, - [AllowShared] BufferSource data, + AllowSharedBufferSource data, GPUImageDataLayout dataLayout, GPUExtent3D size); @@ -1130,18 +1159,19 @@ interface GPUQuerySet { undefined destroy(); readonly attribute GPUQueryType type; - readonly attribute GPUSize32 count; + readonly attribute GPUSize32Out count; }; GPUQuerySet includes GPUObjectBase; -dictionary GPUQuerySetDescriptor : GPUObjectDescriptorBase { +dictionary GPUQuerySetDescriptor + : GPUObjectDescriptorBase { required GPUQueryType type; required GPUSize32 count; }; enum GPUQueryType { "occlusion", - "timestamp" + "timestamp", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -1156,7 +1186,7 @@ interface GPUCanvasContext { enum GPUCanvasAlphaMode { "opaque", - "premultiplied" + "premultiplied", }; dictionary GPUCanvasConfiguration { @@ -1169,12 +1199,13 @@ dictionary GPUCanvasConfiguration { }; enum GPUDeviceLostReason { - "destroyed" + "unknown", + "destroyed", }; [Exposed=(Window, DedicatedWorker), SecureContext] interface GPUDeviceLostInfo { - readonly attribute (GPUDeviceLostReason or undefined) reason; + readonly attribute GPUDeviceLostReason reason; readonly attribute DOMString message; }; @@ -1188,24 +1219,27 @@ interface GPUError { }; [Exposed=(Window, DedicatedWorker), SecureContext] -interface GPUValidationError : GPUError { +interface GPUValidationError + : GPUError { constructor(DOMString message); }; [Exposed=(Window, DedicatedWorker), SecureContext] -interface GPUOutOfMemoryError : GPUError { +interface GPUOutOfMemoryError + : GPUError { constructor(DOMString message); }; [Exposed=(Window, DedicatedWorker), SecureContext] -interface GPUInternalError : GPUError { +interface GPUInternalError + : GPUError { constructor(DOMString message); }; enum GPUErrorFilter { "validation", "out-of-memory", - "internal" + "internal", }; partial interface GPUDevice { @@ -1242,6 +1276,10 @@ typedef [EnforceRange] unsigned long GPUIndex32; typedef [EnforceRange] unsigned long GPUSize32; typedef [EnforceRange] long GPUSignedOffset32; +typedef unsigned long long GPUSize64Out; +typedef unsigned long GPUIntegerCoordinateOut; +typedef unsigned long GPUSize32Out; + typedef unsigned long GPUFlagsConstant; dictionary GPUColorDict { diff --git a/wgpu/structs.py b/wgpu/structs.py index bdb31dc7..f116cb2e 100644 --- a/wgpu/structs.py +++ b/wgpu/structs.py @@ -34,7 +34,7 @@ def __repr__(self): force_fallback_adapter="bool", ) -#: * label :: str = None +#: * label :: str = "" #: * requiredFeatures :: List[:obj:`enums.FeatureName `] = [] #: * requiredLimits :: Dict[str, int] = {} #: * defaultQueue :: :obj:`structs.QueueDescriptor ` = {} @@ -46,7 +46,7 @@ def __repr__(self): default_queue="structs.QueueDescriptor", ) -#: * label :: str = None +#: * label :: str = "" #: * size :: int #: * usage :: :obj:`flags.BufferUsage ` #: * mappedAtCreation :: bool = false @@ -58,7 +58,7 @@ def __repr__(self): mapped_at_creation="bool", ) -#: * label :: str = None +#: * label :: str = "" #: * size :: Union[List[int], :obj:`structs.Extent3D `] #: * mipLevelCount :: int = 1 #: * sampleCount :: int = 1 @@ -78,7 +78,7 @@ def __repr__(self): view_formats="List[enums.TextureFormat]", ) -#: * label :: str = None +#: * label :: str = "" #: * format :: :obj:`enums.TextureFormat ` = None #: * dimension :: :obj:`enums.TextureViewDimension ` = None #: * aspect :: :obj:`enums.TextureAspect ` = "all" @@ -98,17 +98,17 @@ def __repr__(self): array_layer_count="int", ) -#: * label :: str = None -#: * source :: object +#: * label :: str = "" +#: * source :: Union[memoryview, object] #: * colorSpace :: str = "srgb" ExternalTextureDescriptor = Struct( "ExternalTextureDescriptor", label="str", - source="object", + source="Union[memoryview, object]", color_space="str", ) -#: * label :: str = None +#: * label :: str = "" #: * addressModeU :: :obj:`enums.AddressMode ` = "clamp-to-edge" #: * addressModeV :: :obj:`enums.AddressMode ` = "clamp-to-edge" #: * addressModeW :: :obj:`enums.AddressMode ` = "clamp-to-edge" @@ -134,7 +134,7 @@ def __repr__(self): max_anisotropy="int", ) -#: * label :: str = None +#: * label :: str = "" #: * entries :: List[:obj:`structs.BindGroupLayoutEntry `] BindGroupLayoutDescriptor = Struct( "BindGroupLayoutDescriptor", @@ -200,7 +200,7 @@ def __repr__(self): "ExternalTextureBindingLayout", ) -#: * label :: str = None +#: * label :: str = "" #: * layout :: :class:`GPUBindGroupLayout ` #: * entries :: List[:obj:`structs.BindGroupEntry `] BindGroupDescriptor = Struct( @@ -228,7 +228,7 @@ def __repr__(self): size="int", ) -#: * label :: str = None +#: * label :: str = "" #: * bindGroupLayouts :: List[:class:`GPUBindGroupLayout `] PipelineLayoutDescriptor = Struct( "PipelineLayoutDescriptor", @@ -236,7 +236,7 @@ def __repr__(self): bind_group_layouts="List[GPUBindGroupLayout]", ) -#: * label :: str = None +#: * label :: str = "" #: * code :: str #: * sourceMap :: dict = None #: * hints :: Dict[str, :obj:`structs.ShaderModuleCompilationHint `] = None @@ -270,7 +270,7 @@ def __repr__(self): constants="Dict[str, float]", ) -#: * label :: str = None +#: * label :: str = "" #: * layout :: Union[:class:`GPUPipelineLayout `, :obj:`enums.AutoLayoutMode `] #: * compute :: :obj:`structs.ProgrammableStage ` ComputePipelineDescriptor = Struct( @@ -280,7 +280,7 @@ def __repr__(self): compute="structs.ProgrammableStage", ) -#: * label :: str = None +#: * label :: str = "" #: * layout :: Union[:class:`GPUPipelineLayout `, :obj:`enums.AutoLayoutMode `] #: * vertex :: :obj:`structs.VertexState ` #: * primitive :: :obj:`structs.PrimitiveState ` = {} @@ -363,8 +363,8 @@ def __repr__(self): ) #: * format :: :obj:`enums.TextureFormat ` -#: * depthWriteEnabled :: bool = false -#: * depthCompare :: :obj:`enums.CompareFunction ` = "always" +#: * depthWriteEnabled :: bool +#: * depthCompare :: :obj:`enums.CompareFunction ` #: * stencilFront :: :obj:`structs.StencilFaceState ` = {} #: * stencilBack :: :obj:`structs.StencilFaceState ` = {} #: * stencilReadMask :: int = 0xFFFFFFFF @@ -474,51 +474,51 @@ def __repr__(self): flip_y="bool", ) -#: * label :: str = None +#: * label :: str = "" CommandBufferDescriptor = Struct( "CommandBufferDescriptor", label="str", ) -#: * label :: str = None +#: * label :: str = "" CommandEncoderDescriptor = Struct( "CommandEncoderDescriptor", label="str", ) #: * querySet :: :class:`GPUQuerySet ` -#: * queryIndex :: int -#: * location :: :obj:`enums.ComputePassTimestampLocation ` -ComputePassTimestampWrite = Struct( - "ComputePassTimestampWrite", +#: * beginningOfPassWriteIndex :: int = None +#: * endOfPassWriteIndex :: int = None +ComputePassTimestampWrites = Struct( + "ComputePassTimestampWrites", query_set="GPUQuerySet", - query_index="int", - location="enums.ComputePassTimestampLocation", + beginning_of_pass_write_index="int", + end_of_pass_write_index="int", ) -#: * label :: str = None -#: * timestampWrites :: List[:obj:`structs.ComputePassTimestampWrite `] = [] +#: * label :: str = "" +#: * timestampWrites :: :obj:`structs.ComputePassTimestampWrites ` = None ComputePassDescriptor = Struct( "ComputePassDescriptor", label="str", - timestamp_writes="List[structs.ComputePassTimestampWrite]", + timestamp_writes="structs.ComputePassTimestampWrites", ) #: * querySet :: :class:`GPUQuerySet ` -#: * queryIndex :: int -#: * location :: :obj:`enums.RenderPassTimestampLocation ` -RenderPassTimestampWrite = Struct( - "RenderPassTimestampWrite", +#: * beginningOfPassWriteIndex :: int = None +#: * endOfPassWriteIndex :: int = None +RenderPassTimestampWrites = Struct( + "RenderPassTimestampWrites", query_set="GPUQuerySet", - query_index="int", - location="enums.RenderPassTimestampLocation", + beginning_of_pass_write_index="int", + end_of_pass_write_index="int", ) -#: * label :: str = None +#: * label :: str = "" #: * colorAttachments :: List[:obj:`structs.RenderPassColorAttachment `] #: * depthStencilAttachment :: :obj:`structs.RenderPassDepthStencilAttachment ` = None #: * occlusionQuerySet :: :class:`GPUQuerySet ` = None -#: * timestampWrites :: List[:obj:`structs.RenderPassTimestampWrite `] = [] +#: * timestampWrites :: :obj:`structs.RenderPassTimestampWrites ` = None #: * maxDrawCount :: int = 50000000 RenderPassDescriptor = Struct( "RenderPassDescriptor", @@ -526,7 +526,7 @@ def __repr__(self): color_attachments="List[structs.RenderPassColorAttachment]", depth_stencil_attachment="structs.RenderPassDepthStencilAttachment", occlusion_query_set="GPUQuerySet", - timestamp_writes="List[structs.RenderPassTimestampWrite]", + timestamp_writes="structs.RenderPassTimestampWrites", max_draw_count="int", ) @@ -545,7 +545,7 @@ def __repr__(self): ) #: * view :: :class:`GPUTextureView ` -#: * depthClearValue :: float = 0 +#: * depthClearValue :: float = None #: * depthLoadOp :: :obj:`enums.LoadOp ` = None #: * depthStoreOp :: :obj:`enums.StoreOp ` = None #: * depthReadOnly :: bool = false @@ -566,7 +566,7 @@ def __repr__(self): stencil_read_only="bool", ) -#: * label :: str = None +#: * label :: str = "" #: * colorFormats :: List[:obj:`enums.TextureFormat `] #: * depthStencilFormat :: :obj:`enums.TextureFormat ` = None #: * sampleCount :: int = 1 @@ -578,13 +578,13 @@ def __repr__(self): sample_count="int", ) -#: * label :: str = None +#: * label :: str = "" RenderBundleDescriptor = Struct( "RenderBundleDescriptor", label="str", ) -#: * label :: str = None +#: * label :: str = "" #: * colorFormats :: List[:obj:`enums.TextureFormat `] #: * depthStencilFormat :: :obj:`enums.TextureFormat ` = None #: * sampleCount :: int = 1 @@ -600,13 +600,13 @@ def __repr__(self): stencil_read_only="bool", ) -#: * label :: str = None +#: * label :: str = "" QueueDescriptor = Struct( "QueueDescriptor", label="str", ) -#: * label :: str = None +#: * label :: str = "" #: * type :: :obj:`enums.QueryType ` #: * count :: int QuerySetDescriptor = Struct(