Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions codegen/wgpu_native_patcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
8 changes: 3 additions & 5 deletions tests/test_wgpu_native_basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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"])


Expand Down
29 changes: 9 additions & 20 deletions tests/test_wgpu_native_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from testutils import run_tests
from pytest import raises


dedent = lambda s: s.replace("\n ", "\n").strip()


Expand Down Expand Up @@ -36,9 +35,6 @@ def test_parse_shader_error1(caplog):
9 │ out.invalid_attr = vec4<f32>(0.0, 0.0, 1.0);
│ ^^^^^^^^^^^^ invalid accessor


invalid field accessor `invalid_attr`
"""

code = dedent(code)
Expand All @@ -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}"


Expand All @@ -72,9 +69,6 @@ def test_parse_shader_error2(caplog):
2 │ @location(0) texcoord : vec2<f32>;
│ ^ expected `,`


expected `,`, found ";"
"""

code = dedent(code)
Expand All @@ -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}"


Expand All @@ -108,9 +103,6 @@ def test_parse_shader_error3(caplog):
3 │ @builtin(position) position: vec4<f3>,
│ ^^ unknown type


unknown type: `f3`
"""

code = dedent(code)
Expand All @@ -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}"


Expand All @@ -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)
Expand All @@ -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}"


Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand All @@ -240,11 +230,10 @@ def test_validate_shader_error2(caplog):
9 │ return vec3<f32>(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)
Expand Down
8 changes: 1 addition & 7 deletions tests/test_wgpu_vertex_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions tests_mem/test_destroy.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ def test_destroy_device(n):

@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


Expand Down
2 changes: 1 addition & 1 deletion tests_mem/test_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def test_release_command_encoder(n):
yield {
"expected_counts_after_create": {
"CommandEncoder": (n, 0),
"CommandBuffer": (0, n),
# "CommandBuffer": (0, n),
},
}

Expand Down
4 changes: 2 additions & 2 deletions wgpu/backends/wgpu_native/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
27 changes: 25 additions & 2 deletions wgpu/backends/wgpu_native/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2059,6 +2059,10 @@ 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 = {}
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)
Expand All @@ -2084,10 +2088,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"),
Expand Down Expand Up @@ -4081,11 +4100,15 @@ 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
# destroy now is implemented correctly https://github.com/gfx-rs/wgpu-native/pull/509#discussion_r2403822550
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
Expand Down
10 changes: 8 additions & 2 deletions wgpu/backends/wgpu_native/_mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -371,6 +372,11 @@
"Fxc": 1,
"Dxc": 2,
},
"PolygonMode": {
"Fill": 0,
"Line": 1,
"Point": 2,
},
}

enum_int2str = {
Expand Down
16 changes: 5 additions & 11 deletions wgpu/backends/wgpu_native/extras.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
from typing import Sequence
from typing import Sequence, Union

from . import (
GPUAdapter,
Expand Down Expand Up @@ -231,8 +231,7 @@ 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,
):
"""
Expand All @@ -243,7 +242,6 @@ def set_instance_extras(
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.
"""
Expand All @@ -262,14 +260,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.
Expand Down Expand Up @@ -297,7 +292,7 @@ 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
# H: chain: WGPUChainedStruct, backends: WGPUInstanceBackend/int, flags: WGPUInstanceFlag/int, dx12ShaderCompiler: WGPUDx12Compiler, gles3MinorVersion: WGPUGles3MinorVersion, glFenceBehaviour: WGPUGLFenceBehaviour, dxcPath: WGPUStringView, dxcMaxShaderModel: WGPUDxcMaxShaderModel
c_extras = new_struct_p(
"WGPUInstanceExtras *",
# not used: chain
Expand All @@ -306,7 +301,6 @@ 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,
)
Expand Down
4 changes: 2 additions & 2 deletions wgpu/resources/codegen_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Loading
Loading