From fc7ae307bcbdacb2e8a7ec7f0800d1e3c13927bb Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 24 May 2025 01:57:07 +0200 Subject: [PATCH 01/19] update prerelease header --- wgpu/backends/wgpu_native/__init__.py | 4 ++-- wgpu/resources/wgpu.h | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/wgpu/backends/wgpu_native/__init__.py b/wgpu/backends/wgpu_native/__init__.py index 44b06449..239e5721 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__ = "24.0.3.1" -__commit_sha__ = "e305465e8f1abd2b13878274bf74bbde920096a3" +__version__ = "25.0.0.1" +__commit_sha__ = "059cb334dd07650d30ff58d10d5155766ea4376b" #+ recommended renames version_info = tuple(map(int, __version__.split("."))) # noqa: RUF048 _check_expected_version(version_info) # produces a warning on mismatch diff --git a/wgpu/resources/wgpu.h b/wgpu/resources/wgpu.h index 6cee9d15..edc9a54f 100644 --- a/wgpu/resources/wgpu.h +++ b/wgpu/resources/wgpu.h @@ -118,14 +118,34 @@ typedef enum WGPUNativeQueryType { WGPUNativeQueryType_Force32 = 0x7FFFFFFF } WGPUNativeQueryType WGPU_ENUM_ATTRIBUTE; +typedef enum WGPUDxcMaxShaderModel { + WGPUDxcMaxShaderModel_V6_0 = 0x00000000, + WGPUDxcMaxShaderModel_V6_1 = 0x00000001, + WGPUDxcMaxShaderModel_V6_2 = 0x00000002, + WGPUDxcMaxShaderModel_V6_3 = 0x00000003, + WGPUDxcMaxShaderModel_V6_4 = 0x00000004, + WGPUDxcMaxShaderModel_V6_5 = 0x00000005, + WGPUDxcMaxShaderModel_V6_6 = 0x00000006, + WGPUDxcMaxShaderModel_V6_7 = 0x00000007, + WGPUDxcMaxShaderModel_Force32 = 0x7FFFFFFF +} WGPUDxcMaxShaderModel; + +typedef enum WGPUGLFenceBehaviour { + WGPUGLFenceBehaviour_Normal = 0x00000000, + WGPUGLFenceBehaviour_AutoFinish = 0x00000001, + WGPUGLFenceBehaviour_Force32 = 0x7FFFFFFF +} WGPUGLFenceBehaviour; + typedef struct WGPUInstanceExtras { WGPUChainedStruct chain; WGPUInstanceBackend backends; WGPUInstanceFlag flags; WGPUDx12Compiler dx12ShaderCompiler; WGPUGles3MinorVersion gles3MinorVersion; + WGPUGLFenceBehaviour glFenceBehaviour; WGPUStringView dxilPath; WGPUStringView dxcPath; + WGPUDxcMaxShaderModel dxcMaxShaderModel; } WGPUInstanceExtras; typedef struct WGPUDeviceExtras { From f7862349a3eda6ab3e3ba6ff311c16ab77ae7116 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 24 May 2025 02:02:42 +0200 Subject: [PATCH 02/19] run codegen --- wgpu/resources/codegen_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu/resources/codegen_report.md b/wgpu/resources/codegen_report.md index 6424e09a..d76ca5ba 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 * The wgpu.h defines 211 functions -* The wgpu.h defines 7 flags, 58 enums, 101 structs +* The wgpu.h defines 7 flags, 60 enums, 101 structs ## Updating API * Wrote 5 flags to flags.py * Wrote 34 enums to enums.py From 8d1c81ae9b30ec9c30ba8dac8bfda42cf98ee413 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 25 May 2025 02:03:43 +0200 Subject: [PATCH 03/19] fix feature level --- tools/download_wgpu_native.py | 2 +- wgpu/_classes.py | 10 +++++++--- wgpu/backends/wgpu_native/_api.py | 12 ++++++------ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/tools/download_wgpu_native.py b/tools/download_wgpu_native.py index abb32b57..978479f8 100644 --- a/tools/download_wgpu_native.py +++ b/tools/download_wgpu_native.py @@ -149,7 +149,7 @@ def main(version=None, os_string=None, arch=None, upstream=None): current_version = get_current_version() if version != current_version: - print(f"Version changed, updating {VERSION_FILE}") + print(f"Version changed, updating {VERSION_FILE}, diff: https://github.com/{upstream}/compare/v{current_version}...v{version}") filename = "commit-sha" url = f"https://github.com/{upstream}/releases/download/v{version}/{filename}" commit_sha_filename = os.path.join(tmp, filename) diff --git a/wgpu/_classes.py b/wgpu/_classes.py index 83ac8214..7ef724d6 100644 --- a/wgpu/_classes.py +++ b/wgpu/_classes.py @@ -92,7 +92,7 @@ class GPU: def request_adapter_sync( self, *, - feaure_level: str = "core", + feature_level: str = "core", power_preference: enums.PowerPreference = None, force_fallback_adapter: bool = False, canvas=None, @@ -105,6 +105,7 @@ def request_adapter_sync( from .backends.auto import gpu return gpu.request_adapter_sync( + feature_level=feature_level, power_preference=power_preference, force_fallback_adapter=force_fallback_adapter, canvas=canvas, @@ -115,7 +116,7 @@ def request_adapter_sync( async def request_adapter_async( self, *, - feaure_level: str = "core", + feature_level: str = "core", power_preference: enums.PowerPreference = None, force_fallback_adapter: bool = False, canvas=None, @@ -124,7 +125,7 @@ async def request_adapter_async( implementation, from which one can request a `GPUDevice`. Arguments: - feaure_level (str): The feature level "core" (default) or "compatibility". + feature_level (str): The feature level "core" (default) or "compatibility". This provides a way to opt into additional validation restrictions. power_preference (PowerPreference): "high-performance" or "low-power". force_fallback_adapter (bool): whether to use a (probably CPU-based) @@ -135,7 +136,10 @@ async def request_adapter_async( # If this method gets called, no backend has been loaded yet, let's do that now! from .backends.auto import gpu + # note, feature_level current' does nothing: # not used currently: https://gpuweb.github.io/gpuweb/#dom-gpurequestadapteroptions-featurelevel + return await gpu.request_adapter_async( + feature_level=feature_level, power_preference=power_preference, force_fallback_adapter=force_fallback_adapter, canvas=canvas, diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index b9077ca3..729b2674 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -427,7 +427,7 @@ class GPU(classes.GPU): def request_adapter_sync( self, *, - feaure_level: str = "core", + feature_level: str = "core", power_preference: enums.PowerPreference = None, force_fallback_adapter: bool = False, canvas=None, @@ -437,7 +437,7 @@ def request_adapter_sync( """ check_can_use_sync_variants() awaitable = self._request_adapter( - feaure_level=feaure_level, + feature_level=feature_level, power_preference=power_preference, force_fallback_adapter=force_fallback_adapter, canvas=canvas, @@ -448,7 +448,7 @@ def request_adapter_sync( async def request_adapter_async( self, *, - feaure_level: str = "core", + feature_level: str = "core", power_preference: enums.PowerPreference = None, force_fallback_adapter: bool = False, canvas=None, @@ -466,7 +466,7 @@ async def request_adapter_async( be left to None. If given, the object must implement ``WgpuCanvasInterface``. """ awaitable = self._request_adapter( - feaure_level=feaure_level, + feature_level=feature_level, power_preference=power_preference, force_fallback_adapter=force_fallback_adapter, canvas=canvas, @@ -474,7 +474,7 @@ async def request_adapter_async( return await awaitable def _request_adapter( - self, *, feaure_level, power_preference, force_fallback_adapter, canvas + self, *, feature_level, power_preference, force_fallback_adapter, canvas ): # Similar to https://github.com/gfx-rs/wgpu?tab=readme-ov-file#environment-variables # It seems that the environment variables are only respected in their @@ -527,7 +527,7 @@ def _request_adapter( c_feature_level = { "core": lib.WGPUFeatureLevel_Core, "compatibility": lib.WGPUFeatureLevel_Compatibility, - }[feaure_level] + }[feature_level] # H: nextInChain: WGPUChainedStruct *, featureLevel: WGPUFeatureLevel, powerPreference: WGPUPowerPreference, forceFallbackAdapter: WGPUBool/int, backendType: WGPUBackendType, compatibleSurface: WGPUSurface struct = new_struct_p( From 79afaf5cbf930945e6587e5ddf4c5d1d1604fb4b Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 May 2025 00:39:07 +0200 Subject: [PATCH 04/19] force dxc --- wgpu/backends/wgpu_native/_api.py | 19 +++++++++++++++++-- wgpu/backends/wgpu_native/_helpers.py | 7 +++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index 729b2674..2540764d 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -314,6 +314,21 @@ def check_struct(struct_name, d): if invalid_keys: raise ValueError(f"Invalid keys in {struct_name}: {invalid_keys}") +# forcing in the dynamic dx12 compiler to see if it works... +dxil_path = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxil.dll" +dxc_path = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxcompiler.dll" + +_instance_extras = new_struct_p("WGPUInstanceExtras *", + backends = 8 , #lib.WGPUInstanceBackend_DX12, #TODO: this isn't evaluated for importing or available in flags.py + dx12ShaderCompiler = lib.WGPUDx12Compiler_Dxc, + dxilPath = to_c_string_view(dxil_path), + dxcPath = to_c_string_view(dxc_path), + dxcMaxShaderModel = lib.WGPUDxcMaxShaderModel_V6_7, + flags=3,#lib.WGPUInstanceFlag_Debug, # figure out if this works or not. + ) +_instance_extras.chain.sType = lib.WGPUSType_InstanceExtras +def get_wgpu_instance_dx12(): + return get_wgpu_instance(extras=_instance_extras) def _get_limits(id: int, device: bool = False, adapter: bool = False): """Gets the limits for a device or an adapter""" @@ -570,7 +585,7 @@ def finalizer(adapter_id): ) # H: WGPUFuture f(WGPUInstance instance, WGPURequestAdapterOptions const * options, WGPURequestAdapterCallbackInfo callbackInfo) - libf.wgpuInstanceRequestAdapter(get_wgpu_instance(), struct, callback_info) + libf.wgpuInstanceRequestAdapter(get_wgpu_instance_dx12(), struct, callback_info) return awaitable @@ -591,7 +606,7 @@ def _enumerate_adapters(self): # The first call is to get the number of adapters, and the second call # is to get the actual adapters. Note that the second arg (now NULL) can # be a `WGPUInstanceEnumerateAdapterOptions` to filter by backend. - instance = get_wgpu_instance() + instance = get_wgpu_instance_dx12() # H: size_t f(WGPUInstance instance, WGPUInstanceEnumerateAdapterOptions const * options, WGPUAdapter * adapters) count = libf.wgpuInstanceEnumerateAdapters(instance, ffi.NULL, ffi.NULL) adapters = new_array("WGPUAdapter[]", count) diff --git a/wgpu/backends/wgpu_native/_helpers.py b/wgpu/backends/wgpu_native/_helpers.py index 7a6d0f94..f243fb18 100644 --- a/wgpu/backends/wgpu_native/_helpers.py +++ b/wgpu/backends/wgpu_native/_helpers.py @@ -29,7 +29,6 @@ "Internal": GPUInternalError, } - if sys.platform.startswith("darwin"): from rubicon.objc.api import ObjCInstance, ObjCClass @@ -87,14 +86,18 @@ def get_memoryview_from_address(address, nbytes, format="B"): _the_instance = None -def get_wgpu_instance(): +def get_wgpu_instance(extras=None): """Get the global wgpu instance.""" # Note, we could also use wgpuInstanceRelease, # but we keep a global instance, so we don't have to. global _the_instance + if _the_instance is None: + print("requested without extras!") # H: nextInChain: WGPUChainedStruct * struct = ffi.new("WGPUInstanceDescriptor *") + if extras is not None: + struct.nextInChain = ffi.cast("WGPUChainedStruct *", extras) _the_instance = lib.wgpuCreateInstance(struct) return _the_instance From 48831fa3bf08b5cc7c28811a9ce6ffbe2909c9f8 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 May 2025 00:42:41 +0200 Subject: [PATCH 05/19] fix marker placement --- wgpu/backends/wgpu_native/_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu/backends/wgpu_native/_helpers.py b/wgpu/backends/wgpu_native/_helpers.py index f243fb18..aefef0b3 100644 --- a/wgpu/backends/wgpu_native/_helpers.py +++ b/wgpu/backends/wgpu_native/_helpers.py @@ -93,10 +93,10 @@ def get_wgpu_instance(extras=None): global _the_instance if _the_instance is None: - print("requested without extras!") # H: nextInChain: WGPUChainedStruct * struct = ffi.new("WGPUInstanceDescriptor *") if extras is not None: + print("requested with extras!") struct.nextInChain = ffi.cast("WGPUChainedStruct *", extras) _the_instance = lib.wgpuCreateInstance(struct) return _the_instance From 14c357a77ee6a855838851180fd80f8ed8eec6bf Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 May 2025 00:44:18 +0200 Subject: [PATCH 06/19] revert version info --- wgpu/backends/wgpu_native/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wgpu/backends/wgpu_native/__init__.py b/wgpu/backends/wgpu_native/__init__.py index 239e5721..44b06449 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.0.1" -__commit_sha__ = "059cb334dd07650d30ff58d10d5155766ea4376b" #+ recommended renames +__version__ = "24.0.3.1" +__commit_sha__ = "e305465e8f1abd2b13878274bf74bbde920096a3" version_info = tuple(map(int, __version__.split("."))) # noqa: RUF048 _check_expected_version(version_info) # produces a warning on mismatch From 5f29ec8b1b6aa6ef2926ee0c1405de8216ce7bb5 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 May 2025 00:46:53 +0200 Subject: [PATCH 07/19] update to release --- wgpu/backends/wgpu_native/__init__.py | 4 ++-- wgpu/resources/wgpu.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/wgpu/backends/wgpu_native/__init__.py b/wgpu/backends/wgpu_native/__init__.py index 44b06449..499fe75f 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__ = "24.0.3.1" -__commit_sha__ = "e305465e8f1abd2b13878274bf74bbde920096a3" +__version__ = "25.0.2.1" +__commit_sha__ = "af9074edf144efe4f1432b2e42c477429c4964c1" version_info = tuple(map(int, __version__.split("."))) # noqa: RUF048 _check_expected_version(version_info) # produces a warning on mismatch diff --git a/wgpu/resources/wgpu.h b/wgpu/resources/wgpu.h index edc9a54f..ec12da35 100644 --- a/wgpu/resources/wgpu.h +++ b/wgpu/resources/wgpu.h @@ -8,7 +8,7 @@ typedef enum WGPUNativeSType { WGPUSType_DeviceExtras = 0x00030001, WGPUSType_NativeLimits = 0x00030002, WGPUSType_PipelineLayoutExtras = 0x00030003, - WGPUSType_ShaderModuleGLSLDescriptor = 0x00030004, + WGPUSType_ShaderSourceGLSL = 0x00030004, WGPUSType_InstanceExtras = 0x00030006, WGPUSType_BindGroupEntryExtras = 0x00030007, WGPUSType_BindGroupLayoutEntryExtras = 0x00030008, @@ -179,13 +179,13 @@ typedef struct WGPUShaderDefine { WGPUStringView value; } WGPUShaderDefine; -typedef struct WGPUShaderModuleGLSLDescriptor { +typedef struct WGPUShaderSourceGLSL { WGPUChainedStruct chain; WGPUShaderStage stage; WGPUStringView code; uint32_t defineCount; WGPUShaderDefine * defines; -} WGPUShaderModuleGLSLDescriptor; +} WGPUShaderSourceGLSL; typedef struct WGPUShaderModuleDescriptorSpirV { WGPUStringView label; @@ -280,7 +280,7 @@ size_t wgpuInstanceEnumerateAdapters(WGPUInstance instance, WGPU_NULLABLE WGPUIn WGPUSubmissionIndex wgpuQueueSubmitForIndex(WGPUQueue queue, size_t commandCount, WGPUCommandBuffer const * commands); // Returns true if the queue is empty, or false if there are more queue submissions still in flight. -WGPUBool wgpuDevicePoll(WGPUDevice device, WGPUBool wait, WGPU_NULLABLE WGPUSubmissionIndex const * wrappedSubmissionIndex); +WGPUBool wgpuDevicePoll(WGPUDevice device, WGPUBool wait, WGPU_NULLABLE WGPUSubmissionIndex const * submissionIndex); WGPUShaderModule wgpuDeviceCreateShaderModuleSpirV(WGPUDevice device, WGPUShaderModuleDescriptorSpirV const * descriptor); void wgpuSetLogCallback(WGPULogCallback callback, void * userdata); From d161c47272a14079fcb5be8db5abb3e5e7d03133 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 May 2025 00:48:56 +0200 Subject: [PATCH 08/19] run codegen --- wgpu/backends/wgpu_native/_api.py | 31 ++++++++++++++++++++----------- wgpu/resources/codegen_report.md | 3 ++- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index 2540764d..385bb756 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -314,22 +314,31 @@ def check_struct(struct_name, d): if invalid_keys: raise ValueError(f"Invalid keys in {struct_name}: {invalid_keys}") + # forcing in the dynamic dx12 compiler to see if it works... dxil_path = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxil.dll" dxc_path = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxcompiler.dll" -_instance_extras = new_struct_p("WGPUInstanceExtras *", - backends = 8 , #lib.WGPUInstanceBackend_DX12, #TODO: this isn't evaluated for importing or available in flags.py - dx12ShaderCompiler = lib.WGPUDx12Compiler_Dxc, - dxilPath = to_c_string_view(dxil_path), - dxcPath = to_c_string_view(dxc_path), - dxcMaxShaderModel = lib.WGPUDxcMaxShaderModel_V6_7, - flags=3,#lib.WGPUInstanceFlag_Debug, # figure out if this works or not. - ) +# H: chain: WGPUChainedStruct, backends: WGPUInstanceBackend/int, flags: WGPUInstanceFlag/int, dx12ShaderCompiler: WGPUDx12Compiler, gles3MinorVersion: WGPUGles3MinorVersion, glFenceBehaviour: WGPUGLFenceBehaviour, dxilPath: WGPUStringView, dxcPath: WGPUStringView, dxcMaxShaderModel: WGPUDxcMaxShaderModel +_instance_extras = new_struct_p( + "WGPUInstanceExtras *", + backends=8, # lib.WGPUInstanceBackend_DX12, #TODO: this isn't evaluated for importing or available in flags.py + dx12ShaderCompiler=lib.WGPUDx12Compiler_Dxc, + dxilPath=to_c_string_view(dxil_path), + dxcPath=to_c_string_view(dxc_path), + dxcMaxShaderModel=lib.WGPUDxcMaxShaderModel_V6_7, + flags=3, # lib.WGPUInstanceFlag_Debug, # figure out if this works or not. + # not used: chain + # not used: gles3MinorVersion + # not used: glFenceBehaviour +) _instance_extras.chain.sType = lib.WGPUSType_InstanceExtras + + def get_wgpu_instance_dx12(): return get_wgpu_instance(extras=_instance_extras) + def _get_limits(id: int, device: bool = False, adapter: bool = False): """Gets the limits for a device or an adapter""" assert device + adapter == 1 # exactly one is set @@ -1371,12 +1380,12 @@ class GPUDevice(classes.GPUDevice, GPUObjectBase): def _poll(self): # Internal function if self._internal: - # H: WGPUBool f(WGPUDevice device, WGPUBool wait, WGPUSubmissionIndex const * wrappedSubmissionIndex) + # H: WGPUBool f(WGPUDevice device, WGPUBool wait, WGPUSubmissionIndex const * submissionIndex) libf.wgpuDevicePoll(self._internal, False, ffi.NULL) def _poll_wait(self): if self._internal: - # H: WGPUBool f(WGPUDevice device, WGPUBool wait, WGPUSubmissionIndex const * wrappedSubmissionIndex) + # H: WGPUBool f(WGPUDevice device, WGPUBool wait, WGPUSubmissionIndex const * submissionIndex) libf.wgpuDevicePoll(self._internal, True, ffi.NULL) def create_buffer( @@ -1787,7 +1796,7 @@ def create_shader_module( ) ) # note, GLSL is a wgpu-native feature and still uses the older structure! - # H: chain: WGPUChainedStruct, stage: WGPUShaderStage/int, code: WGPUStringView, defineCount: int, defines: WGPUShaderDefine * + # FIXME: unknown C struct WGPUShaderModuleGLSLDescriptor source_struct = new_struct_p( "WGPUShaderModuleGLSLDescriptor *", code=to_c_string_view(code), diff --git a/wgpu/resources/codegen_report.md b/wgpu/resources/codegen_report.md index d76ca5ba..0ab6d50a 100644 --- a/wgpu/resources/codegen_report.md +++ b/wgpu/resources/codegen_report.md @@ -31,4 +31,5 @@ * 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 +* ERROR: unknown C struct WGPUShaderModuleGLSLDescriptor +* Validated 96 C structs From ee58bf68208918ab9e709fd233d18221b9f0aca4 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 May 2025 00:55:08 +0200 Subject: [PATCH 09/19] fix GLSL module --- wgpu/backends/wgpu_native/_api.py | 9 ++++----- wgpu/resources/codegen_report.md | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index 385bb756..d0676c59 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -1795,18 +1795,17 @@ def create_shader_module( value=to_c_string_view("gl_VertexIndex"), ) ) - # note, GLSL is a wgpu-native feature and still uses the older structure! - # FIXME: unknown C struct WGPUShaderModuleGLSLDescriptor + # H: chain: WGPUChainedStruct, stage: WGPUShaderStage/int, code: WGPUStringView, defineCount: int, defines: WGPUShaderDefine * source_struct = new_struct_p( - "WGPUShaderModuleGLSLDescriptor *", + "WGPUShaderSourceGLSL *", + # not used: chain code=to_c_string_view(code), stage=c_stage, defineCount=len(defines), defines=new_array("WGPUShaderDefine[]", defines), - # not used: chain ) source_struct[0].chain.next = ffi.NULL - source_struct[0].chain.sType = lib.WGPUSType_ShaderModuleGLSLDescriptor + source_struct[0].chain.sType = lib.WGPUSType_ShaderSourceGLSL else: # === WGSL # H: chain: WGPUChainedStruct, code: WGPUStringView diff --git a/wgpu/resources/codegen_report.md b/wgpu/resources/codegen_report.md index 0ab6d50a..d24a73ca 100644 --- a/wgpu/resources/codegen_report.md +++ b/wgpu/resources/codegen_report.md @@ -31,5 +31,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 -* ERROR: unknown C struct WGPUShaderModuleGLSLDescriptor * Validated 96 C structs From bb53024e9629624568b7b7eaba527ab7140e4b01 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 May 2025 01:08:06 +0200 Subject: [PATCH 10/19] disable instance extras for CI --- wgpu/backends/wgpu_native/_api.py | 4 ++-- wgpu/backends/wgpu_native/_helpers.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index d0676c59..8549ee73 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -594,7 +594,7 @@ def finalizer(adapter_id): ) # H: WGPUFuture f(WGPUInstance instance, WGPURequestAdapterOptions const * options, WGPURequestAdapterCallbackInfo callbackInfo) - libf.wgpuInstanceRequestAdapter(get_wgpu_instance_dx12(), struct, callback_info) + libf.wgpuInstanceRequestAdapter(get_wgpu_instance(), struct, callback_info) return awaitable @@ -615,7 +615,7 @@ def _enumerate_adapters(self): # The first call is to get the number of adapters, and the second call # is to get the actual adapters. Note that the second arg (now NULL) can # be a `WGPUInstanceEnumerateAdapterOptions` to filter by backend. - instance = get_wgpu_instance_dx12() + instance = get_wgpu_instance() # H: size_t f(WGPUInstance instance, WGPUInstanceEnumerateAdapterOptions const * options, WGPUAdapter * adapters) count = libf.wgpuInstanceEnumerateAdapters(instance, ffi.NULL, ffi.NULL) adapters = new_array("WGPUAdapter[]", count) diff --git a/wgpu/backends/wgpu_native/_helpers.py b/wgpu/backends/wgpu_native/_helpers.py index aefef0b3..38c61574 100644 --- a/wgpu/backends/wgpu_native/_helpers.py +++ b/wgpu/backends/wgpu_native/_helpers.py @@ -96,7 +96,6 @@ def get_wgpu_instance(extras=None): # H: nextInChain: WGPUChainedStruct * struct = ffi.new("WGPUInstanceDescriptor *") if extras is not None: - print("requested with extras!") struct.nextInChain = ffi.cast("WGPUChainedStruct *", extras) _the_instance = lib.wgpuCreateInstance(struct) return _the_instance From bb3594e37ccc3e735502109f107b14913de749bf Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 May 2025 01:11:26 +0200 Subject: [PATCH 11/19] update error messages --- tests/test_wgpu_native_errors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_wgpu_native_errors.py b/tests/test_wgpu_native_errors.py index 90447787..d3a20587 100644 --- a/tests/test_wgpu_native_errors.py +++ b/tests/test_wgpu_native_errors.py @@ -185,7 +185,7 @@ def test_validate_shader_error1(caplog): ┌─ :10:20 │ 10 │ out.position = matrics * out.position; - │ ^^^^^^^^^^^^^^^^^^^^^^ naga::Expression [7] + │ ^^^^^^^^^^^^^^^^^^^^^^ naga::ir::Expression [7] │ = 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 } }) @@ -238,7 +238,7 @@ def test_validate_shader_error2(caplog): ┌─ :9:16 │ 9 │ return vec3(1.0, 0.0, 1.0); - │ ^^^^^^^^^^^^^^^^^^^^^^^^ naga::Expression [8] + │ ^^^^^^^^^^^^^^^^^^^^^^^^ naga::ir::Expression [8] │ = The `return` value Some([8]) does not match the function return value From d5ee586b35d7175257472da3297f9f365cb6c0ed Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 May 2025 01:25:42 +0200 Subject: [PATCH 12/19] ruff format --- tools/download_wgpu_native.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/download_wgpu_native.py b/tools/download_wgpu_native.py index 978479f8..76432579 100644 --- a/tools/download_wgpu_native.py +++ b/tools/download_wgpu_native.py @@ -149,7 +149,9 @@ def main(version=None, os_string=None, arch=None, upstream=None): current_version = get_current_version() if version != current_version: - print(f"Version changed, updating {VERSION_FILE}, diff: https://github.com/{upstream}/compare/v{current_version}...v{version}") + print( + f"Version changed, updating {VERSION_FILE}, diff: https://github.com/{upstream}/compare/v{current_version}...v{version}" + ) filename = "commit-sha" url = f"https://github.com/{upstream}/releases/download/v{version}/{filename}" commit_sha_filename = os.path.join(tmp, filename) From 3c4f8a4d97d661dee78771f63acdd835fac307d9 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 30 May 2025 02:53:35 +0200 Subject: [PATCH 13/19] move instance extras --- examples/cube.py | 7 ++++ wgpu/backends/wgpu_native/_api.py | 25 +------------ wgpu/backends/wgpu_native/extras.py | 56 ++++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/examples/cube.py b/examples/cube.py index 506f1c0e..ffb25c71 100644 --- a/examples/cube.py +++ b/examples/cube.py @@ -14,6 +14,8 @@ import wgpu import numpy as np +from wgpu.backends.wgpu_native.extras import set_instance_extras + from rendercanvas.auto import RenderCanvas, loop @@ -455,6 +457,11 @@ async def draw_frame_async(): uniform_data = np.zeros((), dtype=uniform_dtype) +# TODO: remove testing code +set_instance_extras( + backends=1 << 3 # DX12 only +) + print("Available adapters on this system:") for a in wgpu.gpu.enumerate_adapters_sync(): print(a.summary) diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index 8549ee73..71074856 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -315,30 +315,6 @@ def check_struct(struct_name, d): raise ValueError(f"Invalid keys in {struct_name}: {invalid_keys}") -# forcing in the dynamic dx12 compiler to see if it works... -dxil_path = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxil.dll" -dxc_path = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxcompiler.dll" - -# H: chain: WGPUChainedStruct, backends: WGPUInstanceBackend/int, flags: WGPUInstanceFlag/int, dx12ShaderCompiler: WGPUDx12Compiler, gles3MinorVersion: WGPUGles3MinorVersion, glFenceBehaviour: WGPUGLFenceBehaviour, dxilPath: WGPUStringView, dxcPath: WGPUStringView, dxcMaxShaderModel: WGPUDxcMaxShaderModel -_instance_extras = new_struct_p( - "WGPUInstanceExtras *", - backends=8, # lib.WGPUInstanceBackend_DX12, #TODO: this isn't evaluated for importing or available in flags.py - dx12ShaderCompiler=lib.WGPUDx12Compiler_Dxc, - dxilPath=to_c_string_view(dxil_path), - dxcPath=to_c_string_view(dxc_path), - dxcMaxShaderModel=lib.WGPUDxcMaxShaderModel_V6_7, - flags=3, # lib.WGPUInstanceFlag_Debug, # figure out if this works or not. - # not used: chain - # not used: gles3MinorVersion - # not used: glFenceBehaviour -) -_instance_extras.chain.sType = lib.WGPUSType_InstanceExtras - - -def get_wgpu_instance_dx12(): - return get_wgpu_instance(extras=_instance_extras) - - def _get_limits(id: int, device: bool = False, adapter: bool = False): """Gets the limits for a device or an adapter""" assert device + adapter == 1 # exactly one is set @@ -1290,6 +1266,7 @@ def device_lost_callback(c_device, c_reason, c_message, userdata1, userdata2): def uncaptured_error_callback( c_device, c_type, c_message, userdata1, userdata2 ): + # TODO: does this always raise an exception? retest the loop cases! error_type = enum_int2str["ErrorType"].get(c_type, "Unknown") msg = from_c_string_view(c_message) msg = "\n".join(line.rstrip() for line in msg.splitlines()) diff --git a/wgpu/backends/wgpu_native/extras.py b/wgpu/backends/wgpu_native/extras.py index 4662460c..0133fa99 100644 --- a/wgpu/backends/wgpu_native/extras.py +++ b/wgpu/backends/wgpu_native/extras.py @@ -2,8 +2,17 @@ from typing import List from . import GPUCommandEncoder, GPUComputePassEncoder, GPURenderPassEncoder -from ._api import Dict, GPUBindGroupLayout, enums, logger, structs +from ._api import ( + Dict, + GPUBindGroupLayout, + enums, + logger, + structs, + new_struct_p, + to_c_string_view, +) from ...enums import Enum +from ._helpers import get_wgpu_instance # NOTE: these functions represent backend-specific extra API. @@ -172,3 +181,48 @@ def write_timestamp(encoder, query_set, query_index): encoder, (GPURenderPassEncoder, GPUComputePassEncoder, GPUCommandEncoder) ) encoder._write_timestamp(query_set, query_index) + + +def set_instance_extras( + backends=0, # default all + flags=0, + dx12_compiler="fxc", # default, alternative "dxc" + gles3_minor_version=0, + fence_behavior=0, + dxil_path: os.PathLike | None = None, + dxc_path: os.PathLike | None = None, + dxc_max_shader_model: float = 6.5, +): + """ + Sets the global instance with extras. + """ + # TODO document and explain, find reference for defaults + + # maybe include wgpu.h enums and flags in our codegen? (especially make sure to evaluate the flags) + compiler_map = { + "undefined": 0, # lib.WGPUDx12Compiler_Undefined + "fxc": 1, # lib.WGPUDx12Compiler_Fxc + "dxc": 2, # lib.WGPUDx12Compiler_Dxc + } + c_dx12_compiler = compiler_map.get(dx12_compiler, 0) # default to "undefined"? + # the rust conv layer does all the checking, so fallbacks are handled there. + + # TODO: translate to C enums/flags + # H: chain: WGPUChainedStruct, backends: WGPUInstanceBackend/int, flags: WGPUInstanceFlag/int, dx12ShaderCompiler: WGPUDx12Compiler, gles3MinorVersion: WGPUGles3MinorVersion, glFenceBehaviour: WGPUGLFenceBehaviour, dxilPath: WGPUStringView, dxcPath: WGPUStringView, dxcMaxShaderModel: WGPUDxcMaxShaderModel + c_extras = new_struct_p( + "WGPUInstanceExtras *", + # not used: chain + backends=backends, + flags=flags, # lib.WGPUInstanceFlag_Debug, # figure out if this works or not. + 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=lib.WGPUDxcMaxShaderModel_V6_5, + ) + + c_extras.chain.sType = ( + 0x00030006 # lib.WGPUSType_InstanceExtras (but we don't import lib here?) + ) + get_wgpu_instance(extras=c_extras) # this sets a global From a6ee33ed43a41cd9b4893ee9b36972cfeaa81de6 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 30 May 2025 03:54:47 +0200 Subject: [PATCH 14/19] add compiler enum --- codegen/wgpu_native_patcher.py | 2 ++ examples/cube.py | 8 ++++++-- wgpu/backends/wgpu_native/_mappings.py | 5 +++++ wgpu/backends/wgpu_native/extras.py | 25 ++++++++++++++++--------- wgpu/resources/codegen_report.md | 2 +- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/codegen/wgpu_native_patcher.py b/codegen/wgpu_native_patcher.py index e85e9efb..09896cc3 100644 --- a/codegen/wgpu_native_patcher.py +++ b/codegen/wgpu_native_patcher.py @@ -70,6 +70,7 @@ def write_mappings(): idl = get_idl_parser() hp = get_h_parser() + # these are empty and have no use? name_map = {} name_map_i = {v: k for k, v in name_map.items()} @@ -126,6 +127,7 @@ def write_mappings(): ("BackendType", False), ("NativeFeature", True), ("PipelineStatisticName", True), + ("Dx12Compiler", False), ): pylines.append(f' "{name}":' + " {") for key, val in hp.enums[name].items(): diff --git a/examples/cube.py b/examples/cube.py index ffb25c71..c5374413 100644 --- a/examples/cube.py +++ b/examples/cube.py @@ -457,9 +457,13 @@ async def draw_frame_async(): uniform_data = np.zeros((), dtype=uniform_dtype) -# TODO: remove testing code +# TODO: remove testing code, this is all needed to use the Dxc compiler set_instance_extras( - backends=1 << 3 # DX12 only + backends=1 << 3, # DX12 only: notice how it lists fewer adapters below + dx12_compiler="dxc", + dxil_path=r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxil.dll", + dxc_path=r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxcompiler.dll", + dxc_max_shader_model=6.7, ) print("Available adapters on this system:") diff --git a/wgpu/backends/wgpu_native/_mappings.py b/wgpu/backends/wgpu_native/_mappings.py index 42057149..c4273beb 100644 --- a/wgpu/backends/wgpu_native/_mappings.py +++ b/wgpu/backends/wgpu_native/_mappings.py @@ -365,6 +365,11 @@ "fragment-shader-invocations": 3, "compute-shader-invocations": 4, }, + "Dx12Compiler": { + "Undefined": 0, + "Fxc": 1, + "Dxc": 2, + }, } enum_int2str = { diff --git a/wgpu/backends/wgpu_native/extras.py b/wgpu/backends/wgpu_native/extras.py index 0133fa99..80189c08 100644 --- a/wgpu/backends/wgpu_native/extras.py +++ b/wgpu/backends/wgpu_native/extras.py @@ -10,6 +10,7 @@ structs, new_struct_p, to_c_string_view, + enum_str2int, ) from ...enums import Enum from ._helpers import get_wgpu_instance @@ -198,14 +199,20 @@ def set_instance_extras( """ # TODO document and explain, find reference for defaults - # maybe include wgpu.h enums and flags in our codegen? (especially make sure to evaluate the flags) - compiler_map = { - "undefined": 0, # lib.WGPUDx12Compiler_Undefined - "fxc": 1, # lib.WGPUDx12Compiler_Fxc - "dxc": 2, # lib.WGPUDx12Compiler_Dxc - } - c_dx12_compiler = compiler_map.get(dx12_compiler, 0) # default to "undefined"? + c_dx12_compiler = enum_str2int["Dx12Compiler"].get( + dx12_compiler.capitalize(), enum_str2int["Dx12Compiler"]["Undefined"] + ) # default to "undefined"? # the rust conv layer does all the checking, so fallbacks are handled there. + 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. + # if dxc is specified but no paths are provided, there will be a panic about static-dxc, so maybe we check against that. + # TODO: warning maybe? - can we overwrite this ourself to force fxc instead? + c_dx12_compiler = enum_str2int["Dx12Compiler"]["Undefined"] + + # 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) # TODO: translate to C enums/flags # H: chain: WGPUChainedStruct, backends: WGPUInstanceBackend/int, flags: WGPUInstanceFlag/int, dx12ShaderCompiler: WGPUDx12Compiler, gles3MinorVersion: WGPUGles3MinorVersion, glFenceBehaviour: WGPUGLFenceBehaviour, dxilPath: WGPUStringView, dxcPath: WGPUStringView, dxcMaxShaderModel: WGPUDxcMaxShaderModel @@ -213,13 +220,13 @@ def set_instance_extras( "WGPUInstanceExtras *", # not used: chain backends=backends, - flags=flags, # lib.WGPUInstanceFlag_Debug, # figure out if this works or not. + flags=flags, 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=lib.WGPUDxcMaxShaderModel_V6_5, + dxcMaxShaderModel=c_max_shader_model, ) c_extras.chain.sType = ( diff --git a/wgpu/resources/codegen_report.md b/wgpu/resources/codegen_report.md index d24a73ca..d76ca5ba 100644 --- a/wgpu/resources/codegen_report.md +++ b/wgpu/resources/codegen_report.md @@ -31,4 +31,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 96 C structs +* Validated 95 C structs From b22bbfc0d2a0b69e29c5e6565a84d08fa33723ed Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 2 Jun 2025 02:55:09 +0200 Subject: [PATCH 15/19] support python3.9 syntax --- wgpu/backends/wgpu_native/_helpers.py | 4 ++++ wgpu/backends/wgpu_native/extras.py | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/wgpu/backends/wgpu_native/_helpers.py b/wgpu/backends/wgpu_native/_helpers.py index 38c61574..27d6c764 100644 --- a/wgpu/backends/wgpu_native/_helpers.py +++ b/wgpu/backends/wgpu_native/_helpers.py @@ -91,6 +91,10 @@ def get_wgpu_instance(extras=None): # Note, we could also use wgpuInstanceRelease, # but we keep a global instance, so we don't have to. global _the_instance + if _the_instance is not None and extras is not None: + # reset the instance if extras are given to avoid not getting requested extras. + lib.wgpuInstanceRelease(_the_instance) + _the_instance = None if _the_instance is None: # H: nextInChain: WGPUChainedStruct * diff --git a/wgpu/backends/wgpu_native/extras.py b/wgpu/backends/wgpu_native/extras.py index 80189c08..95d51646 100644 --- a/wgpu/backends/wgpu_native/extras.py +++ b/wgpu/backends/wgpu_native/extras.py @@ -1,5 +1,5 @@ import os -from typing import List +from typing import List, Union from . import GPUCommandEncoder, GPUComputePassEncoder, GPURenderPassEncoder from ._api import ( @@ -190,12 +190,12 @@ def set_instance_extras( dx12_compiler="fxc", # default, alternative "dxc" gles3_minor_version=0, fence_behavior=0, - dxil_path: os.PathLike | None = None, - dxc_path: os.PathLike | None = None, + dxil_path: Union[os.PathLike | None] = None, + dxc_path: Union[os.PathLike | None] = None, dxc_max_shader_model: float = 6.5, ): """ - Sets the global instance with extras. + Sets the global instance with extras. Removes any """ # TODO document and explain, find reference for defaults From b5b02ad93771111b2bb7aaa5bf7dfbb1a3724261 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 3 Jun 2025 21:23:19 +0200 Subject: [PATCH 16/19] amend last commit --- wgpu/backends/wgpu_native/extras.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wgpu/backends/wgpu_native/extras.py b/wgpu/backends/wgpu_native/extras.py index 95d51646..88e991fa 100644 --- a/wgpu/backends/wgpu_native/extras.py +++ b/wgpu/backends/wgpu_native/extras.py @@ -190,12 +190,12 @@ def set_instance_extras( dx12_compiler="fxc", # default, alternative "dxc" gles3_minor_version=0, fence_behavior=0, - dxil_path: Union[os.PathLike | None] = None, - dxc_path: Union[os.PathLike | None] = None, + dxil_path: Union[os.PathLike, None] = None, + dxc_path: Union[os.PathLike, None] = None, dxc_max_shader_model: float = 6.5, ): """ - Sets the global instance with extras. Removes any + Sets the global instance with extras. Removes any existing instance. """ # TODO document and explain, find reference for defaults From 0cbd3a3850e765f8e6640cbbd02264d359ba4b56 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 4 Jun 2025 00:54:01 +0200 Subject: [PATCH 17/19] get dlls from resources --- codegen/wgpu_native_patcher.py | 6 ++++-- examples/cube.py | 6 ++++-- wgpu/backends/wgpu_native/extras.py | 15 +++++++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/codegen/wgpu_native_patcher.py b/codegen/wgpu_native_patcher.py index 09896cc3..a864d90e 100644 --- a/codegen/wgpu_native_patcher.py +++ b/codegen/wgpu_native_patcher.py @@ -41,7 +41,7 @@ def compare_flags(): """ idl = get_idl_parser() - hp = get_h_parser() + hp = get_h_parser() # gets both headerfiles! name_map = { "ColorWrite": "ColorWriteMask", @@ -50,7 +50,9 @@ def compare_flags(): for name, flag in idl.flags.items(): name = name_map.get(name, name) if name not in hp.flags: - print(f"Flag {name} missing in wgpu.h") + print( + f"Flag {name} missing in wgpu.h" + ) # should actually be webgpu.h/wgpu.h as this hparser here has both else: for key, val in flag.items(): key = key.title().replace("_", "") # MAP_READ -> MapRead diff --git a/examples/cube.py b/examples/cube.py index c5374413..c6550ac5 100644 --- a/examples/cube.py +++ b/examples/cube.py @@ -460,9 +460,11 @@ async def draw_frame_async(): # TODO: remove testing code, this is all needed to use the Dxc compiler set_instance_extras( backends=1 << 3, # DX12 only: notice how it lists fewer adapters below + # backends = 1 << 0, # Vulkan + flags=1 << 0, # WGPUInstanceFlag_Debug dx12_compiler="dxc", - dxil_path=r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxil.dll", - dxc_path=r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\dxcompiler.dll", + # dxil_path=get_library_filename("dxil.dll"), # now gets handled in extras.py + # dxc_path=get_library_filename("dxcompiler.dll"), dxc_max_shader_model=6.7, ) diff --git a/wgpu/backends/wgpu_native/extras.py b/wgpu/backends/wgpu_native/extras.py index 88e991fa..059ffd43 100644 --- a/wgpu/backends/wgpu_native/extras.py +++ b/wgpu/backends/wgpu_native/extras.py @@ -14,6 +14,7 @@ ) from ...enums import Enum from ._helpers import get_wgpu_instance +from ..._coreutils import get_library_filename # NOTE: these functions represent backend-specific extra API. @@ -208,13 +209,23 @@ def set_instance_extras( 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. # if dxc is specified but no paths are provided, there will be a panic about static-dxc, so maybe we check against that. - # TODO: warning maybe? - can we overwrite this ourself to force fxc instead? - c_dx12_compiler = enum_str2int["Dx12Compiler"]["Undefined"] + 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. + # TODO: explain user to add DXC manually or provide a script/package it? (in the future) + logger.warning( + f"could not load .dll files for DXC from /resource: {e}.\n Please provide a path manually which can panic. Falling back to FXC" + ) + c_dx12_compiler = enum_str2int["Dx12Compiler"]["Fxc"] # 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) # TODO: translate to C enums/flags + # TODO: can we codegen the native only flags? do we put them here or in a flags.py? + # H: chain: WGPUChainedStruct, backends: WGPUInstanceBackend/int, flags: WGPUInstanceFlag/int, dx12ShaderCompiler: WGPUDx12Compiler, gles3MinorVersion: WGPUGles3MinorVersion, glFenceBehaviour: WGPUGLFenceBehaviour, dxilPath: WGPUStringView, dxcPath: WGPUStringView, dxcMaxShaderModel: WGPUDxcMaxShaderModel c_extras = new_struct_p( "WGPUInstanceExtras *", From ca6717f2eb1a7a33e7d62fc5499c26960392680a Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 6 Jun 2025 20:58:29 +0200 Subject: [PATCH 18/19] map remaining extras --- wgpu/backends/wgpu_native/extras.py | 36 +++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/wgpu/backends/wgpu_native/extras.py b/wgpu/backends/wgpu_native/extras.py index 059ffd43..beed521b 100644 --- a/wgpu/backends/wgpu_native/extras.py +++ b/wgpu/backends/wgpu_native/extras.py @@ -188,22 +188,32 @@ def write_timestamp(encoder, query_set, query_index): def set_instance_extras( backends=0, # default all flags=0, - dx12_compiler="fxc", # default, alternative "dxc" - gles3_minor_version=0, - fence_behavior=0, + dx12_compiler="fxc", + gles3_minor_version="Atomic", + fence_behavior="Normal", dxil_path: Union[os.PathLike, None] = None, dxc_path: Union[os.PathLike, None] = None, dxc_max_shader_model: float = 6.5, ): """ - Sets the global instance with extras. Removes any existing instance. + Sets the global instance with extras. Replaces any existing instance. + Args: + backends: bitflag/int, which backends to enable on the instance level. Defaults to (0b0: all). + flags: bitflag/int for debugging the instance and compiler. Defaults to (0b0: 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. """ # TODO document and explain, find reference for defaults c_dx12_compiler = enum_str2int["Dx12Compiler"].get( dx12_compiler.capitalize(), enum_str2int["Dx12Compiler"]["Undefined"] - ) # default to "undefined"? - # the rust conv layer does all the checking, so fallbacks are handled there. + ) + # 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) @@ -220,10 +230,22 @@ def set_instance_extras( ) c_dx12_compiler = enum_str2int["Dx12Compiler"]["Fxc"] + # https://docs.rs/wgpu/latest/wgpu/enum.Gles3MinorVersion.html + if gles3_minor_version[-1].isdigit(): + gles3_minor_version = int(gles3_minor_version[-1]) + 1 # hack as the last char easily maps to the enum. + elif isinstance(gles3_minor_version, str): + gles3_minor_version = 0 # likely means atomic + + # https://docs.rs/wgpu/latest/wgpu/enum.GlFenceBehavior.html + fence_behavior_map = { + "Normal": 0, # WGPUGLFenceBehavior_Normal + "AutoFinish": 1, # WGPUGLFenceBehavior_AutoFinish + } + fence_behavior = fence_behavior_map.get(fence_behavior, 0) + # 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) - # TODO: translate to C enums/flags # TODO: can we codegen the native only flags? do we put them here or in a flags.py? # H: chain: WGPUChainedStruct, backends: WGPUInstanceBackend/int, flags: WGPUInstanceFlag/int, dx12ShaderCompiler: WGPUDx12Compiler, gles3MinorVersion: WGPUGles3MinorVersion, glFenceBehaviour: WGPUGLFenceBehaviour, dxilPath: WGPUStringView, dxcPath: WGPUStringView, dxcMaxShaderModel: WGPUDxcMaxShaderModel From 921c48c19dea455aadaa74c8e5e1da18f00406d7 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 6 Jun 2025 21:32:56 +0200 Subject: [PATCH 19/19] cleanup debug code --- examples/cube.py | 13 ------------- wgpu/backends/wgpu_native/extras.py | 4 +++- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/examples/cube.py b/examples/cube.py index c6550ac5..103bf4d4 100644 --- a/examples/cube.py +++ b/examples/cube.py @@ -14,7 +14,6 @@ import wgpu import numpy as np -from wgpu.backends.wgpu_native.extras import set_instance_extras from rendercanvas.auto import RenderCanvas, loop @@ -456,18 +455,6 @@ async def draw_frame_async(): uniform_dtype = [("transform", "float32", (4, 4))] uniform_data = np.zeros((), dtype=uniform_dtype) - -# TODO: remove testing code, this is all needed to use the Dxc compiler -set_instance_extras( - backends=1 << 3, # DX12 only: notice how it lists fewer adapters below - # backends = 1 << 0, # Vulkan - flags=1 << 0, # WGPUInstanceFlag_Debug - dx12_compiler="dxc", - # dxil_path=get_library_filename("dxil.dll"), # now gets handled in extras.py - # dxc_path=get_library_filename("dxcompiler.dll"), - dxc_max_shader_model=6.7, -) - print("Available adapters on this system:") for a in wgpu.gpu.enumerate_adapters_sync(): print(a.summary) diff --git a/wgpu/backends/wgpu_native/extras.py b/wgpu/backends/wgpu_native/extras.py index beed521b..52fd2ad9 100644 --- a/wgpu/backends/wgpu_native/extras.py +++ b/wgpu/backends/wgpu_native/extras.py @@ -232,7 +232,9 @@ def set_instance_extras( # https://docs.rs/wgpu/latest/wgpu/enum.Gles3MinorVersion.html if gles3_minor_version[-1].isdigit(): - gles3_minor_version = int(gles3_minor_version[-1]) + 1 # hack as the last char easily maps to the enum. + gles3_minor_version = ( + int(gles3_minor_version[-1]) + 1 + ) # hack as the last char easily maps to the enum. elif isinstance(gles3_minor_version, str): gles3_minor_version = 0 # likely means atomic