diff --git a/codegen/wgpu_native_patcher.py b/codegen/wgpu_native_patcher.py index 53270be7..0f9707c2 100644 --- a/codegen/wgpu_native_patcher.py +++ b/codegen/wgpu_native_patcher.py @@ -128,6 +128,7 @@ def write_mappings(): ("NativeFeature", True), ("PipelineStatisticName", True), ("Dx12Compiler", False), + ("PolygonMode", False), ): pylines.append(f' "{name}":' + " {") for key, val in hp.enums[name].items(): diff --git a/docs/backends.rst b/docs/backends.rst index 4db20cb9..362b3061 100644 --- a/docs/backends.rst +++ b/docs/backends.rst @@ -317,18 +317,20 @@ given in a different order in the list. :param encoder: The ComputePassEncoder or RenderPassEncoder. -.. py:function:: wgpu.backends.wgpu_native.set_instance_extras(backends, flags, dx12_compiler, gles3_minor_version, fence_behavior, dxil_path, dxc_path, dxc_max_shader_model) +.. py:function:: wgpu.backends.wgpu_native.set_instance_extras(backends, flags, dx12_compiler, gles3_minor_version, fence_behavior, dxc_path, dxc_max_shader_model, budget_for_device_creation, budget_for_device_loss) Sets the global instance with extras. Needs to be called before instance is created (in enumerate_adapters or request_adapter). + Most of these options are for specific backends, and might not create an instance or crash when used in the wrong combinations. :param backends: bitflags as list[str], which backends to enable on the instance level. Defaults to ``["All"]``. Can be any combination of ``["Vulkan", "GL", "Metal", "DX12", "BrowserWebGPU"]`` or the premade combinations ``["All", "Primary", "secondary"]``. Note that your device needs to support these backends, for detailed information see https://docs.rs/wgpu/latest/wgpu/struct.Backends.html :param flags: bitflags as list[str], debug flags for the compiler. Defaults to ``["Default"]``, can be any combination of ``["Debug", "Validation", "DiscardHalLabels"]``. :param dx12_compiler: enum/str, either "Fxc", "Dxc" or "Undefined". Defaults to "Fxc" same as "Undefined". Dxc requires additional library files. :param gles3_minor_version: enum/int 0, 1 or 2. Defaults to "Atomic" (handled by driver). :param fence_behavior: enum/int, "Normal" or "AutoFinish", Default to "Normal". - :param dxil_path: str, path to dxil.dll, defaults to ``None``. None looks in the resource directory. :param dxc_path: str, path to dxcompiler.dll, defaults to ``None``. None looks in the resource directory. :param dxc_max_shader_model: float between 6.0 and 6.7, Maximum shader model the given dll supports. Defaults to 6.5. + :param budget_for_device_creation: Optional[int], between 0 and 100, to specify memory budget threshold for when creating resources (buffer, textures...) will fail. Defaults to None. + :param budget_for_device_loss: Optional[int], between 0 and 100, to specify memory budget threshold when the device will be lost. Defaults to None. Use like the following before the instance is created, which happens during request_adapter or enumerate_adapters. diff --git a/examples/extras_dxc.py b/examples/extras_dxc.py index 4c9acc41..9771ae0a 100644 --- a/examples/extras_dxc.py +++ b/examples/extras_dxc.py @@ -17,8 +17,11 @@ "DX12" ], # using the env var `WGPU_BACKEND_TYPE` happens later during request_device, so you can only select backends that are requested for the instance dx12_compiler="Dxc", # request the Dxc compiler to be used - # dxil_path and dxc_path can be set for a custom Dxc location + # dxc_path can be set for a custom Dxc location dxc_max_shader_model=6.7, + # by setting these limits to percentages 0..100 you will get a Validation Error, should too much memory be requested. + budget_for_device_creation=99, + budget_for_device_loss=97, ) diff --git a/tests/test_wgpu_native_basics.py b/tests/test_wgpu_native_basics.py index c30229d7..df193e4d 100644 --- a/tests/test_wgpu_native_basics.py +++ b/tests/test_wgpu_native_basics.py @@ -414,8 +414,8 @@ def are_features_wgpu_legal(features): def test_features_are_legal(): # A standard feature. Probably exists assert are_features_wgpu_legal(["shader-f16"]) - # Two common extension features - assert are_features_wgpu_legal(["multi-draw-indirect", "vertex-writable-storage"]) + # A common extension feature + assert are_features_wgpu_legal(["vertex-writable-storage"]) # An uncommon extension feature. Certainly not on a mac. assert are_features_wgpu_legal(["pipeline-statistics-query"]) assert are_features_wgpu_legal( @@ -429,9 +429,7 @@ def test_features_are_legal(): def test_features_are_illegal(): # writable is misspelled - assert not are_features_wgpu_legal( - ["multi-draw-indirect", "vertex-writeable-storage"] - ) + assert not are_features_wgpu_legal(["vertex-writeable-storage"]) assert not are_features_wgpu_legal(["my-made-up-feature"]) diff --git a/tests/test_wgpu_native_errors.py b/tests/test_wgpu_native_errors.py index d3a20587..b181c377 100644 --- a/tests/test_wgpu_native_errors.py +++ b/tests/test_wgpu_native_errors.py @@ -3,7 +3,6 @@ from testutils import run_tests from pytest import raises - dedent = lambda s: s.replace("\n ", "\n").strip() @@ -36,9 +35,6 @@ def test_parse_shader_error1(caplog): │ 9 │ out.invalid_attr = vec4(0.0, 0.0, 1.0); │ ^^^^^^^^^^^^ invalid accessor - - - invalid field accessor `invalid_attr` """ code = dedent(code) @@ -47,6 +43,7 @@ def test_parse_shader_error1(caplog): device.create_shader_module(code=code) error = err.value.message + error = error.rstrip("\n") assert error == expected, f"Expected:\n\n{expected}" @@ -72,9 +69,6 @@ def test_parse_shader_error2(caplog): │ 2 │ @location(0) texcoord : vec2; │ ^ expected `,` - - - expected `,`, found ";" """ code = dedent(code) @@ -83,6 +77,7 @@ def test_parse_shader_error2(caplog): device.create_shader_module(code=code) error = err.value.message + error = error.rstrip("\n") assert error == expected, f"Expected:\n\n{expected}" @@ -108,9 +103,6 @@ def test_parse_shader_error3(caplog): │ 3 │ @builtin(position) position: vec4, │ ^^ unknown type - - - unknown type: `f3` """ code = dedent(code) @@ -119,6 +111,7 @@ def test_parse_shader_error3(caplog): device.create_shader_module(code=code) error = err.value.message + error = error.rstrip("\n") assert error == expected, f"Expected:\n\n{expected}" @@ -140,9 +133,6 @@ def test_parse_shader_error4(caplog): In wgpuDeviceCreateShaderModule Shader '' parsing error: Index 4 is out of bounds for expression [10] - - - Index 4 is out of bounds for expression [10] """ code = dedent(code) @@ -151,6 +141,7 @@ def test_parse_shader_error4(caplog): device.create_shader_module(code=code) error = err.value.message + error = error.rstrip("\n") # seems to have tailing newlines sometimes? assert error == expected, f"Expected:\n\n{expected}" @@ -191,9 +182,8 @@ def test_validate_shader_error1(caplog): = Operation Multiply can't work with [4] (of type Matrix { columns: Quad, rows: Quad, scalar: Scalar { kind: Float, width: 4 } }) and [6] (of type Vector { size: Tri, scalar: Scalar { kind: Float, width: 4 } }) - Entry point vs_main at Vertex is invalid - Expression [7] is invalid - Operation Multiply can't work with [4] (of type Matrix { columns: Quad, rows: Quad, scalar: Scalar { kind: Float, width: 4 } }) and [6] (of type Vector { size: Tri, scalar: Scalar { kind: Float, width: 4 } }) + Expression [7] is invalid + Operation Multiply can't work with [4] (of type Matrix { columns: Quad, rows: Quad, scalar: Scalar { kind: Float, width: 4 } }) and [6] (of type Vector { size: Tri, scalar: Scalar { kind: Float, width: 4 } }) """ code = dedent(code) @@ -227,7 +217,7 @@ def test_validate_shader_error2(caplog): } """ - expected1 = """Returning Some(Vector { size: Tri, scalar: Scalar { kind: Float, width: 4 } }) where Some(Vector { size: Quad, scalar: Scalar { kind: Float, width: 4 } }) is expected""" + expected1 = """Returning Some(Handle([3])) where Some([0]) is expected""" expected2 = """ Validation Error @@ -240,11 +230,10 @@ def test_validate_shader_error2(caplog): 9 │ return vec3(1.0, 0.0, 1.0); │ ^^^^^^^^^^^^^^^^^^^^^^^^ naga::ir::Expression [8] │ - = The `return` value Some([8]) does not match the function return value + = The `return` expression Some([8]) does not match the declared return type Some([0]) - Entry point fs_main at Vertex is invalid - The `return` value Some([8]) does not match the function return value + The `return` expression Some([8]) does not match the declared return type Some([0]) """ code = dedent(code) diff --git a/tests/test_wgpu_vertex_instance.py b/tests/test_wgpu_vertex_instance.py index 69b7ed1b..2114e7d2 100644 --- a/tests/test_wgpu_vertex_instance.py +++ b/tests/test_wgpu_vertex_instance.py @@ -70,7 +70,7 @@ class Runner: REQUIRED_FEATURES = ["indirect-first-instance"] - OPTIONAL_FEATURES = ["multi-draw-indirect", "multi-draw-indirect-count"] + OPTIONAL_FEATURES = ["multi-draw-indirect-count"] @classmethod def is_usable(cls): @@ -263,9 +263,6 @@ def draw(encoder): def test_multi_draw_indirect(runner): - if "multi-draw-indirect" not in runner.device.features: - pytest.skip("Must have 'multi-draw-indirect' to run") - def draw(encoder): multi_draw_indirect(encoder, runner.draw_data_buffer, offset=8, count=2) @@ -329,9 +326,6 @@ def draw(encoder): def test_multi_draw_indexed_indirect(runner): - if "multi-draw-indirect" not in runner.device.features: - pytest.skip("Must have 'multi-draw-indirect' to run") - def draw(encoder): multi_draw_indexed_indirect( encoder, runner.draw_data_buffer_indexed, offset=8, count=2 diff --git a/tests_mem/test_destroy.py b/tests_mem/test_destroy.py index 18489743..d923ea1d 100644 --- a/tests_mem/test_destroy.py +++ b/tests_mem/test_destroy.py @@ -28,17 +28,27 @@ def test_destroy_device(n): for i in range(n): d = adapter.request_device_sync() d.destroy() - # NOTE: destroy is not yet implemented in wgpu-native - this does not actually do anything yet + # d.destroy() # fine to call multiple times + + # Uncomment the following lines to see. These are commented because it makes wgpu-core create a buffer. + # error = None + # try: + # d.create_buffer(size=128, usage=wgpu.BufferUsage.UNIFORM) + # except wgpu.GPUValidationError as err: + # error = err + # assert error and "device is lost" in error.message.lower() + yield d @create_and_release def test_destroy_query_set(n): - yield {} + yield { + "expected_counts_after_create": {"QuerySet": (n, 0)}, + } for i in range(n): qs = DEVICE.create_query_set(type=wgpu.QueryType.occlusion, count=2) qs.destroy() - # NOTE: destroy is not yet implemented in wgpu-native - this does not actually do anything yet yield qs @@ -56,11 +66,12 @@ def test_destroy_buffer(n): # can still be queries from wgpu-native, but it cannot be used. # Uncomment the following lines to see. These are commented because it makes wgpu-core create a command-buffer. + # error = None # try: # b.map_sync("READ") # except wgpu.GPUValidationError as err: # error = err - # assert "destroyed" in error.message.lower() + # assert error and "destroyed" in error.message.lower() yield b @@ -77,11 +88,13 @@ def test_destroy_texture(n): t.destroy() # Uncomment the following lines to see. These are commented because the views are created at the native side, but we never store them, but we also don't release them. + # error = None # try: # t.create_view() # except wgpu.GPUValidationError as err: # error = err - # assert "destroyed" in error.message.lower() + # assert error and "destroyed" in error.message.lower() + yield t diff --git a/tests_mem/test_objects.py b/tests_mem/test_objects.py index 94303bbc..74f18ca5 100644 --- a/tests_mem/test_objects.py +++ b/tests_mem/test_objects.py @@ -126,7 +126,7 @@ def test_release_command_encoder(n): yield { "expected_counts_after_create": { "CommandEncoder": (n, 0), - "CommandBuffer": (0, n), + # "CommandBuffer": (0, n), }, } diff --git a/tools/download_dxc.py b/tools/download_dxc.py index bf10d3ba..ac1a2063 100644 --- a/tools/download_dxc.py +++ b/tools/download_dxc.py @@ -59,11 +59,8 @@ def main(version=None): print(f"Downloading {url}") download_file(url, zip_filename) compiler_file = "dxcompiler.dll" - signing_file = "dxil.dll" # in v26 this won't be needed anymore print(f"Extracting {compiler_file} to {RESOURCE_DIR}") extract_file(zip_filename, compiler_file, RESOURCE_DIR) - print(f"Extracting {signing_file} to {RESOURCE_DIR}") - extract_file(zip_filename, signing_file, RESOURCE_DIR) # cleanup of tempfile? # os.remove(zip_filename) diff --git a/wgpu/_classes.py b/wgpu/_classes.py index 3823d065..07bae307 100644 --- a/wgpu/_classes.py +++ b/wgpu/_classes.py @@ -1146,12 +1146,14 @@ def create_render_pipeline( vertex (structs.VertexState): Describes the vertex shader entry point of the pipeline and its input buffer layouts. primitive (structs.PrimitiveState): Describes the primitive-related properties - of the pipeline. If `strip_index_format` is present (which means the + of the pipeline. If ``strip_index_format`` is present (which means the primitive topology is a strip), and the drawCall is indexed, the vertex index list is split into sub-lists using the maximum value of this index format as a separator. Example: a list with values - `[1, 2, 65535, 4, 5, 6]` of type "uint16" will be split in sub-lists - `[1, 2]` and `[4, 5, 6]`. + ``[1, 2, 65535, 4, 5, 6]`` of type "uint16" will be split in sub-lists + ``[1, 2]`` and ``[4, 5, 6]``. + If the native-only features "polygon-mode-line" or "polygon-mode-point" are requested, an additional field in the primitive state + ``polygon_mode`` can be set to "line" or "point" respectively. However this requires the use of a dict and not `structs.PrimitiveState`. depth_stencil (structs.DepthStencilState): Describes the optional depth-stencil properties, including the testing, operations, and bias. Optional. multisample (structs.MultisampleState): Describes the multi-sampling properties of the pipeline. diff --git a/wgpu/backends/wgpu_native/__init__.py b/wgpu/backends/wgpu_native/__init__.py index ae7d62e5..d4735f57 100644 --- a/wgpu/backends/wgpu_native/__init__.py +++ b/wgpu/backends/wgpu_native/__init__.py @@ -11,8 +11,8 @@ # The wgpu-native version that we target/expect -__version__ = "25.0.2.2" -__commit_sha__ = "a2f5109b0da3c87d356a6a876f5b203c6a68924a" +__version__ = "27.0.2.0" +__commit_sha__ = "74f8c24c903b6352d09f1928c56962ce06f77a4d" version_info = tuple(map(int, __version__.split("."))) # noqa: RUF048 _check_expected_version(version_info) # produces a warning on mismatch diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index 59a4110f..ba633053 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -2059,6 +2059,12 @@ def _create_render_pipeline_descriptor( depth_stencil = depth_stencil or {} multisample = multisample or {} primitive = primitive or {} + # remove the extras so the struct can still be checked + primitive_extras = {} + if isinstance(primitive, dict): + # in case of extras, the struct isn't used but a dict... so we check for it here. + primitive_extras["polygon_mode"] = primitive.pop("polygon_mode", "Fill") + primitive_extras["conservative"] = primitive.pop("conservative", False) check_struct("VertexState", vertex) check_struct("DepthStencilState", depth_stencil) check_struct("MultisampleState", multisample) @@ -2084,10 +2090,25 @@ def _create_render_pipeline_descriptor( buffers=c_vertex_buffer_descriptors_array, ) + # explanations for extras: https://docs.rs/wgpu/latest/wgpu/struct.PrimitiveState.html + polygon_mode = enum_str2int["PolygonMode"].get( + primitive_extras.get("polygon_mode"), enum_str2int["PolygonMode"]["Fill"] + ) + + # H: chain: WGPUChainedStruct, polygonMode: WGPUPolygonMode, conservative: WGPUBool/int + c_primitive_state_extras = new_struct_p( + "WGPUPrimitiveStateExtras *", + # not used: chain + polygonMode=polygon_mode, + conservative=primitive_extras.get("conservative", False), + ) + c_primitive_state_extras.chain.sType = lib.WGPUSType_PrimitiveStateExtras + next_in_chain = ffi.cast("WGPUChainedStruct *", c_primitive_state_extras) + # H: nextInChain: WGPUChainedStruct *, topology: WGPUPrimitiveTopology, stripIndexFormat: WGPUIndexFormat, frontFace: WGPUFrontFace, cullMode: WGPUCullMode, unclippedDepth: WGPUBool/int c_primitive_state = new_struct( "WGPUPrimitiveState", - # not used: nextInChain + nextInChain=next_in_chain, topology=primitive.get("topology", "triangle-list"), stripIndexFormat=primitive.get("strip_index_format", 0), frontFace=primitive.get("front_face", "ccw"), @@ -2354,7 +2375,8 @@ async def _get_lost_async(self): raise NotImplementedError() def destroy(self) -> None: - # Note: not yet implemented in wgpu-core, the wgpu-native func is a noop + # NOTE: destroy means that the wgpu-core object gets into a destroyed state. The wgpu-core object still exists. + # Therefore we must not set self._internal to None. internal = self._internal if internal is not None: # H: void f(WGPUDevice device) @@ -2611,9 +2633,8 @@ def _experimental_get_mapped_range(self, buffer_offset=None, size=None): return src_m def destroy(self) -> None: - # NOTE: destroy means that the wgpu-core object gets into a destroyed - # state. The wgpu-core object still exists. So destroying is quite - # different from releasing. + # NOTE: destroy means that the wgpu-core object gets into a destroyed state. The wgpu-core object still exists. + # Therefore we must not set self._internal to None. internal = self._internal if internal is not None: # H: void f(WGPUBuffer buffer) @@ -2682,6 +2703,8 @@ def create_view( return GPUTextureView(label, id, self._device, self, self.size) def destroy(self) -> None: + # NOTE: destroy means that the wgpu-core object gets into a destroyed state. The wgpu-core object still exists. + # Therefore we must not set self._internal to None. internal = self._internal if internal is not None: # H: void f(WGPUTexture texture) @@ -4081,11 +4104,28 @@ class GPUQuerySet(classes.GPUQuerySet, GPUObjectBase): _release_function = libf.wgpuQuerySetRelease def destroy(self) -> None: - # Note: not yet implemented in wgpu-core, the wgpu-native func is a noop + # NOTE: wgpuQuerySetDestroy is currently not implemented incorrectly https://github.com/gfx-rs/wgpu-native/pull/509#discussion_r2403822550 + # It calls `drop` instead, i.e. does the same as wgpuQuerySetRelease. This means that we must set self._internal to None. + # But this means that if we'd call wgpuQuerySetDestroy, and wgpu-native gets fixed, we get a leak :( + # So instead we make it explicitly do the same as release. + # TODO: remove this when wgpu-native actually uses destroy. + wgpu_native_uses_drop = True + if wgpu_native_uses_drop: + self._release() + return + + # Below is the eventual code for this method: + + # NOTE: destroy means that the wgpu-core object gets into a destroyed state. The wgpu-core object still exists. + # Therefore we must not set self._internal to None. internal = self._internal if internal is not None: # H: void f(WGPUQuerySet querySet) libf.wgpuQuerySetDestroy(internal) + # if we call del objects during our tests on the "destroyed" object, we get a panic + # by setting this to none, the __del__ call via _release skips it. + # might mean we retain memory tho? + self._internal = None # %% Subclasses that don't need anything else diff --git a/wgpu/backends/wgpu_native/_mappings.py b/wgpu/backends/wgpu_native/_mappings.py index db3b932c..9d3987e0 100644 --- a/wgpu/backends/wgpu_native/_mappings.py +++ b/wgpu/backends/wgpu_native/_mappings.py @@ -330,7 +330,6 @@ "NativeFeature": { "push-constants": 196609, "texture-adapter-specific-format-features": 196610, - "multi-draw-indirect": 196611, "multi-draw-indirect-count": 196612, "vertex-writable-storage": 196613, "texture-binding-array": 196614, @@ -343,10 +342,12 @@ "mappable-primary-buffers": 196622, "buffer-binding-array": 196623, "uniform-buffer-and-storage-texture-array-non-uniform-indexing": 196624, + "polygon-mode-line": 196627, + "polygon-mode-point": 196628, + "conservative-rasterization": 196629, "spirv-shader-passthrough": 196631, "vertex-attribute64bit": 196633, "texture-format-nv12": 196634, - "ray-tracing-acceleration-structure": 196635, "ray-query": 196636, "shader-f64": 196637, "shader-i16": 196638, @@ -371,6 +372,11 @@ "Fxc": 1, "Dxc": 2, }, + "PolygonMode": { + "Fill": 0, + "Line": 1, + "Point": 2, + }, } enum_int2str = { diff --git a/wgpu/backends/wgpu_native/extras.py b/wgpu/backends/wgpu_native/extras.py index d4e01843..75383c15 100644 --- a/wgpu/backends/wgpu_native/extras.py +++ b/wgpu/backends/wgpu_native/extras.py @@ -1,5 +1,5 @@ import os -from typing import Sequence +from typing import Sequence, Union from . import ( GPUAdapter, @@ -24,7 +24,7 @@ from ...enums import Enum from ._helpers import get_wgpu_instance from ..._coreutils import get_library_filename, ArrayLike -from ._ffi import lib +from ._ffi import lib, ffi from ._mappings import native_flags @@ -231,21 +231,24 @@ def set_instance_extras( dx12_compiler="fxc", gles3_minor_version="Atomic", fence_behavior="Normal", - dxil_path: os.PathLike | None = None, - dxc_path: os.PathLike | None = None, + dxc_path: Union[os.PathLike, None] = None, dxc_max_shader_model: float = 6.5, + budget_for_device_creation: Union[int, None] = None, + budget_for_device_loss: Union[int, None] = None, ): """ Sets the global instance with extras. Needs to be called before instance is created (in enumerate_adapters or request_adapter). + Most of these options are for specific backends, and might not create an instance or crash when used in the wrong combinations. Args: backends: bitflags as list[str], which backends to enable on the instance level. Defaults to ``["All"]``. flags: bitflags as list[str], for debugging the instance and compiler. Defaults to ``["Default"]``. dx12_compiler: enum/str, either "Fxc", "Dxc" or "Undefined". Defaults to "Fxc" same as "Undefined". Dxc requires additional library files. gles3_minor_version: enum/int, 0, 1 or 2. Defaults to "Atomic" (handled by driver). fence_behavior: enum/int, "Normal" or "AutoFinish". Defaults to "Normal". - dxil_path: Path to the dxil.dll file, if not provided or `None`, will try to load from wgpu/resources. dxc_path: Path to the dxcompiler.dll file, if not provided or `None`, will try to load from wgpu/resources. dxc_max_shader_model: float between 6.0 and 6.7, the maximum shader model to use with DXC. Defaults to 6.5. + budget_for_device_creation: Optional[int], between 0 and 100, to specify memory budget threshold for when creating resources (buffer, textures...) will fail. Defaults to None. + budget_for_device_loss: Optional[int], between 0 and 100, to specify memory budget threshold when the device will be lost. Defaults to None. """ # TODO document and explain, add examples @@ -262,14 +265,11 @@ def set_instance_extras( dx12_compiler.capitalize(), enum_str2int["Dx12Compiler"]["Undefined"] ) # https://docs.rs/wgpu/latest/wgpu/enum.Dx12Compiler.html#variant.DynamicDxc #explains the idea, will improve in the future. - # https://github.com/gfx-rs/wgpu-native/blob/v25.0.2.1/src/conv.rs#L308-L349 handles the fxc fallback, most of the time... if ( - c_dx12_compiler == enum_str2int["Dx12Compiler"]["Dxc"] - and not (dxil_path or dxc_path) - ): # os.path.exists(dxil_path) or os.path.exists(dxc_path)): # this check errors with None as default. but we can't have empty strings. + c_dx12_compiler == enum_str2int["Dx12Compiler"]["Dxc"] and not dxc_path + ): # or os.path.exists(dxc_path)): # this check errors with None as default. but we can't have empty strings. # if dxc is specified but no paths are provided, there will be a panic about static-dxc, so maybe we check against that. try: - dxil_path = get_library_filename("dxil.dll") dxc_path = get_library_filename("dxcompiler.dll") except RuntimeError as e: # here we couldn't load the libs from wgpu/resources... so we assume the user doesn't have them. @@ -297,7 +297,19 @@ def set_instance_extras( # hack as only version 6.0..6.7 are supported and enum mapping fits. c_max_shader_model = int((dxc_max_shader_model - 6.0) * 1.0) - # H: chain: WGPUChainedStruct, backends: WGPUInstanceBackend/int, flags: WGPUInstanceFlag/int, dx12ShaderCompiler: WGPUDx12Compiler, gles3MinorVersion: WGPUGles3MinorVersion, glFenceBehaviour: WGPUGLFenceBehaviour, dxilPath: WGPUStringView, dxcPath: WGPUStringView, dxcMaxShaderModel: WGPUDxcMaxShaderModel + # https://docs.rs/wgpu/latest/wgpu/struct.MemoryBudgetThresholds.html + c_budget_creation = ( + ffi.new("uint8_t *", budget_for_device_creation) + if budget_for_device_creation is not None + else ffi.NULL + ) + c_budget_loss = ( + ffi.new("uint8_t *", budget_for_device_loss) + if budget_for_device_loss is not None + else ffi.NULL + ) + + # H: chain: WGPUChainedStruct, backends: WGPUInstanceBackend/int, flags: WGPUInstanceFlag/int, dx12ShaderCompiler: WGPUDx12Compiler, gles3MinorVersion: WGPUGles3MinorVersion, glFenceBehaviour: WGPUGLFenceBehaviour, dxcPath: WGPUStringView, dxcMaxShaderModel: WGPUDxcMaxShaderModel, const uint8_t* budgetForDeviceCreation, const uint8_t* budgetForDeviceLoss c_extras = new_struct_p( "WGPUInstanceExtras *", # not used: chain @@ -306,9 +318,10 @@ def set_instance_extras( dx12ShaderCompiler=c_dx12_compiler, gles3MinorVersion=gles3_minor_version, glFenceBehaviour=fence_behavior, - dxilPath=to_c_string_view(dxil_path), dxcPath=to_c_string_view(dxc_path), dxcMaxShaderModel=c_max_shader_model, + budgetForDeviceCreation=c_budget_creation, + budgetForDeviceLoss=c_budget_loss, ) c_extras.chain.sType = lib.WGPUSType_InstanceExtras diff --git a/wgpu/resources/codegen_report.md b/wgpu/resources/codegen_report.md index 297319df..9b2c882c 100644 --- a/wgpu/resources/codegen_report.md +++ b/wgpu/resources/codegen_report.md @@ -3,7 +3,7 @@ * The webgpu.idl defines 37 classes with 76 functions * The webgpu.idl defines 5 flags, 34 enums, 60 structs * webgpu.h/wgpu.h define 211 functions -* webgpu.h/wgpu.h define 7 flags, 60 enums, 102 structs +* webgpu.h/wgpu.h define 7 flags, 61 enums, 103 structs ## Updating API * Wrote 5 flags to flags.py * Wrote 34 enums to enums.py @@ -41,4 +41,4 @@ * Wrote 255 enum mappings and 47 struct-field mappings to wgpu_native/_mappings.py * Validated 151 C function calls * Not using 69 C functions -* Validated 95 C structs +* Validated 96 C structs diff --git a/wgpu/resources/wgpu.h b/wgpu/resources/wgpu.h index 2adc5c0b..272ed23a 100644 --- a/wgpu/resources/wgpu.h +++ b/wgpu/resources/wgpu.h @@ -15,13 +15,13 @@ typedef enum WGPUNativeSType { WGPUSType_QuerySetDescriptorExtras = 0x00030009, WGPUSType_SurfaceConfigurationExtras = 0x0003000A, WGPUSType_SurfaceSourceSwapChainPanel = 0x0003000B, + WGPUSType_PrimitiveStateExtras = 0x0003000C, WGPUNativeSType_Force32 = 0x7FFFFFFF } WGPUNativeSType; typedef enum WGPUNativeFeature { WGPUNativeFeature_PushConstants = 0x00030001, WGPUNativeFeature_TextureAdapterSpecificFormatFeatures = 0x00030002, - WGPUNativeFeature_MultiDrawIndirect = 0x00030003, WGPUNativeFeature_MultiDrawIndirectCount = 0x00030004, WGPUNativeFeature_VertexWritableStorage = 0x00030005, WGPUNativeFeature_TextureBindingArray = 0x00030006, @@ -37,15 +37,14 @@ typedef enum WGPUNativeFeature { // TODO: requires wgpu.h api change // WGPUNativeFeature_AddressModeClampToZero = 0x00030011, // WGPUNativeFeature_AddressModeClampToBorder = 0x00030012, - // WGPUNativeFeature_PolygonModeLine = 0x00030013, - // WGPUNativeFeature_PolygonModePoint = 0x00030014, - // WGPUNativeFeature_ConservativeRasterization = 0x00030015, + WGPUNativeFeature_PolygonModeLine = 0x00030013, + WGPUNativeFeature_PolygonModePoint = 0x00030014, + WGPUNativeFeature_ConservativeRasterization = 0x00030015, // WGPUNativeFeature_ClearTexture = 0x00030016, WGPUNativeFeature_SpirvShaderPassthrough = 0x00030017, // WGPUNativeFeature_Multiview = 0x00030018, WGPUNativeFeature_VertexAttribute64bit = 0x00030019, WGPUNativeFeature_TextureFormatNv12 = 0x0003001A, - WGPUNativeFeature_RayTracingAccelerationStructure = 0x0003001B, WGPUNativeFeature_RayQuery = 0x0003001C, WGPUNativeFeature_ShaderF64 = 0x0003001D, WGPUNativeFeature_ShaderI16 = 0x0003001E, @@ -145,9 +144,11 @@ typedef struct WGPUInstanceExtras { WGPUDx12Compiler dx12ShaderCompiler; WGPUGles3MinorVersion gles3MinorVersion; WGPUGLFenceBehaviour glFenceBehaviour; - WGPUStringView dxilPath; WGPUStringView dxcPath; WGPUDxcMaxShaderModel dxcMaxShaderModel; + + WGPU_NULLABLE const uint8_t* budgetForDeviceCreation; + WGPU_NULLABLE const uint8_t* budgetForDeviceLoss; } WGPUInstanceExtras; typedef struct WGPUDeviceExtras { @@ -259,17 +260,29 @@ typedef struct WGPUSurfaceConfigurationExtras { } WGPUSurfaceConfigurationExtras WGPU_STRUCTURE_ATTRIBUTE; /** - * Chained in @ref WGPUSurfaceDescriptor to make a @ref WGPUSurface wrapping a WinUI [`SwapChainPanel`](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swapchainpanel). - */ +* Chained in @ref WGPUSurfaceDescriptor to make a @ref WGPUSurface wrapping a WinUI [`SwapChainPanel`](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swapchainpanel). +*/ typedef struct WGPUSurfaceSourceSwapChainPanel { WGPUChainedStruct chain; /** - * A pointer to the [`ISwapChainPanelNative`](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/win32/microsoft.ui.xaml.media.dxinterop/nn-microsoft-ui-xaml-media-dxinterop-iswapchainpanelnative) - * interface of the SwapChainPanel that will be wrapped by the @ref WGPUSurface. - */ + * A pointer to the [`ISwapChainPanelNative`](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/win32/microsoft.ui.xaml.media.dxinterop/nn-microsoft-ui-xaml-media-dxinterop-iswapchainpanelnative) + * interface of the SwapChainPanel that will be wrapped by the @ref WGPUSurface. + */ void * panelNative; } WGPUSurfaceSourceSwapChainPanel WGPU_STRUCTURE_ATTRIBUTE; +typedef enum WGPUPolygonMode { + WGPUPolygonMode_Fill = 0, + WGPUPolygonMode_Line = 1, + WGPUPolygonMode_Point = 2, +} WGPUPolygonMode; + +typedef struct WGPUPrimitiveStateExtras { + WGPUChainedStruct chain; + WGPUPolygonMode polygonMode; + WGPUBool conservative; +} WGPUPrimitiveStateExtras WGPU_STRUCTURE_ATTRIBUTE; + typedef void (*WGPULogCallback)(WGPULogLevel level, WGPUStringView message, void * userdata); typedef enum WGPUNativeTextureFormat { @@ -282,8 +295,10 @@ typedef enum WGPUNativeTextureFormat { WGPUNativeTextureFormat_Rgba16Snorm = 0x00030006, // From Features::TEXTURE_FORMAT_NV12 WGPUNativeTextureFormat_NV12 = 0x00030007, + WGPUNativeTextureFormat_P010 = 0x00030008, } WGPUNativeTextureFormat; + #ifdef __cplusplus extern "C" { #endif