wgpu 0.19.0__py3-none-win_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wgpu/__init__.py +19 -0
- wgpu/__pyinstaller/__init__.py +12 -0
- wgpu/__pyinstaller/conftest.py +1 -0
- wgpu/__pyinstaller/hook-wgpu.py +30 -0
- wgpu/__pyinstaller/test_wgpu.py +30 -0
- wgpu/_classes.py +2628 -0
- wgpu/_coreutils.py +226 -0
- wgpu/_diagnostics.py +524 -0
- wgpu/_version.py +113 -0
- wgpu/backends/__init__.py +37 -0
- wgpu/backends/auto.py +27 -0
- wgpu/backends/js_webgpu/__init__.py +31 -0
- wgpu/backends/wgpu_native/__init__.py +23 -0
- wgpu/backends/wgpu_native/_api.py +3646 -0
- wgpu/backends/wgpu_native/_ffi.py +208 -0
- wgpu/backends/wgpu_native/_helpers.py +513 -0
- wgpu/backends/wgpu_native/_mappings.py +491 -0
- wgpu/backends/wgpu_native/extras.py +121 -0
- wgpu/classes.py +8 -0
- wgpu/enums.py +411 -0
- wgpu/flags.py +70 -0
- wgpu/gui/__init__.py +12 -0
- wgpu/gui/_gui_utils.py +160 -0
- wgpu/gui/auto.py +191 -0
- wgpu/gui/base.py +389 -0
- wgpu/gui/glfw.py +628 -0
- wgpu/gui/jupyter.py +126 -0
- wgpu/gui/offscreen.py +99 -0
- wgpu/gui/qt.py +546 -0
- wgpu/gui/wx.py +519 -0
- wgpu/resources/__init__.py +1 -0
- wgpu/resources/codegen_report.md +40 -0
- wgpu/resources/webgpu.h +2091 -0
- wgpu/resources/webgpu.idl +1331 -0
- wgpu/resources/wgpu.h +301 -0
- wgpu/resources/wgpu_native-release.dll +0 -0
- wgpu/structs.py +757 -0
- wgpu/utils/__init__.py +21 -0
- wgpu/utils/compute.py +200 -0
- wgpu/utils/device.py +17 -0
- wgpu/utils/imgui/__init__.py +2 -0
- wgpu/utils/imgui/imgui_backend.py +501 -0
- wgpu/utils/imgui/imgui_renderer.py +205 -0
- wgpu-0.19.0.dist-info/METADATA +260 -0
- wgpu-0.19.0.dist-info/RECORD +48 -0
- wgpu-0.19.0.dist-info/WHEEL +4 -0
- wgpu-0.19.0.dist-info/entry_points.txt +3 -0
- wgpu-0.19.0.dist-info/licenses/LICENSE +25 -0
wgpu/_classes.py
ADDED
|
@@ -0,0 +1,2628 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The classes representing the wgpu API. This module defines the classes,
|
|
3
|
+
properties, methods and documentation. The majority of methods are
|
|
4
|
+
implemented in backend modules.
|
|
5
|
+
|
|
6
|
+
This module is maintained using a combination of manual code and
|
|
7
|
+
automatically inserted code. Read the codegen/readme.md for more
|
|
8
|
+
information.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# Allow using class names in type annotations, before the class is defined. Py3.7+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import weakref
|
|
15
|
+
import logging
|
|
16
|
+
from typing import List, Dict, Union, Optional
|
|
17
|
+
|
|
18
|
+
from ._coreutils import ApiDiff, str_flag_to_int
|
|
19
|
+
from ._diagnostics import diagnostics, texture_format_to_bpp
|
|
20
|
+
from . import flags, enums, structs
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"GPUObjectBase",
|
|
25
|
+
"GPUAdapterInfo",
|
|
26
|
+
"GPU",
|
|
27
|
+
"GPUAdapter",
|
|
28
|
+
"GPUDevice",
|
|
29
|
+
"GPUBuffer",
|
|
30
|
+
"GPUTexture",
|
|
31
|
+
"GPUTextureView",
|
|
32
|
+
"GPUSampler",
|
|
33
|
+
"GPUBindGroupLayout",
|
|
34
|
+
"GPUBindGroup",
|
|
35
|
+
"GPUPipelineLayout",
|
|
36
|
+
"GPUShaderModule",
|
|
37
|
+
"GPUCompilationMessage",
|
|
38
|
+
"GPUCompilationInfo",
|
|
39
|
+
"GPUPipelineError",
|
|
40
|
+
"GPUPipelineBase",
|
|
41
|
+
"GPUComputePipeline",
|
|
42
|
+
"GPURenderPipeline",
|
|
43
|
+
"GPUCommandBuffer",
|
|
44
|
+
"GPUCommandsMixin",
|
|
45
|
+
"GPUCommandEncoder",
|
|
46
|
+
"GPUBindingCommandsMixin",
|
|
47
|
+
"GPUDebugCommandsMixin",
|
|
48
|
+
"GPUComputePassEncoder",
|
|
49
|
+
"GPURenderPassEncoder",
|
|
50
|
+
"GPURenderCommandsMixin",
|
|
51
|
+
"GPURenderBundle",
|
|
52
|
+
"GPURenderBundleEncoder",
|
|
53
|
+
"GPUQueue",
|
|
54
|
+
"GPUQuerySet",
|
|
55
|
+
"GPUCanvasContext",
|
|
56
|
+
"GPUDeviceLostInfo",
|
|
57
|
+
"GPUError",
|
|
58
|
+
"GPUValidationError",
|
|
59
|
+
"GPUOutOfMemoryError",
|
|
60
|
+
"GPUInternalError",
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
logger = logging.getLogger("wgpu")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
apidiff = ApiDiff()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Obtain the object tracker. Note that we store a ref of
|
|
70
|
+
# the latter on all classes that refer to it. Otherwise, on a sys exit,
|
|
71
|
+
# the module attributes are None-ified, and the destructors would
|
|
72
|
+
# therefore fail and produce warnings.
|
|
73
|
+
object_tracker = diagnostics.object_counts.tracker
|
|
74
|
+
|
|
75
|
+
# The 'optional' value is used as the default value for optional arguments in the following two cases:
|
|
76
|
+
# * The method accepts a descriptor that is optional, so we make all arguments (i.e. descriptor fields) optional, and this one does not have a default value.
|
|
77
|
+
# * In wgpu-py we decided that this argument should be optional, even though it's currently not according to the WebGPU spec.
|
|
78
|
+
optional = None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class GPU:
|
|
82
|
+
"""The entrypoint to the wgpu API.
|
|
83
|
+
|
|
84
|
+
The starting point of your wgpu-adventure is always to obtain an
|
|
85
|
+
adapter. This is the equivalent to browser's ``navigator.gpu``.
|
|
86
|
+
When a backend is loaded, the ``wgpu.gpu`` object is replaced with
|
|
87
|
+
a backend-specific implementation.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
# IDL: Promise<GPUAdapter?> requestAdapter(optional GPURequestAdapterOptions options = {}); -> GPUPowerPreference powerPreference, boolean forceFallbackAdapter = false
|
|
91
|
+
@apidiff.change("arguments include canvas")
|
|
92
|
+
def request_adapter_sync(
|
|
93
|
+
self,
|
|
94
|
+
*,
|
|
95
|
+
power_preference: enums.PowerPreference = None,
|
|
96
|
+
force_fallback_adapter: bool = False,
|
|
97
|
+
canvas=None,
|
|
98
|
+
):
|
|
99
|
+
"""Sync version of `request_adapter_async()`.
|
|
100
|
+
|
|
101
|
+
Provided by wgpu-py, but not compatible with WebGPU.
|
|
102
|
+
"""
|
|
103
|
+
# If this method gets called, no backend has been loaded yet, let's do that now!
|
|
104
|
+
from .backends.auto import gpu
|
|
105
|
+
|
|
106
|
+
return gpu.request_adapter_sync(
|
|
107
|
+
power_preference=power_preference,
|
|
108
|
+
force_fallback_adapter=force_fallback_adapter,
|
|
109
|
+
canvas=canvas,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# IDL: Promise<GPUAdapter?> requestAdapter(optional GPURequestAdapterOptions options = {}); -> GPUPowerPreference powerPreference, boolean forceFallbackAdapter = false
|
|
113
|
+
@apidiff.change("arguments include canvas")
|
|
114
|
+
async def request_adapter_async(
|
|
115
|
+
self,
|
|
116
|
+
*,
|
|
117
|
+
power_preference: enums.PowerPreference = None,
|
|
118
|
+
force_fallback_adapter: bool = False,
|
|
119
|
+
canvas=None,
|
|
120
|
+
):
|
|
121
|
+
"""Create a `GPUAdapter`, the object that represents an abstract wgpu
|
|
122
|
+
implementation, from which one can request a `GPUDevice`.
|
|
123
|
+
|
|
124
|
+
Arguments:
|
|
125
|
+
power_preference (PowerPreference): "high-performance" or "low-power".
|
|
126
|
+
force_fallback_adapter (bool): whether to use a (probably CPU-based)
|
|
127
|
+
fallback adapter.
|
|
128
|
+
canvas : The canvas that the adapter should be able to render to. This can typically
|
|
129
|
+
be left to None. If given, the object must implement ``WgpuCanvasInterface``.
|
|
130
|
+
"""
|
|
131
|
+
# If this method gets called, no backend has been loaded yet, let's do that now!
|
|
132
|
+
from .backends.auto import gpu
|
|
133
|
+
|
|
134
|
+
return await gpu.request_adapter_async(
|
|
135
|
+
power_preference=power_preference,
|
|
136
|
+
force_fallback_adapter=force_fallback_adapter,
|
|
137
|
+
canvas=canvas,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
@apidiff.add("Method useful for multi-gpu environments")
|
|
141
|
+
def enumerate_adapters_sync(self):
|
|
142
|
+
"""Sync version of `enumerate_adapters_async()`.
|
|
143
|
+
|
|
144
|
+
Provided by wgpu-py, but not compatible with WebGPU.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
# If this method gets called, no backend has been loaded yet, let's do that now!
|
|
148
|
+
from .backends.auto import gpu
|
|
149
|
+
|
|
150
|
+
return gpu.enumerate_adapters_sync()
|
|
151
|
+
|
|
152
|
+
@apidiff.add("Method useful for multi-gpu environments")
|
|
153
|
+
async def enumerate_adapters_async(self):
|
|
154
|
+
"""Get a list of adapter objects available on the current system.
|
|
155
|
+
|
|
156
|
+
An adapter can then be selected (e.g. using it's summary), and a device
|
|
157
|
+
then created from it.
|
|
158
|
+
|
|
159
|
+
The order of the devices is such that Vulkan adapters go first, then
|
|
160
|
+
Metal, then D3D12, then OpenGL. Within each category, the order as
|
|
161
|
+
provided by the particular backend is maintained. Note that the same
|
|
162
|
+
device may be present via multiple backends (e.g. vulkan/opengl).
|
|
163
|
+
|
|
164
|
+
We cannot make guarantees about whether the order of the adapters
|
|
165
|
+
matches the order as reported by e.g. ``nvidia-smi``. We have found that
|
|
166
|
+
on a Linux multi-gpu cluster, the order does match, but we cannot
|
|
167
|
+
promise that this is always the case. If you want to make sure, do some
|
|
168
|
+
testing by allocating big buffers and checking memory usage using
|
|
169
|
+
``nvidia-smi``.
|
|
170
|
+
|
|
171
|
+
See https://github.com/pygfx/wgpu-py/issues/482 for more details.
|
|
172
|
+
"""
|
|
173
|
+
# Note that backends that cannot enumerate adapters, like WebGL,
|
|
174
|
+
# can at least request two adapters with different power preference,
|
|
175
|
+
# and then return both or one (if they represent the same adapter).
|
|
176
|
+
|
|
177
|
+
# If this method gets called, no backend has been loaded yet, let's do that now!
|
|
178
|
+
from .backends.auto import gpu
|
|
179
|
+
|
|
180
|
+
return await gpu.enumerate_adapters_async()
|
|
181
|
+
|
|
182
|
+
# IDL: GPUTextureFormat getPreferredCanvasFormat();
|
|
183
|
+
@apidiff.change("Disabled because we put it on the canvas context")
|
|
184
|
+
def get_preferred_canvas_format(self):
|
|
185
|
+
"""Not implemented in wgpu-py; use `GPUCanvasContext.get_preferred_format()` instead.
|
|
186
|
+
The WebGPU spec defines this function, but in wgpu there are different
|
|
187
|
+
kinds of canvases which may each prefer/support a different format.
|
|
188
|
+
"""
|
|
189
|
+
raise RuntimeError("Use canvas.get_preferred_format() instead.")
|
|
190
|
+
|
|
191
|
+
# IDL: [SameObject] readonly attribute WGSLLanguageFeatures wgslLanguageFeatures;
|
|
192
|
+
@property
|
|
193
|
+
def wgsl_language_features(self):
|
|
194
|
+
"""A set of strings representing the WGSL language extensions supported by all adapters.
|
|
195
|
+
Returns an empty set for now."""
|
|
196
|
+
# Looks like at the time of writing there are no definitions for extensions yet
|
|
197
|
+
return set()
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# Instantiate API entrypoint
|
|
201
|
+
gpu = GPU()
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class GPUCanvasContext:
|
|
205
|
+
"""Represents a context to configure a canvas and render to it.
|
|
206
|
+
|
|
207
|
+
Can be obtained via `gui.WgpuCanvasInterface.get_context()`.
|
|
208
|
+
|
|
209
|
+
The canvas-context plays a crucial role in connecting the wgpu API to the
|
|
210
|
+
GUI layer, in a way that allows the GUI to be agnostic about wgpu. It
|
|
211
|
+
combines (and checks) the user's preferences with the capabilities and
|
|
212
|
+
preferences of the canvas.
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
_ot = object_tracker
|
|
216
|
+
|
|
217
|
+
def __init__(self, canvas):
|
|
218
|
+
self._ot.increase(self.__class__.__name__)
|
|
219
|
+
self._canvas_ref = weakref.ref(canvas)
|
|
220
|
+
|
|
221
|
+
# Surface capabilities. Stored the first time it is obtained
|
|
222
|
+
self._capabilities = None
|
|
223
|
+
|
|
224
|
+
# Configuration dict from the user, set via self.configure()
|
|
225
|
+
self._config = None
|
|
226
|
+
|
|
227
|
+
# The last used texture
|
|
228
|
+
self._texture = None
|
|
229
|
+
|
|
230
|
+
# The configuration from the canvas, obtained with canvas.get_present_info()
|
|
231
|
+
self._present_info = canvas.get_present_info()
|
|
232
|
+
if self._present_info.get("method", None) not in ("screen", "image"):
|
|
233
|
+
raise RuntimeError(
|
|
234
|
+
"canvas.get_present_info() must produce a dict with a field 'method' that is either 'screen' or 'image'."
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
def _get_canvas(self):
|
|
238
|
+
"""Getter method for internal use."""
|
|
239
|
+
return self._canvas_ref()
|
|
240
|
+
|
|
241
|
+
# IDL: readonly attribute (HTMLCanvasElement or OffscreenCanvas) canvas;
|
|
242
|
+
@property
|
|
243
|
+
def canvas(self):
|
|
244
|
+
"""The associated canvas object."""
|
|
245
|
+
return self._canvas_ref()
|
|
246
|
+
|
|
247
|
+
def _get_capabilities(self, adapter):
|
|
248
|
+
"""Get dict of capabilities and cache the result."""
|
|
249
|
+
if self._capabilities is None:
|
|
250
|
+
self._capabilities = {}
|
|
251
|
+
if self._present_info["method"] == "screen":
|
|
252
|
+
# Query capabilities from the surface
|
|
253
|
+
self._capabilities.update(self._get_capabilities_screen(adapter))
|
|
254
|
+
else:
|
|
255
|
+
# Default image capabilities
|
|
256
|
+
self._capabilities = {
|
|
257
|
+
"formats": ["rgba8unorm-srgb", "rgba8unorm"],
|
|
258
|
+
"usages": 0xFF,
|
|
259
|
+
"alpha_modes": [enums.CanvasAlphaMode.opaque],
|
|
260
|
+
}
|
|
261
|
+
# If capabilities were provided via surface info, overload them!
|
|
262
|
+
for key in ["formats", "alpha_modes"]:
|
|
263
|
+
if key in self._present_info:
|
|
264
|
+
self._capabilities[key] = self._present_info[key]
|
|
265
|
+
# Derived defaults
|
|
266
|
+
if "view_formats" not in self._capabilities:
|
|
267
|
+
self._capabilities["view_formats"] = self._capabilities["formats"]
|
|
268
|
+
|
|
269
|
+
return self._capabilities
|
|
270
|
+
|
|
271
|
+
def _get_capabilities_screen(self, adapter):
|
|
272
|
+
"""Get capabilities for a native surface."""
|
|
273
|
+
raise NotImplementedError()
|
|
274
|
+
|
|
275
|
+
@apidiff.add("Better place to define the preferred format")
|
|
276
|
+
def get_preferred_format(self, adapter):
|
|
277
|
+
"""Get the preferred surface texture format."""
|
|
278
|
+
capabilities = self._get_capabilities(adapter)
|
|
279
|
+
formats = capabilities["formats"]
|
|
280
|
+
return formats[0] if formats else "bgra8-unorm"
|
|
281
|
+
|
|
282
|
+
# IDL: undefined configure(GPUCanvasConfiguration configuration); -> required GPUDevice device, required GPUTextureFormat format, GPUTextureUsageFlags usage = 0x10, sequence<GPUTextureFormat> viewFormats = [], PredefinedColorSpace colorSpace = "srgb", GPUCanvasToneMapping toneMapping = {}, GPUCanvasAlphaMode alphaMode = "opaque"
|
|
283
|
+
def configure(
|
|
284
|
+
self,
|
|
285
|
+
*,
|
|
286
|
+
device: GPUDevice,
|
|
287
|
+
format: enums.TextureFormat,
|
|
288
|
+
usage: flags.TextureUsage = 0x10,
|
|
289
|
+
view_formats: List[enums.TextureFormat] = [],
|
|
290
|
+
color_space: str = "srgb",
|
|
291
|
+
tone_mapping: structs.CanvasToneMapping = {},
|
|
292
|
+
alpha_mode: enums.CanvasAlphaMode = "opaque",
|
|
293
|
+
):
|
|
294
|
+
"""Configures the presentation context for the associated canvas.
|
|
295
|
+
Destroys any textures produced with a previous configuration.
|
|
296
|
+
This clears the drawing buffer to transparent black.
|
|
297
|
+
|
|
298
|
+
Arguments:
|
|
299
|
+
device (WgpuDevice): The GPU device object to create compatible textures for.
|
|
300
|
+
format (enums.TextureFormat): The format that textures returned by
|
|
301
|
+
``get_current_texture()`` will have. Must be one of the supported context
|
|
302
|
+
formats. Can be ``None`` to use the canvas' preferred format.
|
|
303
|
+
usage (flags.TextureUsage): Default ``TextureUsage.OUTPUT_ATTACHMENT``.
|
|
304
|
+
view_formats (List[enums.TextureFormat]): The formats that views created
|
|
305
|
+
from textures returned by ``get_current_texture()`` may use.
|
|
306
|
+
color_space (PredefinedColorSpace): The color space that values written
|
|
307
|
+
into textures returned by ``get_current_texture()`` should be displayed with.
|
|
308
|
+
Default "srgb". Not yet supported.
|
|
309
|
+
tone_mapping (enums.CanvasToneMappingMode): Not yet supported.
|
|
310
|
+
alpha_mode (structs.CanvasAlphaMode): Determines the effect that alpha values
|
|
311
|
+
will have on the content of textures returned by ``get_current_texture()``
|
|
312
|
+
when read, displayed, or used as an image source. Default "opaque".
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
# Check types
|
|
316
|
+
|
|
317
|
+
if not isinstance(device, GPUDevice):
|
|
318
|
+
raise TypeError("Given device is not a device.")
|
|
319
|
+
|
|
320
|
+
if format is None:
|
|
321
|
+
format = self.get_preferred_format(device.adapter)
|
|
322
|
+
if format not in enums.TextureFormat:
|
|
323
|
+
raise ValueError(f"Configure: format {format} not in {enums.TextureFormat}")
|
|
324
|
+
|
|
325
|
+
if not isinstance(usage, int):
|
|
326
|
+
usage = str_flag_to_int(flags.TextureUsage, usage)
|
|
327
|
+
|
|
328
|
+
color_space # noqa - not really supported, just assume srgb for now
|
|
329
|
+
tone_mapping # noqa - not supported yet
|
|
330
|
+
|
|
331
|
+
if alpha_mode not in enums.CanvasAlphaMode:
|
|
332
|
+
raise ValueError(
|
|
333
|
+
f"Configure: alpha_mode {alpha_mode} not in {enums.CanvasAlphaMode}"
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
# Check against capabilities
|
|
337
|
+
|
|
338
|
+
capabilities = self._get_capabilities(device.adapter)
|
|
339
|
+
|
|
340
|
+
if format not in capabilities["formats"]:
|
|
341
|
+
raise ValueError(
|
|
342
|
+
f"Configure: unsupported texture format: {format} not in {capabilities['formats']}"
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
if not usage & capabilities["usages"]:
|
|
346
|
+
raise ValueError(
|
|
347
|
+
f"Configure: unsupported texture usage: {usage} not in {capabilities['usages']}"
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
for view_format in view_formats:
|
|
351
|
+
if view_format not in capabilities["view_formats"]:
|
|
352
|
+
raise ValueError(
|
|
353
|
+
f"Configure: unsupported view format: {view_format} not in {capabilities['view_formats']}"
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
if alpha_mode not in capabilities["alpha_modes"]:
|
|
357
|
+
raise ValueError(
|
|
358
|
+
f"Configure: unsupported alpha-mode: {alpha_mode} not in {capabilities['alpha_modes']}"
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
# Store
|
|
362
|
+
|
|
363
|
+
self._config = {
|
|
364
|
+
"device": device,
|
|
365
|
+
"format": format,
|
|
366
|
+
"usage": usage,
|
|
367
|
+
"view_formats": view_formats,
|
|
368
|
+
"color_space": color_space,
|
|
369
|
+
"tone_mapping": tone_mapping,
|
|
370
|
+
"alpha_mode": alpha_mode,
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if self._present_info["method"] == "screen":
|
|
374
|
+
self._configure_screen(**self._config)
|
|
375
|
+
|
|
376
|
+
def _configure_screen(
|
|
377
|
+
self,
|
|
378
|
+
*,
|
|
379
|
+
device,
|
|
380
|
+
format,
|
|
381
|
+
usage,
|
|
382
|
+
view_formats,
|
|
383
|
+
color_space,
|
|
384
|
+
tone_mapping,
|
|
385
|
+
alpha_mode,
|
|
386
|
+
):
|
|
387
|
+
raise NotImplementedError()
|
|
388
|
+
|
|
389
|
+
# IDL: undefined unconfigure();
|
|
390
|
+
def unconfigure(self):
|
|
391
|
+
"""Removes the presentation context configuration.
|
|
392
|
+
Destroys any textures produced while configured.
|
|
393
|
+
"""
|
|
394
|
+
if self._present_info["method"] == "screen":
|
|
395
|
+
self._unconfigure_screen()
|
|
396
|
+
self._config = None
|
|
397
|
+
self._drop_texture()
|
|
398
|
+
|
|
399
|
+
def _unconfigure_screen(self):
|
|
400
|
+
raise NotImplementedError()
|
|
401
|
+
|
|
402
|
+
# IDL: GPUTexture getCurrentTexture();
|
|
403
|
+
def get_current_texture(self):
|
|
404
|
+
"""Get the `GPUTexture` that will be composited to the canvas next."""
|
|
405
|
+
if not self._config:
|
|
406
|
+
raise RuntimeError(
|
|
407
|
+
"Canvas context must be configured before calling get_current_texture()."
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
# When the texture is active right now, we could either:
|
|
411
|
+
# * return the existing texture
|
|
412
|
+
# * warn about it, and create a new one
|
|
413
|
+
# * raise an error
|
|
414
|
+
# Right now we return the existing texture, so user can retrieve it in different render passes that write to the same frame.
|
|
415
|
+
|
|
416
|
+
if self._texture is None:
|
|
417
|
+
if self._present_info["method"] == "screen":
|
|
418
|
+
self._texture = self._create_texture_screen()
|
|
419
|
+
else:
|
|
420
|
+
self._texture = self._create_texture_image()
|
|
421
|
+
|
|
422
|
+
return self._texture
|
|
423
|
+
|
|
424
|
+
def _create_texture_image(self):
|
|
425
|
+
canvas = self._get_canvas()
|
|
426
|
+
width, height = canvas.get_physical_size()
|
|
427
|
+
width, height = max(width, 1), max(height, 1)
|
|
428
|
+
|
|
429
|
+
device = self._config["device"]
|
|
430
|
+
self._texture = device.create_texture(
|
|
431
|
+
label="presentation-context",
|
|
432
|
+
size=(width, height, 1),
|
|
433
|
+
format=self._config["format"],
|
|
434
|
+
usage=self._config["usage"] | flags.TextureUsage.COPY_SRC,
|
|
435
|
+
)
|
|
436
|
+
return self._texture
|
|
437
|
+
|
|
438
|
+
def _create_texture_screen(self):
|
|
439
|
+
raise NotImplementedError()
|
|
440
|
+
|
|
441
|
+
def _drop_texture(self):
|
|
442
|
+
if self._texture:
|
|
443
|
+
self._texture._release() # not destroy, because it may be in use.
|
|
444
|
+
self._texture = None
|
|
445
|
+
|
|
446
|
+
@apidiff.add("Present method is exposed")
|
|
447
|
+
def present(self):
|
|
448
|
+
"""Present what has been drawn to the current texture, by compositing it
|
|
449
|
+
to the canvas. Note that a canvas based on `gui.WgpuCanvasBase` will call this
|
|
450
|
+
method automatically at the end of each draw event.
|
|
451
|
+
"""
|
|
452
|
+
# todo: can we remove this present() method?
|
|
453
|
+
|
|
454
|
+
if not self._texture:
|
|
455
|
+
# This can happen when a user somehow forgot to call
|
|
456
|
+
# get_current_texture(). But then what was this person rendering to
|
|
457
|
+
# then? The thing is that this also happens when there is an
|
|
458
|
+
# exception in the draw function before the call to
|
|
459
|
+
# get_current_texture(). In this scenario our warning may
|
|
460
|
+
# add confusion, so provide context and make it a debug level warning.
|
|
461
|
+
msg = "Warning in present(): No texture to present, missing call to get_current_texture()?"
|
|
462
|
+
logger.debug(msg)
|
|
463
|
+
return
|
|
464
|
+
|
|
465
|
+
if self._present_info["method"] == "screen":
|
|
466
|
+
self._present_screen()
|
|
467
|
+
else:
|
|
468
|
+
self._present_image()
|
|
469
|
+
|
|
470
|
+
self._drop_texture()
|
|
471
|
+
|
|
472
|
+
def _present_image(self):
|
|
473
|
+
texture = self._texture
|
|
474
|
+
device = texture._device
|
|
475
|
+
|
|
476
|
+
size = texture.size
|
|
477
|
+
format = texture.format
|
|
478
|
+
nchannels = 4 # we expect rgba or bgra
|
|
479
|
+
if not format.startswith(("rgba", "bgra")):
|
|
480
|
+
raise RuntimeError(f"Image present unsupported texture format {format}.")
|
|
481
|
+
if "8" in format:
|
|
482
|
+
bytes_per_pixel = nchannels
|
|
483
|
+
elif "16" in format:
|
|
484
|
+
bytes_per_pixel = nchannels * 2
|
|
485
|
+
elif "32" in format:
|
|
486
|
+
bytes_per_pixel = nchannels * 4
|
|
487
|
+
else:
|
|
488
|
+
raise RuntimeError(
|
|
489
|
+
f"Image present unsupported texture format bitdepth {format}."
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
data = device.queue.read_texture(
|
|
493
|
+
{
|
|
494
|
+
"texture": texture,
|
|
495
|
+
"mip_level": 0,
|
|
496
|
+
"origin": (0, 0, 0),
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
"offset": 0,
|
|
500
|
+
"bytes_per_row": bytes_per_pixel * size[0],
|
|
501
|
+
"rows_per_image": size[1],
|
|
502
|
+
},
|
|
503
|
+
size,
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
# Represent as memory object to avoid numpy dependency
|
|
507
|
+
# Equivalent: np.frombuffer(data, np.uint8).reshape(size[1], size[0], nchannels)
|
|
508
|
+
data = data.cast("B", (size[1], size[0], nchannels))
|
|
509
|
+
|
|
510
|
+
self._get_canvas().present_image(data, format=format)
|
|
511
|
+
|
|
512
|
+
def _present_screen(self):
|
|
513
|
+
raise NotImplementedError()
|
|
514
|
+
|
|
515
|
+
def __del__(self):
|
|
516
|
+
self._ot.decrease(self.__class__.__name__)
|
|
517
|
+
self._release()
|
|
518
|
+
|
|
519
|
+
def _release(self):
|
|
520
|
+
self._drop_texture()
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
class GPUAdapterInfo:
|
|
524
|
+
"""Represents information about an adapter."""
|
|
525
|
+
|
|
526
|
+
def __init__(self, info):
|
|
527
|
+
self._info = info
|
|
528
|
+
|
|
529
|
+
# IDL: readonly attribute DOMString vendor;
|
|
530
|
+
@property
|
|
531
|
+
def vendor(self):
|
|
532
|
+
"""The vendor that built this adaptor."""
|
|
533
|
+
return self._info["vendor"]
|
|
534
|
+
|
|
535
|
+
# IDL: readonly attribute DOMString architecture;
|
|
536
|
+
@property
|
|
537
|
+
def architecture(self):
|
|
538
|
+
"""The adapters architecrure."""
|
|
539
|
+
return self._info["architecture"]
|
|
540
|
+
|
|
541
|
+
# IDL: readonly attribute DOMString device;
|
|
542
|
+
@property
|
|
543
|
+
def device(self):
|
|
544
|
+
"""The kind of device that this adapter represents."""
|
|
545
|
+
return self._info["device"]
|
|
546
|
+
|
|
547
|
+
# IDL: readonly attribute DOMString description;
|
|
548
|
+
@property
|
|
549
|
+
def description(self):
|
|
550
|
+
"""A textual description of the adapter."""
|
|
551
|
+
return self._info["description"]
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
class GPUAdapter:
|
|
555
|
+
"""Represents an abstract wgpu implementation.
|
|
556
|
+
|
|
557
|
+
An adapter represents both an instance of a hardware accelerator
|
|
558
|
+
(e.g. GPU or CPU) and an implementation of WGPU on top of that
|
|
559
|
+
accelerator.
|
|
560
|
+
|
|
561
|
+
The adapter is used to request a device object. The adapter object
|
|
562
|
+
enumerates its capabilities (features) and limits.
|
|
563
|
+
|
|
564
|
+
If an adapter becomes unavailable, it becomes invalid.
|
|
565
|
+
Once invalid, it never becomes valid again.
|
|
566
|
+
"""
|
|
567
|
+
|
|
568
|
+
_ot = object_tracker
|
|
569
|
+
|
|
570
|
+
def __init__(self, internal, features, limits, adapter_info):
|
|
571
|
+
self._ot.increase(self.__class__.__name__)
|
|
572
|
+
self._internal = internal
|
|
573
|
+
|
|
574
|
+
assert isinstance(features, set)
|
|
575
|
+
assert isinstance(limits, dict)
|
|
576
|
+
assert isinstance(adapter_info, dict)
|
|
577
|
+
|
|
578
|
+
self._features = features
|
|
579
|
+
self._limits = limits
|
|
580
|
+
self._adapter_info = adapter_info
|
|
581
|
+
|
|
582
|
+
# IDL: [SameObject] readonly attribute GPUSupportedFeatures features;
|
|
583
|
+
@property
|
|
584
|
+
def features(self):
|
|
585
|
+
"""A set of feature names supported by the adapter."""
|
|
586
|
+
return self._features
|
|
587
|
+
|
|
588
|
+
# IDL: [SameObject] readonly attribute GPUSupportedLimits limits;
|
|
589
|
+
@property
|
|
590
|
+
def limits(self):
|
|
591
|
+
"""A dict with limits for the adapter."""
|
|
592
|
+
return self._limits
|
|
593
|
+
|
|
594
|
+
# IDL: Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {}); -> USVString label = "", sequence<GPUFeatureName> requiredFeatures = [], record<DOMString, GPUSize64> requiredLimits = {}, GPUQueueDescriptor defaultQueue = {}
|
|
595
|
+
def request_device_sync(
|
|
596
|
+
self,
|
|
597
|
+
*,
|
|
598
|
+
label: str = "",
|
|
599
|
+
required_features: List[enums.FeatureName] = [],
|
|
600
|
+
required_limits: Dict[str, int] = {},
|
|
601
|
+
default_queue: structs.QueueDescriptor = {},
|
|
602
|
+
):
|
|
603
|
+
"""Sync version of `request_device_async()`.
|
|
604
|
+
|
|
605
|
+
Provided by wgpu-py, but not compatible with WebGPU.
|
|
606
|
+
"""
|
|
607
|
+
raise NotImplementedError()
|
|
608
|
+
|
|
609
|
+
# IDL: Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {}); -> USVString label = "", sequence<GPUFeatureName> requiredFeatures = [], record<DOMString, GPUSize64> requiredLimits = {}, GPUQueueDescriptor defaultQueue = {}
|
|
610
|
+
async def request_device_async(
|
|
611
|
+
self,
|
|
612
|
+
*,
|
|
613
|
+
label: str = "",
|
|
614
|
+
required_features: List[enums.FeatureName] = [],
|
|
615
|
+
required_limits: Dict[str, int] = {},
|
|
616
|
+
default_queue: structs.QueueDescriptor = {},
|
|
617
|
+
):
|
|
618
|
+
"""Request a `GPUDevice` from the adapter.
|
|
619
|
+
|
|
620
|
+
Arguments:
|
|
621
|
+
label (str): A human-readable label. Optional.
|
|
622
|
+
required_features (list of str): the features (extensions) that you need. Default [].
|
|
623
|
+
required_limits (dict): the various limits that you need. Default {}.
|
|
624
|
+
default_queue (structs.QueueDescriptor): Descriptor for the default queue. Optional.
|
|
625
|
+
"""
|
|
626
|
+
raise NotImplementedError()
|
|
627
|
+
|
|
628
|
+
def _release(self):
|
|
629
|
+
pass
|
|
630
|
+
|
|
631
|
+
def __del__(self):
|
|
632
|
+
self._ot.decrease(self.__class__.__name__)
|
|
633
|
+
self._release()
|
|
634
|
+
|
|
635
|
+
# IDL: readonly attribute boolean isFallbackAdapter;
|
|
636
|
+
@property
|
|
637
|
+
def is_fallback_adapter(self):
|
|
638
|
+
"""Whether this adapter runs on software (rather than dedicated hardware)."""
|
|
639
|
+
return self._adapter_info.get("adapter_type", "").lower() in ("software", "cpu")
|
|
640
|
+
|
|
641
|
+
# IDL: [SameObject] readonly attribute GPUAdapterInfo info;
|
|
642
|
+
@property
|
|
643
|
+
def info(self):
|
|
644
|
+
"""A dict with information about this adapter, such as the vendor and device name."""
|
|
645
|
+
# Note: returns a dict rather than an GPUAdapterInfo instance.
|
|
646
|
+
return self._adapter_info
|
|
647
|
+
|
|
648
|
+
@apidiff.add("Useful in multi-gpu environments")
|
|
649
|
+
@property
|
|
650
|
+
def summary(self):
|
|
651
|
+
"""A one-line summary of the info of this adapter (device, adapter_type, backend_type)."""
|
|
652
|
+
d = self._adapter_info
|
|
653
|
+
return f"{d['device']} ({d['adapter_type']}) via {d['backend_type']}"
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
class GPUObjectBase:
|
|
657
|
+
"""The base class for all GPU objects.
|
|
658
|
+
|
|
659
|
+
A GPU object is an object that can be thought of having a representation on
|
|
660
|
+
the GPU; the device and all objects belonging to a device.
|
|
661
|
+
"""
|
|
662
|
+
|
|
663
|
+
_ot = object_tracker
|
|
664
|
+
_nbytes = 0
|
|
665
|
+
|
|
666
|
+
def __init__(self, label, internal, device):
|
|
667
|
+
self._ot.increase(self.__class__.__name__, self._nbytes)
|
|
668
|
+
self._label = label
|
|
669
|
+
self._internal = internal # The native/raw/real GPU object
|
|
670
|
+
self._device = device
|
|
671
|
+
logger.info(f"Creating {self.__class__.__name__} {label}")
|
|
672
|
+
|
|
673
|
+
# IDL: attribute USVString label;
|
|
674
|
+
@property
|
|
675
|
+
def label(self):
|
|
676
|
+
"""A human-readable name identifying the GPU object."""
|
|
677
|
+
return self._label
|
|
678
|
+
|
|
679
|
+
def __str__(self):
|
|
680
|
+
if self._label:
|
|
681
|
+
return f'<{self.__class__.__name__} "{self._label}">'
|
|
682
|
+
else:
|
|
683
|
+
return f"<{self.__class__.__name__} {id(self)}>"
|
|
684
|
+
|
|
685
|
+
def _release(self):
|
|
686
|
+
"""Subclasses can implement this to clean up."""
|
|
687
|
+
pass
|
|
688
|
+
|
|
689
|
+
def __del__(self):
|
|
690
|
+
self._ot.decrease(self.__class__.__name__, self._nbytes)
|
|
691
|
+
self._release()
|
|
692
|
+
|
|
693
|
+
# Public destroy() methods are implemented on classes as the WebGPU spec specifies.
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
class GPUDevice(GPUObjectBase):
|
|
697
|
+
"""The top-level interface through which GPU objects are created.
|
|
698
|
+
|
|
699
|
+
A device is the logical instantiation of an adapter, through which
|
|
700
|
+
internal objects are created. It can be shared across threads.
|
|
701
|
+
A device is the exclusive owner of all internal objects created
|
|
702
|
+
from it: when the device is lost, all objects created from it become
|
|
703
|
+
invalid.
|
|
704
|
+
|
|
705
|
+
Create a device using `GPUAdapter.request_device_sync()` or
|
|
706
|
+
`GPUAdapter.request_device_async()`.
|
|
707
|
+
"""
|
|
708
|
+
|
|
709
|
+
def __init__(self, label, internal, adapter, features, limits, queue):
|
|
710
|
+
super().__init__(label, internal, self)
|
|
711
|
+
|
|
712
|
+
assert isinstance(adapter, GPUAdapter)
|
|
713
|
+
assert isinstance(features, set)
|
|
714
|
+
assert isinstance(limits, dict)
|
|
715
|
+
|
|
716
|
+
self._adapter = adapter
|
|
717
|
+
self._features = features
|
|
718
|
+
self._limits = limits
|
|
719
|
+
self._queue = queue
|
|
720
|
+
queue._device = self # because it could not be set earlier
|
|
721
|
+
|
|
722
|
+
# IDL: [SameObject] readonly attribute GPUSupportedFeatures features;
|
|
723
|
+
@property
|
|
724
|
+
def features(self):
|
|
725
|
+
"""A set of feature names supported by this device."""
|
|
726
|
+
return self._features
|
|
727
|
+
|
|
728
|
+
# IDL: [SameObject] readonly attribute GPUSupportedLimits limits;
|
|
729
|
+
@property
|
|
730
|
+
def limits(self):
|
|
731
|
+
"""A dict with limits for this device."""
|
|
732
|
+
return self._limits
|
|
733
|
+
|
|
734
|
+
# IDL: [SameObject] readonly attribute GPUQueue queue;
|
|
735
|
+
@property
|
|
736
|
+
def queue(self):
|
|
737
|
+
"""The default `GPUQueue` for this device."""
|
|
738
|
+
return self._queue
|
|
739
|
+
|
|
740
|
+
@apidiff.add("Too useful to not-have")
|
|
741
|
+
@property
|
|
742
|
+
def adapter(self):
|
|
743
|
+
"""The adapter object corresponding to this device."""
|
|
744
|
+
return self._adapter
|
|
745
|
+
|
|
746
|
+
# IDL: readonly attribute Promise<GPUDeviceLostInfo> lost;
|
|
747
|
+
@apidiff.hide("Not a Pythonic API")
|
|
748
|
+
@property
|
|
749
|
+
def lost_sync(self):
|
|
750
|
+
"""Sync version of `lost`.
|
|
751
|
+
|
|
752
|
+
Provided by wgpu-py, but not compatible with WebGPU.
|
|
753
|
+
"""
|
|
754
|
+
return self._get_lost_sync()
|
|
755
|
+
|
|
756
|
+
# IDL: readonly attribute Promise<GPUDeviceLostInfo> lost;
|
|
757
|
+
@apidiff.hide("Not a Pythonic API")
|
|
758
|
+
@property
|
|
759
|
+
async def lost_async(self):
|
|
760
|
+
"""Provides information about why the device is lost."""
|
|
761
|
+
# In JS you can device.lost.then ... to handle lost devices.
|
|
762
|
+
# We may want to eventually support something similar async-like?
|
|
763
|
+
# at some point
|
|
764
|
+
|
|
765
|
+
# Properties don't get repeated at _api.py, so we use a proxy method.
|
|
766
|
+
return await self._get_lost_async()
|
|
767
|
+
|
|
768
|
+
def _get_lost_sync(self):
|
|
769
|
+
raise NotImplementedError()
|
|
770
|
+
|
|
771
|
+
async def _get_lost_async(self):
|
|
772
|
+
raise NotImplementedError()
|
|
773
|
+
|
|
774
|
+
# IDL: attribute EventHandler onuncapturederror;
|
|
775
|
+
@apidiff.hide("Specific to browsers")
|
|
776
|
+
@property
|
|
777
|
+
def onuncapturederror(self):
|
|
778
|
+
"""Event handler.
|
|
779
|
+
|
|
780
|
+
In JS you'd do ``gpuDevice.addEventListener('uncapturederror', ...)``. We'd need
|
|
781
|
+
to figure out how to do this in Python.
|
|
782
|
+
"""
|
|
783
|
+
raise NotImplementedError()
|
|
784
|
+
|
|
785
|
+
# IDL: undefined destroy();
|
|
786
|
+
def destroy(self):
|
|
787
|
+
"""Destroy this device.
|
|
788
|
+
|
|
789
|
+
This cleans up all its resources and puts it in an unusable state.
|
|
790
|
+
Note that all objects get cleaned up properly automatically; this
|
|
791
|
+
is only intended to support explicit destroying.
|
|
792
|
+
|
|
793
|
+
NOTE: not yet implemented; for the moment this does nothing.
|
|
794
|
+
"""
|
|
795
|
+
raise NotImplementedError()
|
|
796
|
+
|
|
797
|
+
# IDL: GPUBuffer createBuffer(GPUBufferDescriptor descriptor); -> USVString label = "", required GPUSize64 size, required GPUBufferUsageFlags usage, boolean mappedAtCreation = false
|
|
798
|
+
def create_buffer(
|
|
799
|
+
self,
|
|
800
|
+
*,
|
|
801
|
+
label: str = "",
|
|
802
|
+
size: int,
|
|
803
|
+
usage: flags.BufferUsage,
|
|
804
|
+
mapped_at_creation: bool = False,
|
|
805
|
+
):
|
|
806
|
+
"""Create a `GPUBuffer` object.
|
|
807
|
+
|
|
808
|
+
Arguments:
|
|
809
|
+
label (str): A human-readable label. Optional.
|
|
810
|
+
size (int): The size of the buffer in bytes.
|
|
811
|
+
usage (flags.BufferUsage): The ways in which this buffer will be used.
|
|
812
|
+
mapped_at_creation (bool): Whether the buffer is initially mapped.
|
|
813
|
+
|
|
814
|
+
Alignment: the size must be a multiple of 4.
|
|
815
|
+
|
|
816
|
+
"""
|
|
817
|
+
raise NotImplementedError()
|
|
818
|
+
|
|
819
|
+
@apidiff.add("Convenience function")
|
|
820
|
+
def create_buffer_with_data(self, *, label="", data, usage: "flags.BufferUsage"):
|
|
821
|
+
"""Create a `GPUBuffer` object initialized with the given data.
|
|
822
|
+
|
|
823
|
+
This is a convenience function that creates a mapped buffer,
|
|
824
|
+
writes the given data to it, and then unmaps the buffer.
|
|
825
|
+
|
|
826
|
+
Arguments:
|
|
827
|
+
label (str): A human-readable label. Optional.
|
|
828
|
+
data: Any object supporting the Python buffer protocol (this
|
|
829
|
+
includes bytes, bytearray, ctypes arrays, numpy arrays, etc.).
|
|
830
|
+
usage (flags.BufferUsage): The ways in which this buffer will be used.
|
|
831
|
+
|
|
832
|
+
Alignment: if the size (in bytes) of data is not a multiple of 4, the buffer
|
|
833
|
+
size is rounded up to the nearest multiple of 4.
|
|
834
|
+
|
|
835
|
+
Also see `GPUBuffer.write_mapped()` and `GPUQueue.write_buffer()`.
|
|
836
|
+
"""
|
|
837
|
+
# This function was originally created to support the workflow
|
|
838
|
+
# of initializing a buffer with data when we did not support
|
|
839
|
+
# buffer mapping. Now that we do have buffer mapping it is not
|
|
840
|
+
# strictly necessary, but it's still quite useful and feels
|
|
841
|
+
# more Pythonic than having to write the boilerplate code below.
|
|
842
|
+
|
|
843
|
+
# Create a view of known type
|
|
844
|
+
data = memoryview(data).cast("B")
|
|
845
|
+
size = (data.nbytes + 3) & ~3 # round up to a multiple of 4
|
|
846
|
+
|
|
847
|
+
# Create the buffer and write data
|
|
848
|
+
buf = self.create_buffer(
|
|
849
|
+
label=label, size=size, usage=usage, mapped_at_creation=True
|
|
850
|
+
)
|
|
851
|
+
buf.write_mapped(data)
|
|
852
|
+
buf.unmap()
|
|
853
|
+
return buf
|
|
854
|
+
|
|
855
|
+
# IDL: GPUTexture createTexture(GPUTextureDescriptor descriptor); -> USVString label = "", required GPUExtent3D size, GPUIntegerCoordinate mipLevelCount = 1, GPUSize32 sampleCount = 1, GPUTextureDimension dimension = "2d", required GPUTextureFormat format, required GPUTextureUsageFlags usage, sequence<GPUTextureFormat> viewFormats = []
|
|
856
|
+
def create_texture(
|
|
857
|
+
self,
|
|
858
|
+
*,
|
|
859
|
+
label: str = "",
|
|
860
|
+
size: Union[List[int], structs.Extent3D],
|
|
861
|
+
mip_level_count: int = 1,
|
|
862
|
+
sample_count: int = 1,
|
|
863
|
+
dimension: enums.TextureDimension = "2d",
|
|
864
|
+
format: enums.TextureFormat,
|
|
865
|
+
usage: flags.TextureUsage,
|
|
866
|
+
view_formats: List[enums.TextureFormat] = [],
|
|
867
|
+
):
|
|
868
|
+
"""Create a `GPUTexture` object.
|
|
869
|
+
|
|
870
|
+
Arguments:
|
|
871
|
+
label (str): A human-readable label. Optional.
|
|
872
|
+
size (tuple or dict): The texture size as a 3-tuple or a `structs.Extent3D`.
|
|
873
|
+
mip_level_count (int): The number of mip leveles. Default 1.
|
|
874
|
+
sample_count (int): The number of samples. Default 1.
|
|
875
|
+
dimension (enums.TextureDimension): The dimensionality of the texture. Default 2d.
|
|
876
|
+
format (TextureFormat): What channels it stores and how.
|
|
877
|
+
usage (flags.TextureUsage): The ways in which the texture will be used.
|
|
878
|
+
view_formats (optional): A list of formats that views are allowed to have
|
|
879
|
+
in addition to the texture's own view. Using these formats may have
|
|
880
|
+
a performance penalty.
|
|
881
|
+
|
|
882
|
+
See https://gpuweb.github.io/gpuweb/#texture-format-caps for a
|
|
883
|
+
list of available texture formats. Note that fewer formats are
|
|
884
|
+
available for storage usage.
|
|
885
|
+
"""
|
|
886
|
+
raise NotImplementedError()
|
|
887
|
+
|
|
888
|
+
# IDL: GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {}); -> USVString label = "", GPUAddressMode addressModeU = "clamp-to-edge", GPUAddressMode addressModeV = "clamp-to-edge", GPUAddressMode addressModeW = "clamp-to-edge", GPUFilterMode magFilter = "nearest", GPUFilterMode minFilter = "nearest", GPUMipmapFilterMode mipmapFilter = "nearest", float lodMinClamp = 0, float lodMaxClamp = 32, GPUCompareFunction compare, [Clamp] unsigned short maxAnisotropy = 1
|
|
889
|
+
def create_sampler(
|
|
890
|
+
self,
|
|
891
|
+
*,
|
|
892
|
+
label: str = "",
|
|
893
|
+
address_mode_u: enums.AddressMode = "clamp-to-edge",
|
|
894
|
+
address_mode_v: enums.AddressMode = "clamp-to-edge",
|
|
895
|
+
address_mode_w: enums.AddressMode = "clamp-to-edge",
|
|
896
|
+
mag_filter: enums.FilterMode = "nearest",
|
|
897
|
+
min_filter: enums.FilterMode = "nearest",
|
|
898
|
+
mipmap_filter: enums.MipmapFilterMode = "nearest",
|
|
899
|
+
lod_min_clamp: float = 0,
|
|
900
|
+
lod_max_clamp: float = 32,
|
|
901
|
+
compare: enums.CompareFunction = optional,
|
|
902
|
+
max_anisotropy: int = 1,
|
|
903
|
+
):
|
|
904
|
+
"""Create a `GPUSampler` object. Samplers specify how a texture is sampled.
|
|
905
|
+
|
|
906
|
+
Arguments:
|
|
907
|
+
label (str): A human-readable label. Optional.
|
|
908
|
+
address_mode_u (enums.AddressMode): What happens when sampling beyond the x edge.
|
|
909
|
+
Default "clamp-to-edge".
|
|
910
|
+
address_mode_v (enums.AddressMode): What happens when sampling beyond the y edge.
|
|
911
|
+
Default "clamp-to-edge".
|
|
912
|
+
address_mode_w (enums.AddressMode): What happens when sampling beyond the z edge.
|
|
913
|
+
Default "clamp-to-edge".
|
|
914
|
+
mag_filter (enums.FilterMode): Interpolation when zoomed in. Default 'nearest'.
|
|
915
|
+
min_filter (enums.FilterMode): Interpolation when zoomed out. Default 'nearest'.
|
|
916
|
+
mipmap_filter: (enums.MipmapFilterMode): Interpolation between mip levels. Default 'nearest'.
|
|
917
|
+
lod_min_clamp (float): The minimum level of detail. Default 0.
|
|
918
|
+
lod_max_clamp (float): The maximum level of detail. Default 32.
|
|
919
|
+
compare (enums.CompareFunction): The sample compare operation for depth textures.
|
|
920
|
+
Only specify this for depth textures. Default None.
|
|
921
|
+
max_anisotropy (int): The maximum anisotropy value clamp used by the sample,
|
|
922
|
+
betweet 1 and 16, default 1.
|
|
923
|
+
"""
|
|
924
|
+
raise NotImplementedError()
|
|
925
|
+
|
|
926
|
+
# IDL: GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor); -> USVString label = "", required sequence<GPUBindGroupLayoutEntry> entries
|
|
927
|
+
def create_bind_group_layout(
|
|
928
|
+
self, *, label: str = "", entries: List[structs.BindGroupLayoutEntry]
|
|
929
|
+
):
|
|
930
|
+
"""Create a `GPUBindGroupLayout` object. One or more
|
|
931
|
+
such objects are passed to `create_pipeline_layout()` to
|
|
932
|
+
specify the (abstract) pipeline layout for resources. See the
|
|
933
|
+
docs on bind groups for details.
|
|
934
|
+
|
|
935
|
+
Arguments:
|
|
936
|
+
label (str): A human-readable label. Optional.
|
|
937
|
+
entries (list): A list of `structs.BindGroupLayoutEntry` dicts.
|
|
938
|
+
Each contains either a `structs.BufferBindingLayout`,
|
|
939
|
+
`structs.SamplerBindingLayout`, `structs.TextureBindingLayout`,
|
|
940
|
+
or `structs.StorageTextureBindingLayout`.
|
|
941
|
+
|
|
942
|
+
Example with `structs.BufferBindingLayout`:
|
|
943
|
+
|
|
944
|
+
.. code-block:: py
|
|
945
|
+
|
|
946
|
+
{
|
|
947
|
+
"binding": 0,
|
|
948
|
+
"visibility": wgpu.ShaderStage.COMPUTE,
|
|
949
|
+
"buffer": {
|
|
950
|
+
"type": wgpu.BufferBindingType.storage_buffer,
|
|
951
|
+
"has_dynamic_offset": False, # optional
|
|
952
|
+
"min_binding_size": 0 # optional
|
|
953
|
+
}
|
|
954
|
+
},
|
|
955
|
+
|
|
956
|
+
Note on ``has_dynamic_offset``: For uniform-buffer, storage-buffer, and
|
|
957
|
+
readonly-storage-buffer bindings, it indicates whether the binding has a
|
|
958
|
+
dynamic offset. One offset must be passed to `pass.set_bind_group()`
|
|
959
|
+
for each dynamic binding in increasing order of binding number.
|
|
960
|
+
"""
|
|
961
|
+
raise NotImplementedError()
|
|
962
|
+
|
|
963
|
+
# IDL: GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor); -> USVString label = "", required GPUBindGroupLayout layout, required sequence<GPUBindGroupEntry> entries
|
|
964
|
+
def create_bind_group(
|
|
965
|
+
self,
|
|
966
|
+
*,
|
|
967
|
+
label: str = "",
|
|
968
|
+
layout: GPUBindGroupLayout,
|
|
969
|
+
entries: List[structs.BindGroupEntry],
|
|
970
|
+
):
|
|
971
|
+
"""Create a `GPUBindGroup` object, which can be used in
|
|
972
|
+
`pass.set_bind_group()` to attach a group of resources.
|
|
973
|
+
|
|
974
|
+
Arguments:
|
|
975
|
+
label (str): A human-readable label. Optional.
|
|
976
|
+
layout (GPUBindGroupLayout): The layout (abstract representation)
|
|
977
|
+
for this bind group.
|
|
978
|
+
entries (list): A list of `structs.BindGroupEntry` dicts. The ``resource`` field
|
|
979
|
+
is either `GPUSampler`, `GPUTextureView` or `structs.BufferBinding`.
|
|
980
|
+
|
|
981
|
+
Example entry dicts:
|
|
982
|
+
|
|
983
|
+
.. code-block:: py
|
|
984
|
+
|
|
985
|
+
# For a sampler
|
|
986
|
+
{
|
|
987
|
+
"binding" : 0, # slot
|
|
988
|
+
"resource": a_sampler,
|
|
989
|
+
}
|
|
990
|
+
# For a texture view
|
|
991
|
+
{
|
|
992
|
+
"binding" : 0, # slot
|
|
993
|
+
"resource": a_texture_view,
|
|
994
|
+
}
|
|
995
|
+
# For a buffer
|
|
996
|
+
{
|
|
997
|
+
"binding" : 0, # slot
|
|
998
|
+
"resource": {
|
|
999
|
+
"buffer": a_buffer,
|
|
1000
|
+
"offset": 0,
|
|
1001
|
+
"size": 812,
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
"""
|
|
1005
|
+
raise NotImplementedError()
|
|
1006
|
+
|
|
1007
|
+
# IDL: GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor); -> USVString label = "", required sequence<GPUBindGroupLayout> bindGroupLayouts
|
|
1008
|
+
def create_pipeline_layout(
|
|
1009
|
+
self, *, label: str = "", bind_group_layouts: List[GPUBindGroupLayout]
|
|
1010
|
+
):
|
|
1011
|
+
"""Create a `GPUPipelineLayout` object, which can be
|
|
1012
|
+
used in `create_render_pipeline()` or `create_compute_pipeline()`.
|
|
1013
|
+
|
|
1014
|
+
Arguments:
|
|
1015
|
+
label (str): A human-readable label. Optional.
|
|
1016
|
+
bind_group_layouts (list): A list of `GPUBindGroupLayout` objects.
|
|
1017
|
+
"""
|
|
1018
|
+
raise NotImplementedError()
|
|
1019
|
+
|
|
1020
|
+
# IDL: GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor); -> USVString label = "", required USVString code, object sourceMap, sequence<GPUShaderModuleCompilationHint> compilationHints = []
|
|
1021
|
+
def create_shader_module(
|
|
1022
|
+
self,
|
|
1023
|
+
*,
|
|
1024
|
+
label: str = "",
|
|
1025
|
+
code: str,
|
|
1026
|
+
source_map: dict = optional,
|
|
1027
|
+
compilation_hints: List[structs.ShaderModuleCompilationHint] = [],
|
|
1028
|
+
):
|
|
1029
|
+
"""Create a `GPUShaderModule` object from shader source.
|
|
1030
|
+
|
|
1031
|
+
The primary shader language is WGSL, though SpirV is also supported,
|
|
1032
|
+
as well as GLSL (experimental).
|
|
1033
|
+
|
|
1034
|
+
Arguments:
|
|
1035
|
+
label (str): A human-readable label. Optional.
|
|
1036
|
+
code (str | bytes): The shader code, as WGSL, GLSL or SpirV.
|
|
1037
|
+
For GLSL code, the label must be given and contain the word
|
|
1038
|
+
'comp', 'vert' or 'frag'. For SpirV the code must be bytes.
|
|
1039
|
+
compilation_hints: currently unused.
|
|
1040
|
+
"""
|
|
1041
|
+
raise NotImplementedError()
|
|
1042
|
+
|
|
1043
|
+
# IDL: GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor); -> USVString label = "", required (GPUPipelineLayout or GPUAutoLayoutMode) layout, required GPUProgrammableStage compute
|
|
1044
|
+
def create_compute_pipeline(
|
|
1045
|
+
self,
|
|
1046
|
+
*,
|
|
1047
|
+
label: str = "",
|
|
1048
|
+
layout: Union[GPUPipelineLayout, enums.AutoLayoutMode],
|
|
1049
|
+
compute: structs.ProgrammableStage,
|
|
1050
|
+
):
|
|
1051
|
+
"""Create a `GPUComputePipeline` object.
|
|
1052
|
+
|
|
1053
|
+
Arguments:
|
|
1054
|
+
label (str): A human-readable label. Optional.
|
|
1055
|
+
layout (GPUPipelineLayout): object created with `create_pipeline_layout()`.
|
|
1056
|
+
compute (structs.ProgrammableStage): Binds shader module and entrypoint.
|
|
1057
|
+
"""
|
|
1058
|
+
raise NotImplementedError()
|
|
1059
|
+
|
|
1060
|
+
# IDL: Promise<GPUComputePipeline> createComputePipelineAsync(GPUComputePipelineDescriptor descriptor); -> USVString label = "", required (GPUPipelineLayout or GPUAutoLayoutMode) layout, required GPUProgrammableStage compute
|
|
1061
|
+
async def create_compute_pipeline_async(
|
|
1062
|
+
self,
|
|
1063
|
+
*,
|
|
1064
|
+
label: str = "",
|
|
1065
|
+
layout: Union[GPUPipelineLayout, enums.AutoLayoutMode],
|
|
1066
|
+
compute: structs.ProgrammableStage,
|
|
1067
|
+
):
|
|
1068
|
+
"""Async version of `create_compute_pipeline()`.
|
|
1069
|
+
|
|
1070
|
+
Both versions are compatible with WebGPU."""
|
|
1071
|
+
raise NotImplementedError()
|
|
1072
|
+
|
|
1073
|
+
# IDL: GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor); -> USVString label = "", required (GPUPipelineLayout or GPUAutoLayoutMode) layout, required GPUVertexState vertex, GPUPrimitiveState primitive = {}, GPUDepthStencilState depthStencil, GPUMultisampleState multisample = {}, GPUFragmentState fragment
|
|
1074
|
+
def create_render_pipeline(
|
|
1075
|
+
self,
|
|
1076
|
+
*,
|
|
1077
|
+
label: str = "",
|
|
1078
|
+
layout: Union[GPUPipelineLayout, enums.AutoLayoutMode],
|
|
1079
|
+
vertex: structs.VertexState,
|
|
1080
|
+
primitive: structs.PrimitiveState = {},
|
|
1081
|
+
depth_stencil: structs.DepthStencilState = optional,
|
|
1082
|
+
multisample: structs.MultisampleState = {},
|
|
1083
|
+
fragment: structs.FragmentState = optional,
|
|
1084
|
+
):
|
|
1085
|
+
"""Create a `GPURenderPipeline` object.
|
|
1086
|
+
|
|
1087
|
+
Arguments:
|
|
1088
|
+
label (str): A human-readable label. Optional.
|
|
1089
|
+
layout (GPUPipelineLayout): The layout for the new pipeline.
|
|
1090
|
+
vertex (structs.VertexState): Describes the vertex shader entry point of the
|
|
1091
|
+
pipeline and its input buffer layouts.
|
|
1092
|
+
primitive (structs.PrimitiveState): Describes the primitive-related properties
|
|
1093
|
+
of the pipeline. If `strip_index_format` is present (which means the
|
|
1094
|
+
primitive topology is a strip), and the drawCall is indexed, the
|
|
1095
|
+
vertex index list is split into sub-lists using the maximum value of this
|
|
1096
|
+
index format as a separator. Example: a list with values
|
|
1097
|
+
`[1, 2, 65535, 4, 5, 6]` of type "uint16" will be split in sub-lists
|
|
1098
|
+
`[1, 2]` and `[4, 5, 6]`.
|
|
1099
|
+
depth_stencil (structs.DepthStencilState): Describes the optional depth-stencil
|
|
1100
|
+
properties, including the testing, operations, and bias. Optional.
|
|
1101
|
+
multisample (structs.MultisampleState): Describes the multi-sampling properties of the pipeline.
|
|
1102
|
+
fragment (structs.FragmentState): Describes the fragment shader
|
|
1103
|
+
entry point of the pipeline and its output colors. If it's
|
|
1104
|
+
None, the No-Color-Output mode is enabled: the pipeline
|
|
1105
|
+
does not produce any color attachment outputs. It still
|
|
1106
|
+
performs rasterization and produces depth values based on
|
|
1107
|
+
the vertex position output. The depth testing and stencil
|
|
1108
|
+
operations can still be used.
|
|
1109
|
+
|
|
1110
|
+
In the example dicts below, the values that are marked as optional,
|
|
1111
|
+
the shown value is the default.
|
|
1112
|
+
|
|
1113
|
+
Example vertex (structs.VertexState) dict:
|
|
1114
|
+
|
|
1115
|
+
.. code-block:: py
|
|
1116
|
+
|
|
1117
|
+
{
|
|
1118
|
+
"module": shader_module,
|
|
1119
|
+
"entry_point": "main",
|
|
1120
|
+
"buffers": [
|
|
1121
|
+
{
|
|
1122
|
+
"array_stride": 8,
|
|
1123
|
+
"step_mode": wgpu.VertexStepMode.vertex, # optional
|
|
1124
|
+
"attributes": [
|
|
1125
|
+
{
|
|
1126
|
+
"format": wgpu.VertexFormat.float2,
|
|
1127
|
+
"offset": 0,
|
|
1128
|
+
"shader_location": 0,
|
|
1129
|
+
},
|
|
1130
|
+
...
|
|
1131
|
+
],
|
|
1132
|
+
},
|
|
1133
|
+
...
|
|
1134
|
+
]
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
Example primitive (structs.PrimitiveState) dict:
|
|
1138
|
+
|
|
1139
|
+
.. code-block:: py
|
|
1140
|
+
|
|
1141
|
+
{
|
|
1142
|
+
"topology": wgpu.PrimitiveTopology.triangle_list, # optional
|
|
1143
|
+
"strip_index_format": wgpu.IndexFormat.uint32, # see note
|
|
1144
|
+
"front_face": wgpu.FrontFace.ccw, # optional
|
|
1145
|
+
"cull_mode": wgpu.CullMode.none, # optional
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
Example depth_stencil (structs.DepthStencilState) dict:
|
|
1149
|
+
|
|
1150
|
+
.. code-block:: py
|
|
1151
|
+
|
|
1152
|
+
{
|
|
1153
|
+
"format": wgpu.TextureFormat.depth24plus_stencil8,
|
|
1154
|
+
"depth_write_enabled": False, # optional
|
|
1155
|
+
"depth_compare": wgpu.CompareFunction.always, # optional
|
|
1156
|
+
"stencil_front": { # optional
|
|
1157
|
+
"compare": wgpu.CompareFunction.equal,
|
|
1158
|
+
"fail_op": wgpu.StencilOperation.keep,
|
|
1159
|
+
"depth_fail_op": wgpu.StencilOperation.keep,
|
|
1160
|
+
"pass_op": wgpu.StencilOperation.keep,
|
|
1161
|
+
},
|
|
1162
|
+
"stencil_back": { # optional
|
|
1163
|
+
"compare": wgpu.CompareFunction.equal,
|
|
1164
|
+
"fail_op": wgpu.StencilOperation.keep,
|
|
1165
|
+
"depth_fail_op": wgpu.StencilOperation.keep,
|
|
1166
|
+
"pass_op": wgpu.StencilOperation.keep,
|
|
1167
|
+
},
|
|
1168
|
+
"stencil_read_mask": 0xFFFFFFFF, # optional
|
|
1169
|
+
"stencil_write_mask": 0xFFFFFFFF, # optional
|
|
1170
|
+
"depth_bias": 0, # optional
|
|
1171
|
+
"depth_bias_slope_scale": 0.0, # optional
|
|
1172
|
+
"depth_bias_clamp": 0.0, # optional
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
Example multisample (structs.MultisampleState) dict:
|
|
1176
|
+
|
|
1177
|
+
.. code-block:: py
|
|
1178
|
+
|
|
1179
|
+
{
|
|
1180
|
+
"count": 1, # optional
|
|
1181
|
+
"mask": 0xFFFFFFFF, # optional
|
|
1182
|
+
"alpha_to_coverage_enabled": False # optional
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
Example fragment (structs.FragmentState) dict. The `blend` parameter can be None
|
|
1186
|
+
to disable blending (not all texture formats support blending).
|
|
1187
|
+
|
|
1188
|
+
.. code-block:: py
|
|
1189
|
+
|
|
1190
|
+
{
|
|
1191
|
+
"module": shader_module,
|
|
1192
|
+
"entry_point": "main",
|
|
1193
|
+
"targets": [
|
|
1194
|
+
{
|
|
1195
|
+
"format": wgpu.TextureFormat.bgra8unorm_srgb,
|
|
1196
|
+
"blend": {
|
|
1197
|
+
"color": {
|
|
1198
|
+
"src_target": wgpu.BlendFactor.one, # optional
|
|
1199
|
+
"dst_target": wgpu.BlendFactor.zero, # optional
|
|
1200
|
+
"operation": gpu.BlendOperation.add, # optional
|
|
1201
|
+
},
|
|
1202
|
+
"alpha": {
|
|
1203
|
+
"src_target": wgpu.BlendFactor.one, # optional
|
|
1204
|
+
"dst_target": wgpu.BlendFactor.zero, # optional
|
|
1205
|
+
"operation": wgpu.BlendOperation.add, # optional
|
|
1206
|
+
},
|
|
1207
|
+
}
|
|
1208
|
+
"write_mask": wgpu.ColorWrite.ALL # optional
|
|
1209
|
+
},
|
|
1210
|
+
...
|
|
1211
|
+
]
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
"""
|
|
1215
|
+
raise NotImplementedError()
|
|
1216
|
+
|
|
1217
|
+
# IDL: Promise<GPURenderPipeline> createRenderPipelineAsync(GPURenderPipelineDescriptor descriptor); -> USVString label = "", required (GPUPipelineLayout or GPUAutoLayoutMode) layout, required GPUVertexState vertex, GPUPrimitiveState primitive = {}, GPUDepthStencilState depthStencil, GPUMultisampleState multisample = {}, GPUFragmentState fragment
|
|
1218
|
+
async def create_render_pipeline_async(
|
|
1219
|
+
self,
|
|
1220
|
+
*,
|
|
1221
|
+
label: str = "",
|
|
1222
|
+
layout: Union[GPUPipelineLayout, enums.AutoLayoutMode],
|
|
1223
|
+
vertex: structs.VertexState,
|
|
1224
|
+
primitive: structs.PrimitiveState = {},
|
|
1225
|
+
depth_stencil: structs.DepthStencilState = optional,
|
|
1226
|
+
multisample: structs.MultisampleState = {},
|
|
1227
|
+
fragment: structs.FragmentState = optional,
|
|
1228
|
+
):
|
|
1229
|
+
"""Async version of `create_render_pipeline()`.
|
|
1230
|
+
|
|
1231
|
+
Both versions are compatible with WebGPU."""
|
|
1232
|
+
raise NotImplementedError()
|
|
1233
|
+
|
|
1234
|
+
# IDL: GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor = {}); -> USVString label = ""
|
|
1235
|
+
def create_command_encoder(self, *, label: str = ""):
|
|
1236
|
+
"""Create a `GPUCommandEncoder` object. A command
|
|
1237
|
+
encoder is used to record commands, which can then be submitted
|
|
1238
|
+
at once to the GPU.
|
|
1239
|
+
|
|
1240
|
+
Arguments:
|
|
1241
|
+
label (str): A human-readable label. Optional.
|
|
1242
|
+
"""
|
|
1243
|
+
raise NotImplementedError()
|
|
1244
|
+
|
|
1245
|
+
# IDL: GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor); -> USVString label = "", required sequence<GPUTextureFormat?> colorFormats, GPUTextureFormat depthStencilFormat, GPUSize32 sampleCount = 1, boolean depthReadOnly = false, boolean stencilReadOnly = false
|
|
1246
|
+
def create_render_bundle_encoder(
|
|
1247
|
+
self,
|
|
1248
|
+
*,
|
|
1249
|
+
label: str = "",
|
|
1250
|
+
color_formats: List[enums.TextureFormat],
|
|
1251
|
+
depth_stencil_format: enums.TextureFormat = optional,
|
|
1252
|
+
sample_count: int = 1,
|
|
1253
|
+
depth_read_only: bool = False,
|
|
1254
|
+
stencil_read_only: bool = False,
|
|
1255
|
+
):
|
|
1256
|
+
"""Create a `GPURenderBundleEncoder` object.
|
|
1257
|
+
|
|
1258
|
+
Render bundles represent a pre-recorded bundle of commands. In cases where the same
|
|
1259
|
+
commands are issued across multiple views or frames, using a rander bundle can improve
|
|
1260
|
+
performance by removing the overhead of repeating the commands.
|
|
1261
|
+
|
|
1262
|
+
Arguments:
|
|
1263
|
+
label (str): A human-readable label. Optional.
|
|
1264
|
+
color_formats (list): A list of the `GPUTextureFormats` of the color attachments for this pass or bundle.
|
|
1265
|
+
depth_stencil_format (GPUTextureFormat): The format of the depth/stencil attachment for this pass or bundle.
|
|
1266
|
+
sample_count (int): The number of samples per pixel in the attachments for this pass or bundle. Default 1.
|
|
1267
|
+
depth_read_only (bool): If true, indicates that the render bundle does not modify the depth component of any depth-stencil attachments. Default False.
|
|
1268
|
+
stencil_read_only (bool): If true, indicates that the render bundle does not modify the stencil component of any depth-stencil attachments. Default False.
|
|
1269
|
+
"""
|
|
1270
|
+
raise NotImplementedError()
|
|
1271
|
+
|
|
1272
|
+
# IDL: GPUQuerySet createQuerySet(GPUQuerySetDescriptor descriptor); -> USVString label = "", required GPUQueryType type, required GPUSize32 count
|
|
1273
|
+
def create_query_set(self, *, label: str = "", type: enums.QueryType, count: int):
|
|
1274
|
+
"""Create a `GPUQuerySet` object."""
|
|
1275
|
+
raise NotImplementedError()
|
|
1276
|
+
|
|
1277
|
+
# IDL: undefined pushErrorScope(GPUErrorFilter filter);
|
|
1278
|
+
@apidiff.hide
|
|
1279
|
+
def push_error_scope(self, filter: enums.ErrorFilter):
|
|
1280
|
+
"""Pushes a new GPU error scope onto the stack."""
|
|
1281
|
+
raise NotImplementedError()
|
|
1282
|
+
|
|
1283
|
+
# IDL: Promise<GPUError?> popErrorScope();
|
|
1284
|
+
@apidiff.hide
|
|
1285
|
+
def pop_error_scope_sync(self):
|
|
1286
|
+
"""Sync version of `pop_error_scope_async().
|
|
1287
|
+
|
|
1288
|
+
Provided by wgpu-py, but not compatible with WebGPU.
|
|
1289
|
+
"""
|
|
1290
|
+
raise NotImplementedError()
|
|
1291
|
+
|
|
1292
|
+
# IDL: Promise<GPUError?> popErrorScope();
|
|
1293
|
+
@apidiff.hide
|
|
1294
|
+
async def pop_error_scope_async(self):
|
|
1295
|
+
"""Pops a GPU error scope from the stack."""
|
|
1296
|
+
raise NotImplementedError()
|
|
1297
|
+
|
|
1298
|
+
# IDL: GPUExternalTexture importExternalTexture(GPUExternalTextureDescriptor descriptor); -> USVString label = "", required (HTMLVideoElement or VideoFrame) source, PredefinedColorSpace colorSpace = "srgb"
|
|
1299
|
+
@apidiff.hide("Specific to browsers")
|
|
1300
|
+
def import_external_texture(
|
|
1301
|
+
self,
|
|
1302
|
+
*,
|
|
1303
|
+
label: str = "",
|
|
1304
|
+
source: Union[memoryview, object],
|
|
1305
|
+
color_space: str = "srgb",
|
|
1306
|
+
):
|
|
1307
|
+
"""For browsers only."""
|
|
1308
|
+
raise NotImplementedError()
|
|
1309
|
+
|
|
1310
|
+
|
|
1311
|
+
class GPUBuffer(GPUObjectBase):
|
|
1312
|
+
"""Represents a block of memory that can be used in GPU operations.
|
|
1313
|
+
|
|
1314
|
+
Data is stored in linear layout, meaning that each byte
|
|
1315
|
+
of the allocation can be addressed by its offset from the start of
|
|
1316
|
+
the buffer, subject to alignment restrictions depending on the
|
|
1317
|
+
operation.
|
|
1318
|
+
|
|
1319
|
+
Create a buffer using `GPUDevice.create_buffer()`.
|
|
1320
|
+
|
|
1321
|
+
One can sync data in a buffer by mapping it and then getting and setting data.
|
|
1322
|
+
Alternatively, one can tell the GPU (via the command encoder) to
|
|
1323
|
+
copy data between buffers and textures.
|
|
1324
|
+
"""
|
|
1325
|
+
|
|
1326
|
+
def __init__(self, label, internal, device, size, usage, map_state):
|
|
1327
|
+
self._nbytes = size
|
|
1328
|
+
super().__init__(label, internal, device)
|
|
1329
|
+
self._size = size
|
|
1330
|
+
self._usage = usage
|
|
1331
|
+
self._map_state = map_state
|
|
1332
|
+
|
|
1333
|
+
# IDL: readonly attribute GPUSize64Out size;
|
|
1334
|
+
@property
|
|
1335
|
+
def size(self):
|
|
1336
|
+
"""The length of the GPUBuffer allocation in bytes."""
|
|
1337
|
+
return self._size
|
|
1338
|
+
|
|
1339
|
+
# IDL: readonly attribute GPUFlagsConstant usage;
|
|
1340
|
+
@property
|
|
1341
|
+
def usage(self):
|
|
1342
|
+
"""The allowed usages (int bitmap) for this GPUBuffer, specifying
|
|
1343
|
+
e.g. whether the buffer may be used as a vertex buffer, uniform buffer,
|
|
1344
|
+
target or source for copying data, etc.
|
|
1345
|
+
"""
|
|
1346
|
+
return self._usage
|
|
1347
|
+
|
|
1348
|
+
# IDL: readonly attribute GPUBufferMapState mapState;
|
|
1349
|
+
@property
|
|
1350
|
+
def map_state(self):
|
|
1351
|
+
"""The mapping state of the buffer, see `BufferMapState`."""
|
|
1352
|
+
return self._map_state
|
|
1353
|
+
|
|
1354
|
+
# WebGPU specifies an API to sync data with the buffer via mapping.
|
|
1355
|
+
# The idea is to (async) request mapped data, read from / write to
|
|
1356
|
+
# this memory (using getMappedRange), and then unmap. A buffer
|
|
1357
|
+
# must be unmapped before it can be used in a pipeline.
|
|
1358
|
+
#
|
|
1359
|
+
# This means that the mapped memory is reclaimed (i.e. invalid)
|
|
1360
|
+
# when unmap is called, and that whatever object we expose the
|
|
1361
|
+
# memory with to the user, must be set to a state where it can no
|
|
1362
|
+
# longer be used. There does not seem to be a good way to do this.
|
|
1363
|
+
#
|
|
1364
|
+
# In our Python API we do make use of the same map/unmap mechanism,
|
|
1365
|
+
# but reading and writing data goes via method calls instead of via
|
|
1366
|
+
# an array-like object that exposes the shared memory.
|
|
1367
|
+
|
|
1368
|
+
# IDL: Promise<undefined> mapAsync(GPUMapModeFlags mode, optional GPUSize64 offset = 0, optional GPUSize64 size);
|
|
1369
|
+
def map_sync(
|
|
1370
|
+
self, mode: flags.MapMode, offset: int = 0, size: Optional[int] = None
|
|
1371
|
+
):
|
|
1372
|
+
"""Sync version of `map_async()`.
|
|
1373
|
+
|
|
1374
|
+
Provided by wgpu-py, but not compatible with WebGPU.
|
|
1375
|
+
"""
|
|
1376
|
+
raise NotImplementedError()
|
|
1377
|
+
|
|
1378
|
+
# IDL: Promise<undefined> mapAsync(GPUMapModeFlags mode, optional GPUSize64 offset = 0, optional GPUSize64 size);
|
|
1379
|
+
async def map_async(
|
|
1380
|
+
self, mode: flags.MapMode, offset: int = 0, size: Optional[int] = None
|
|
1381
|
+
):
|
|
1382
|
+
"""Maps the given range of the GPUBuffer.
|
|
1383
|
+
|
|
1384
|
+
When this call returns, the buffer content is ready to be
|
|
1385
|
+
accessed with ``read_mapped`` or ``write_mapped``. Don't forget
|
|
1386
|
+
to ``unmap()`` when done.
|
|
1387
|
+
|
|
1388
|
+
Arguments:
|
|
1389
|
+
mode (enum): The mapping mode, either wgpu.MapMode.READ or
|
|
1390
|
+
wgpu.MapMode.WRITE, can also be a string.
|
|
1391
|
+
offset (str): the buffer offset in bytes. Default 0.
|
|
1392
|
+
size (int): the size to read. Default until the end.
|
|
1393
|
+
|
|
1394
|
+
Alignment: the offset must be a multiple of 8, the size must be a multiple of 4.
|
|
1395
|
+
"""
|
|
1396
|
+
raise NotImplementedError()
|
|
1397
|
+
|
|
1398
|
+
# IDL: undefined unmap();
|
|
1399
|
+
def unmap(self):
|
|
1400
|
+
"""Unmaps the buffer.
|
|
1401
|
+
|
|
1402
|
+
Unmaps the mapped range of the GPUBuffer and makes its contents
|
|
1403
|
+
available for use by the GPU again.
|
|
1404
|
+
"""
|
|
1405
|
+
raise NotImplementedError()
|
|
1406
|
+
|
|
1407
|
+
@apidiff.add("Replacement for get_mapped_range")
|
|
1408
|
+
def read_mapped(self, buffer_offset=None, size=None, *, copy=True):
|
|
1409
|
+
"""Read mapped buffer data.
|
|
1410
|
+
|
|
1411
|
+
This method must only be called when the buffer is in a mapped state.
|
|
1412
|
+
This is the Python alternative to WebGPU's ``getMappedRange``.
|
|
1413
|
+
Returns a memoryview that is a copy of the mapped data (it won't
|
|
1414
|
+
become invalid when the buffer is ummapped).
|
|
1415
|
+
|
|
1416
|
+
Arguments:
|
|
1417
|
+
buffer_offset (int): the buffer offset in bytes. Must be at
|
|
1418
|
+
least as large as the offset specified in ``map()``. The default
|
|
1419
|
+
is the offset of the mapped range.
|
|
1420
|
+
size (int): the size to read (in bytes). The resulting range must fit into the range
|
|
1421
|
+
specified in ``map()``. The default is as large as the mapped range allows.
|
|
1422
|
+
copy (bool): whether a copy of the data is given. Default True.
|
|
1423
|
+
If False, the returned memoryview represents the mapped data
|
|
1424
|
+
directly, and is released when the buffer is unmapped.
|
|
1425
|
+
WARNING: views of the returned data (e.g. memoryview objects or
|
|
1426
|
+
numpy arrays) can still be used after the base memory is released,
|
|
1427
|
+
which can result in corrupted data and segfaults. Therefore, when
|
|
1428
|
+
setting copy to False, make *very* sure the memory is not accessed
|
|
1429
|
+
after the buffer is unmapped.
|
|
1430
|
+
|
|
1431
|
+
Alignment: the buffer offset must be a multiple of 8, the size must be a multiple of 4.
|
|
1432
|
+
|
|
1433
|
+
Also see `GPUBuffer.write_mapped()`, `GPUQueue.read_buffer()` and `GPUQueue.write_buffer()`.
|
|
1434
|
+
"""
|
|
1435
|
+
raise NotImplementedError()
|
|
1436
|
+
|
|
1437
|
+
@apidiff.add("Replacement for get_mapped_range")
|
|
1438
|
+
def write_mapped(self, data, buffer_offset=None):
|
|
1439
|
+
"""Write mapped buffer data.
|
|
1440
|
+
|
|
1441
|
+
This method must only be called when the buffer is in a mapped state.
|
|
1442
|
+
This is the Python alternative to WebGPU's ``getMappedRange``.
|
|
1443
|
+
Since the data can also be a view into a larger array, this method
|
|
1444
|
+
allows updating the buffer with minimal data copying.
|
|
1445
|
+
|
|
1446
|
+
Arguments:
|
|
1447
|
+
data (buffer-like): The data to write to the buffer.
|
|
1448
|
+
Must be an object that supports the buffer protocol,
|
|
1449
|
+
e.g. bytes, memoryview, numpy array, etc. Does not have to
|
|
1450
|
+
be contiguous, since the data is copied anyway.
|
|
1451
|
+
buffer_offset (int): the buffer offset in bytes. Must be at least
|
|
1452
|
+
as large as the offset specified in ``map()``. The default
|
|
1453
|
+
is the offset of the mapped range.
|
|
1454
|
+
|
|
1455
|
+
Alignment: the buffer offset must be a multiple of 8.
|
|
1456
|
+
|
|
1457
|
+
|
|
1458
|
+
Also see `GPUBuffer.read_mapped, `GPUQueue.read_buffer()` and `GPUQueue.write_buffer()`.
|
|
1459
|
+
"""
|
|
1460
|
+
raise NotImplementedError()
|
|
1461
|
+
|
|
1462
|
+
# IDL: ArrayBuffer getMappedRange(optional GPUSize64 offset = 0, optional GPUSize64 size);
|
|
1463
|
+
@apidiff.hide
|
|
1464
|
+
def get_mapped_range(self, offset: int = 0, size: Optional[int] = None):
|
|
1465
|
+
raise NotImplementedError("The Python API differs from WebGPU here")
|
|
1466
|
+
|
|
1467
|
+
# IDL: undefined destroy();
|
|
1468
|
+
def destroy(self):
|
|
1469
|
+
"""Destroy the buffer.
|
|
1470
|
+
|
|
1471
|
+
Explicitly destroys the buffer, freeing its memory and putting
|
|
1472
|
+
the object in an unusable state. In general its easier (and
|
|
1473
|
+
safer) to just let the garbage collector do its thing.
|
|
1474
|
+
"""
|
|
1475
|
+
raise NotImplementedError()
|
|
1476
|
+
|
|
1477
|
+
|
|
1478
|
+
class GPUTexture(GPUObjectBase):
|
|
1479
|
+
"""Represents a 1D, 2D or 3D color image object.
|
|
1480
|
+
|
|
1481
|
+
A texture also can have mipmaps (different levels of varying
|
|
1482
|
+
detail), and arrays. The texture represents the "raw" data. A
|
|
1483
|
+
`GPUTextureView` is used to define how the texture data
|
|
1484
|
+
should be interpreted.
|
|
1485
|
+
|
|
1486
|
+
Create a texture using `GPUDevice.create_texture()`.
|
|
1487
|
+
"""
|
|
1488
|
+
|
|
1489
|
+
def __init__(self, label, internal, device, tex_info):
|
|
1490
|
+
self._nbytes = self._estimate_nbytes(tex_info)
|
|
1491
|
+
super().__init__(label, internal, device)
|
|
1492
|
+
self._tex_info = tex_info
|
|
1493
|
+
|
|
1494
|
+
def _estimate_nbytes(self, tex_info):
|
|
1495
|
+
format = tex_info["format"]
|
|
1496
|
+
size = tex_info["size"]
|
|
1497
|
+
sample_count = tex_info["sample_count"] or 1
|
|
1498
|
+
mip_level_count = tex_info["mip_level_count"] or 1
|
|
1499
|
+
|
|
1500
|
+
bpp = texture_format_to_bpp.get(format, 0)
|
|
1501
|
+
npixels = size[0] * size[1] * size[2]
|
|
1502
|
+
nbytes_at_mip_level = sample_count * npixels * bpp / 8
|
|
1503
|
+
|
|
1504
|
+
nbytes = 0
|
|
1505
|
+
for i in range(mip_level_count):
|
|
1506
|
+
nbytes += nbytes_at_mip_level
|
|
1507
|
+
nbytes_at_mip_level /= 2
|
|
1508
|
+
|
|
1509
|
+
# Return rounded to nearest integer
|
|
1510
|
+
return int(nbytes + 0.5)
|
|
1511
|
+
|
|
1512
|
+
@apidiff.add("Too useful to not-have")
|
|
1513
|
+
@property
|
|
1514
|
+
def size(self):
|
|
1515
|
+
"""The size of the texture in mipmap level 0, as a 3-tuple of ints."""
|
|
1516
|
+
return self._tex_info["size"]
|
|
1517
|
+
|
|
1518
|
+
# IDL: readonly attribute GPUIntegerCoordinateOut width;
|
|
1519
|
+
@property
|
|
1520
|
+
def width(self):
|
|
1521
|
+
"""The texture's width. Also see ``.size``."""
|
|
1522
|
+
return self._tex_info["size"][0]
|
|
1523
|
+
|
|
1524
|
+
# IDL: readonly attribute GPUIntegerCoordinateOut height;
|
|
1525
|
+
@property
|
|
1526
|
+
def height(self):
|
|
1527
|
+
"""The texture's height. Also see ``.size``."""
|
|
1528
|
+
return self._tex_info["size"][1]
|
|
1529
|
+
|
|
1530
|
+
# IDL: readonly attribute GPUIntegerCoordinateOut depthOrArrayLayers;
|
|
1531
|
+
@property
|
|
1532
|
+
def depth_or_array_layers(self):
|
|
1533
|
+
"""The texture's depth or number of layers. Also see ``.size``."""
|
|
1534
|
+
return self._tex_info["size"][2]
|
|
1535
|
+
|
|
1536
|
+
# IDL: readonly attribute GPUIntegerCoordinateOut mipLevelCount;
|
|
1537
|
+
@property
|
|
1538
|
+
def mip_level_count(self):
|
|
1539
|
+
"""The total number of the mipmap levels of the texture."""
|
|
1540
|
+
return self._tex_info["mip_level_count"]
|
|
1541
|
+
|
|
1542
|
+
# IDL: readonly attribute GPUSize32Out sampleCount;
|
|
1543
|
+
@property
|
|
1544
|
+
def sample_count(self):
|
|
1545
|
+
"""The number of samples in each texel of the texture."""
|
|
1546
|
+
return self._tex_info["sample_count"]
|
|
1547
|
+
|
|
1548
|
+
# IDL: readonly attribute GPUTextureDimension dimension;
|
|
1549
|
+
@property
|
|
1550
|
+
def dimension(self):
|
|
1551
|
+
"""The dimension of the texture."""
|
|
1552
|
+
return self._tex_info["dimension"]
|
|
1553
|
+
|
|
1554
|
+
# IDL: readonly attribute GPUTextureFormat format;
|
|
1555
|
+
@property
|
|
1556
|
+
def format(self):
|
|
1557
|
+
"""The format of the texture."""
|
|
1558
|
+
return self._tex_info["format"]
|
|
1559
|
+
|
|
1560
|
+
# IDL: readonly attribute GPUFlagsConstant usage;
|
|
1561
|
+
@property
|
|
1562
|
+
def usage(self):
|
|
1563
|
+
"""The allowed usages for this texture."""
|
|
1564
|
+
return self._tex_info["usage"]
|
|
1565
|
+
|
|
1566
|
+
# IDL: GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {}); -> USVString label = "", GPUTextureFormat format, GPUTextureViewDimension dimension, GPUTextureAspect aspect = "all", GPUIntegerCoordinate baseMipLevel = 0, GPUIntegerCoordinate mipLevelCount, GPUIntegerCoordinate baseArrayLayer = 0, GPUIntegerCoordinate arrayLayerCount
|
|
1567
|
+
def create_view(
|
|
1568
|
+
self,
|
|
1569
|
+
*,
|
|
1570
|
+
label: str = "",
|
|
1571
|
+
format: enums.TextureFormat = optional,
|
|
1572
|
+
dimension: enums.TextureViewDimension = optional,
|
|
1573
|
+
aspect: enums.TextureAspect = "all",
|
|
1574
|
+
base_mip_level: int = 0,
|
|
1575
|
+
mip_level_count: int = optional,
|
|
1576
|
+
base_array_layer: int = 0,
|
|
1577
|
+
array_layer_count: int = optional,
|
|
1578
|
+
):
|
|
1579
|
+
"""Create a `GPUTextureView` object.
|
|
1580
|
+
|
|
1581
|
+
If no arguments are given, a default view is given, with the
|
|
1582
|
+
same format and dimension as the texture.
|
|
1583
|
+
|
|
1584
|
+
Arguments:
|
|
1585
|
+
label (str): A human-readable label. Optional.
|
|
1586
|
+
format (enums.TextureFormat): What channels it stores and how.
|
|
1587
|
+
dimension (enums.TextureViewDimension): The dimensionality of the texture view.
|
|
1588
|
+
aspect (enums.TextureAspect): Whether this view is used for depth, stencil, or all.
|
|
1589
|
+
Default all.
|
|
1590
|
+
base_mip_level (int): The starting mip level. Default 0.
|
|
1591
|
+
mip_level_count (int): The number of mip levels. Default None.
|
|
1592
|
+
base_array_layer (int): The starting array layer. Default 0.
|
|
1593
|
+
array_layer_count (int): The number of array layers. Default None.
|
|
1594
|
+
"""
|
|
1595
|
+
raise NotImplementedError()
|
|
1596
|
+
|
|
1597
|
+
# IDL: undefined destroy();
|
|
1598
|
+
def destroy(self):
|
|
1599
|
+
"""Destroy the texture.
|
|
1600
|
+
|
|
1601
|
+
Explicitly destroys the texture, freeing its memory and putting
|
|
1602
|
+
the object in an unusable state. In general its easier (and
|
|
1603
|
+
safer) to just let the garbage collector do its thing.
|
|
1604
|
+
"""
|
|
1605
|
+
raise NotImplementedError()
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
class GPUTextureView(GPUObjectBase):
|
|
1609
|
+
"""Represents a way to represent a `GPUTexture`.
|
|
1610
|
+
|
|
1611
|
+
Create a texture view using `GPUTexture.create_view()`.
|
|
1612
|
+
"""
|
|
1613
|
+
|
|
1614
|
+
def __init__(self, label, internal, device, texture, size):
|
|
1615
|
+
super().__init__(label, internal, device)
|
|
1616
|
+
self._texture = texture
|
|
1617
|
+
self._size = size
|
|
1618
|
+
|
|
1619
|
+
@apidiff.add("Need to know size e.g. for texture view provided by canvas")
|
|
1620
|
+
@property
|
|
1621
|
+
def size(self):
|
|
1622
|
+
"""The texture size (as a 3-tuple)."""
|
|
1623
|
+
return self._size
|
|
1624
|
+
|
|
1625
|
+
@apidiff.add("Too useful to not-have")
|
|
1626
|
+
@property
|
|
1627
|
+
def texture(self):
|
|
1628
|
+
"""The texture object to which this is a view."""
|
|
1629
|
+
return self._texture
|
|
1630
|
+
|
|
1631
|
+
|
|
1632
|
+
class GPUSampler(GPUObjectBase):
|
|
1633
|
+
"""Defines how a texture (view) must be sampled by the shader.
|
|
1634
|
+
|
|
1635
|
+
It defines the subsampling, sampling between mip levels, and sampling out
|
|
1636
|
+
of the image boundaries.
|
|
1637
|
+
|
|
1638
|
+
Create a sampler using `GPUDevice.create_sampler()`.
|
|
1639
|
+
"""
|
|
1640
|
+
|
|
1641
|
+
|
|
1642
|
+
class GPUBindGroupLayout(GPUObjectBase):
|
|
1643
|
+
"""Defines the interface between a set of resources bound in a `GPUBindGroup`.
|
|
1644
|
+
|
|
1645
|
+
It also defines their accessibility in shader stages.
|
|
1646
|
+
|
|
1647
|
+
Create a bind group layout using `GPUDevice.create_bind_group_layout()`.
|
|
1648
|
+
"""
|
|
1649
|
+
|
|
1650
|
+
pass
|
|
1651
|
+
|
|
1652
|
+
|
|
1653
|
+
class GPUBindGroup(GPUObjectBase):
|
|
1654
|
+
"""Represents a group of resource bindings (buffer, sampler, texture-view).
|
|
1655
|
+
|
|
1656
|
+
It holds the shader slot and a reference to the resource (sampler,
|
|
1657
|
+
texture-view, buffer).
|
|
1658
|
+
|
|
1659
|
+
Create a bind group using `GPUDevice.create_bind_group()`.
|
|
1660
|
+
"""
|
|
1661
|
+
|
|
1662
|
+
pass
|
|
1663
|
+
|
|
1664
|
+
|
|
1665
|
+
class GPUPipelineLayout(GPUObjectBase):
|
|
1666
|
+
"""Describes the layout of a pipeline, as a list of `GPUBindGroupLayout` objects.
|
|
1667
|
+
|
|
1668
|
+
Create a pipeline layout using `GPUDevice.create_pipeline_layout()`.
|
|
1669
|
+
"""
|
|
1670
|
+
|
|
1671
|
+
pass
|
|
1672
|
+
|
|
1673
|
+
|
|
1674
|
+
class GPUShaderModule(GPUObjectBase):
|
|
1675
|
+
"""Represents a programmable shader.
|
|
1676
|
+
|
|
1677
|
+
Create a shader module using `GPUDevice.create_shader_module()`.
|
|
1678
|
+
"""
|
|
1679
|
+
|
|
1680
|
+
# IDL: Promise<GPUCompilationInfo> getCompilationInfo();
|
|
1681
|
+
def get_compilation_info_sync(self):
|
|
1682
|
+
"""Sync version of `get_compilation_info_async()`.
|
|
1683
|
+
|
|
1684
|
+
Provided by wgpu-py, but not compatible with WebGPU.
|
|
1685
|
+
"""
|
|
1686
|
+
raise NotImplementedError()
|
|
1687
|
+
|
|
1688
|
+
# IDL: Promise<GPUCompilationInfo> getCompilationInfo();
|
|
1689
|
+
async def get_compilation_info_async(self):
|
|
1690
|
+
"""Get shader compilation info. Always returns empty list at the moment."""
|
|
1691
|
+
# How can this return shader errors if one cannot create a
|
|
1692
|
+
# shader module when the shader source has errors?
|
|
1693
|
+
raise NotImplementedError()
|
|
1694
|
+
|
|
1695
|
+
|
|
1696
|
+
class GPUPipelineBase:
|
|
1697
|
+
"""A mixin class for render and compute pipelines."""
|
|
1698
|
+
|
|
1699
|
+
# IDL: [NewObject] GPUBindGroupLayout getBindGroupLayout(unsigned long index);
|
|
1700
|
+
def get_bind_group_layout(self, index: int):
|
|
1701
|
+
"""Get the bind group layout at the given index."""
|
|
1702
|
+
raise NotImplementedError()
|
|
1703
|
+
|
|
1704
|
+
|
|
1705
|
+
class GPUComputePipeline(GPUPipelineBase, GPUObjectBase):
|
|
1706
|
+
"""Represents a single pipeline for computations (no rendering).
|
|
1707
|
+
|
|
1708
|
+
Create a compute pipeline using `GPUDevice.create_compute_pipeline()`.
|
|
1709
|
+
"""
|
|
1710
|
+
|
|
1711
|
+
|
|
1712
|
+
class GPURenderPipeline(GPUPipelineBase, GPUObjectBase):
|
|
1713
|
+
"""Represents a single pipeline to draw something.
|
|
1714
|
+
|
|
1715
|
+
The rendering typically involves a vertex and fragment stage, though
|
|
1716
|
+
the latter is optional.
|
|
1717
|
+
The render target can come from a window on the screen or from an
|
|
1718
|
+
in-memory texture (off-screen rendering).
|
|
1719
|
+
|
|
1720
|
+
Create a render pipeline using `GPUDevice.create_render_pipeline()`.
|
|
1721
|
+
"""
|
|
1722
|
+
|
|
1723
|
+
|
|
1724
|
+
class GPUCommandBuffer(GPUObjectBase):
|
|
1725
|
+
"""Stores a series of commands generated by a `GPUCommandEncoder`.
|
|
1726
|
+
|
|
1727
|
+
The buffered commands can subsequently be submitted to a `GPUQueue`.
|
|
1728
|
+
|
|
1729
|
+
Command buffers are single use, you must only submit them once and
|
|
1730
|
+
submitting them destroys them. Use render bundles to re-use commands.
|
|
1731
|
+
|
|
1732
|
+
Create a command buffer using `GPUCommandEncoder.finish()`.
|
|
1733
|
+
"""
|
|
1734
|
+
|
|
1735
|
+
|
|
1736
|
+
class GPUCommandsMixin:
|
|
1737
|
+
"""Mixin for classes that encode commands."""
|
|
1738
|
+
|
|
1739
|
+
pass
|
|
1740
|
+
|
|
1741
|
+
|
|
1742
|
+
class GPUBindingCommandsMixin:
|
|
1743
|
+
"""Mixin for classes that defines bindings."""
|
|
1744
|
+
|
|
1745
|
+
# IDL: undefined setBindGroup(GPUIndex32 index, GPUBindGroup? bindGroup, Uint32Array dynamicOffsetsData, GPUSize64 dynamicOffsetsDataStart, GPUSize32 dynamicOffsetsDataLength);
|
|
1746
|
+
@apidiff.change(
|
|
1747
|
+
"In the WebGPU specification, this method has two different signatures."
|
|
1748
|
+
)
|
|
1749
|
+
def set_bind_group(
|
|
1750
|
+
self,
|
|
1751
|
+
index,
|
|
1752
|
+
bind_group,
|
|
1753
|
+
dynamic_offsets_data=[],
|
|
1754
|
+
dynamic_offsets_data_start=None,
|
|
1755
|
+
dynamic_offsets_data_length=None,
|
|
1756
|
+
):
|
|
1757
|
+
"""Associate the given bind group (i.e. group or resources) with the
|
|
1758
|
+
given slot/index.
|
|
1759
|
+
|
|
1760
|
+
Arguments:
|
|
1761
|
+
index (int): The slot to bind at.
|
|
1762
|
+
bind_group (GPUBindGroup): The bind group to bind.
|
|
1763
|
+
dynamic_offsets_data (list of int): A list of offsets (one for each entry in bind group marked as ``buffer.has_dynamic_offset``). Default ``[]``.
|
|
1764
|
+
dynamic_offsets_data_start (int): Offset in elements into dynamic_offsets_data where the buffer offset data begins. Default None.
|
|
1765
|
+
dynamic_offsets_data_length (int): Number of buffer offsets to read from dynamic_offsets_data. Default None.
|
|
1766
|
+
"""
|
|
1767
|
+
raise NotImplementedError()
|
|
1768
|
+
|
|
1769
|
+
|
|
1770
|
+
class GPUDebugCommandsMixin:
|
|
1771
|
+
"""Mixin for classes that support debug groups and markers."""
|
|
1772
|
+
|
|
1773
|
+
# IDL: undefined pushDebugGroup(USVString groupLabel);
|
|
1774
|
+
def push_debug_group(self, group_label: str):
|
|
1775
|
+
"""Push a named debug group into the command stream."""
|
|
1776
|
+
raise NotImplementedError()
|
|
1777
|
+
|
|
1778
|
+
# IDL: undefined popDebugGroup();
|
|
1779
|
+
def pop_debug_group(self):
|
|
1780
|
+
"""Pop the active debug group."""
|
|
1781
|
+
raise NotImplementedError()
|
|
1782
|
+
|
|
1783
|
+
# IDL: undefined insertDebugMarker(USVString markerLabel);
|
|
1784
|
+
def insert_debug_marker(self, marker_label: str):
|
|
1785
|
+
"""Insert the given message into the debug message queue."""
|
|
1786
|
+
raise NotImplementedError()
|
|
1787
|
+
|
|
1788
|
+
|
|
1789
|
+
class GPURenderCommandsMixin:
|
|
1790
|
+
"""Mixin for classes that provide rendering commands."""
|
|
1791
|
+
|
|
1792
|
+
# IDL: undefined setPipeline(GPURenderPipeline pipeline);
|
|
1793
|
+
def set_pipeline(self, pipeline: GPURenderPipeline):
|
|
1794
|
+
"""Set the pipeline for this render pass.
|
|
1795
|
+
|
|
1796
|
+
Arguments:
|
|
1797
|
+
pipeline (GPURenderPipeline): The pipeline to use.
|
|
1798
|
+
"""
|
|
1799
|
+
raise NotImplementedError()
|
|
1800
|
+
|
|
1801
|
+
# IDL: undefined setIndexBuffer(GPUBuffer buffer, GPUIndexFormat indexFormat, optional GPUSize64 offset = 0, optional GPUSize64 size);
|
|
1802
|
+
def set_index_buffer(
|
|
1803
|
+
self,
|
|
1804
|
+
buffer: GPUBuffer,
|
|
1805
|
+
index_format: enums.IndexFormat,
|
|
1806
|
+
offset: int = 0,
|
|
1807
|
+
size: Optional[int] = None,
|
|
1808
|
+
):
|
|
1809
|
+
"""Set the index buffer for this render pass.
|
|
1810
|
+
|
|
1811
|
+
Arguments:
|
|
1812
|
+
buffer (GPUBuffer): The buffer that contains the indices.
|
|
1813
|
+
index_format (GPUIndexFormat): The format of the index data
|
|
1814
|
+
contained in buffer. If `strip_index_format` is given in the
|
|
1815
|
+
call to `GPUDevice.create_render_pipeline()`, it must match.
|
|
1816
|
+
offset (int): The byte offset in the buffer. Default 0.
|
|
1817
|
+
size (int): The number of bytes to use. If zero, the remaining size
|
|
1818
|
+
(after offset) of the buffer is used. Default 0.
|
|
1819
|
+
"""
|
|
1820
|
+
raise NotImplementedError()
|
|
1821
|
+
|
|
1822
|
+
# IDL: undefined setVertexBuffer(GPUIndex32 slot, GPUBuffer? buffer, optional GPUSize64 offset = 0, optional GPUSize64 size);
|
|
1823
|
+
def set_vertex_buffer(
|
|
1824
|
+
self, slot: int, buffer: GPUBuffer, offset: int = 0, size: Optional[int] = None
|
|
1825
|
+
):
|
|
1826
|
+
"""Associate a vertex buffer with a bind slot.
|
|
1827
|
+
|
|
1828
|
+
Arguments:
|
|
1829
|
+
slot (int): The binding slot for the vertex buffer.
|
|
1830
|
+
buffer (GPUBuffer): The buffer that contains the vertex data.
|
|
1831
|
+
offset (int): The byte offset in the buffer. Default 0.
|
|
1832
|
+
size (int): The number of bytes to use. If zero, the remaining size
|
|
1833
|
+
(after offset) of the buffer is used. Default 0.
|
|
1834
|
+
|
|
1835
|
+
Alignment: the offset must be a multiple of 4.
|
|
1836
|
+
"""
|
|
1837
|
+
raise NotImplementedError()
|
|
1838
|
+
|
|
1839
|
+
# IDL: undefined draw(GPUSize32 vertexCount, optional GPUSize32 instanceCount = 1, optional GPUSize32 firstVertex = 0, optional GPUSize32 firstInstance = 0);
|
|
1840
|
+
def draw(
|
|
1841
|
+
self,
|
|
1842
|
+
vertex_count: int,
|
|
1843
|
+
instance_count: int = 1,
|
|
1844
|
+
first_vertex: int = 0,
|
|
1845
|
+
first_instance: int = 0,
|
|
1846
|
+
):
|
|
1847
|
+
"""Run the render pipeline without an index buffer.
|
|
1848
|
+
|
|
1849
|
+
Arguments:
|
|
1850
|
+
vertex_count (int): The number of vertices to draw.
|
|
1851
|
+
instance_count (int): The number of instances to draw. Default 1.
|
|
1852
|
+
first_vertex (int): The vertex offset. Default 0.
|
|
1853
|
+
first_instance (int): The instance offset. Default 0.
|
|
1854
|
+
"""
|
|
1855
|
+
raise NotImplementedError()
|
|
1856
|
+
|
|
1857
|
+
# IDL: undefined drawIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
|
|
1858
|
+
def draw_indirect(self, indirect_buffer: GPUBuffer, indirect_offset: int):
|
|
1859
|
+
"""Like `draw()`, but the function arguments are in a buffer.
|
|
1860
|
+
|
|
1861
|
+
Arguments:
|
|
1862
|
+
indirect_buffer (GPUBuffer): The buffer that contains the arguments.
|
|
1863
|
+
indirect_offset (int): The byte offset at which the arguments are.
|
|
1864
|
+
|
|
1865
|
+
Alignment: the indirect offset must be a multiple of 4.
|
|
1866
|
+
"""
|
|
1867
|
+
raise NotImplementedError()
|
|
1868
|
+
|
|
1869
|
+
# IDL: undefined drawIndexed(GPUSize32 indexCount, optional GPUSize32 instanceCount = 1, optional GPUSize32 firstIndex = 0, optional GPUSignedOffset32 baseVertex = 0, optional GPUSize32 firstInstance = 0);
|
|
1870
|
+
def draw_indexed(
|
|
1871
|
+
self,
|
|
1872
|
+
index_count: int,
|
|
1873
|
+
instance_count: int = 1,
|
|
1874
|
+
first_index: int = 0,
|
|
1875
|
+
base_vertex: int = 0,
|
|
1876
|
+
first_instance: int = 0,
|
|
1877
|
+
):
|
|
1878
|
+
"""Run the render pipeline using an index buffer.
|
|
1879
|
+
|
|
1880
|
+
Arguments:
|
|
1881
|
+
index_count (int): The number of indices to draw.
|
|
1882
|
+
instance_count (int): The number of instances to draw. Default 1.
|
|
1883
|
+
first_index (int): The index offset. Default 0.
|
|
1884
|
+
base_vertex (int): A number added to each index in the index buffer. Default 0.
|
|
1885
|
+
first_instance (int): The instance offset. Default 0.
|
|
1886
|
+
|
|
1887
|
+
Alignment: the indirect offset must be a multiple of 4.
|
|
1888
|
+
"""
|
|
1889
|
+
raise NotImplementedError()
|
|
1890
|
+
|
|
1891
|
+
# IDL: undefined drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
|
|
1892
|
+
def draw_indexed_indirect(self, indirect_buffer: GPUBuffer, indirect_offset: int):
|
|
1893
|
+
"""
|
|
1894
|
+
Like `draw_indexed()`, but the function arguments are in a buffer.
|
|
1895
|
+
|
|
1896
|
+
Arguments:
|
|
1897
|
+
indirect_buffer (GPUBuffer): The buffer that contains the arguments.
|
|
1898
|
+
indirect_offset (int): The byte offset at which the arguments are.
|
|
1899
|
+
"""
|
|
1900
|
+
raise NotImplementedError()
|
|
1901
|
+
|
|
1902
|
+
|
|
1903
|
+
class GPUCommandEncoder(GPUCommandsMixin, GPUDebugCommandsMixin, GPUObjectBase):
|
|
1904
|
+
"""Object to record a series of commands.
|
|
1905
|
+
|
|
1906
|
+
When done, call `finish()` to obtain a `GPUCommandBuffer` object.
|
|
1907
|
+
|
|
1908
|
+
Create a command encoder using `GPUDevice.create_command_encoder()`.
|
|
1909
|
+
"""
|
|
1910
|
+
|
|
1911
|
+
# IDL: GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {}); -> USVString label = "", GPUComputePassTimestampWrites timestampWrites
|
|
1912
|
+
def begin_compute_pass(
|
|
1913
|
+
self,
|
|
1914
|
+
*,
|
|
1915
|
+
label: str = "",
|
|
1916
|
+
timestamp_writes: structs.ComputePassTimestampWrites = optional,
|
|
1917
|
+
):
|
|
1918
|
+
"""Record the beginning of a compute pass. Returns a
|
|
1919
|
+
`GPUComputePassEncoder` object.
|
|
1920
|
+
|
|
1921
|
+
Arguments:
|
|
1922
|
+
label (str): A human-readable label. Optional.
|
|
1923
|
+
timestamp_writes: unused
|
|
1924
|
+
"""
|
|
1925
|
+
raise NotImplementedError()
|
|
1926
|
+
|
|
1927
|
+
# IDL: GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor); -> USVString label = "", required sequence<GPURenderPassColorAttachment?> colorAttachments, GPURenderPassDepthStencilAttachment depthStencilAttachment, GPUQuerySet occlusionQuerySet, GPURenderPassTimestampWrites timestampWrites, GPUSize64 maxDrawCount = 50000000
|
|
1928
|
+
def begin_render_pass(
|
|
1929
|
+
self,
|
|
1930
|
+
*,
|
|
1931
|
+
label: str = "",
|
|
1932
|
+
color_attachments: List[structs.RenderPassColorAttachment],
|
|
1933
|
+
depth_stencil_attachment: structs.RenderPassDepthStencilAttachment = optional,
|
|
1934
|
+
occlusion_query_set: GPUQuerySet = optional,
|
|
1935
|
+
timestamp_writes: structs.RenderPassTimestampWrites = optional,
|
|
1936
|
+
max_draw_count: int = 50000000,
|
|
1937
|
+
):
|
|
1938
|
+
"""Record the beginning of a render pass. Returns a
|
|
1939
|
+
`GPURenderPassEncoder` object.
|
|
1940
|
+
|
|
1941
|
+
Arguments:
|
|
1942
|
+
label (str): A human-readable label. Optional.
|
|
1943
|
+
color_attachments (list): List of `structs.RenderPassColorAttachment` dicts.
|
|
1944
|
+
depth_stencil_attachment (structs.RenderPassDepthStencilAttachment): Describes the depth stencil attachment. Default None.
|
|
1945
|
+
occlusion_query_set (GPUQuerySet): Default None.
|
|
1946
|
+
timestamp_writes: unused
|
|
1947
|
+
"""
|
|
1948
|
+
raise NotImplementedError()
|
|
1949
|
+
|
|
1950
|
+
# IDL: undefined clearBuffer( GPUBuffer buffer, optional GPUSize64 offset = 0, optional GPUSize64 size);
|
|
1951
|
+
def clear_buffer(
|
|
1952
|
+
self, buffer: GPUBuffer, offset: int = 0, size: Optional[int] = None
|
|
1953
|
+
):
|
|
1954
|
+
"""Set (part of) the given buffer to zeros.
|
|
1955
|
+
|
|
1956
|
+
Arguments:
|
|
1957
|
+
buffer (GPUBuffer): The buffer to clear.
|
|
1958
|
+
offset (int): The byte offset.
|
|
1959
|
+
size (int, optional): The size to clear in bytes. If None, the effective size is the full size minus the offset.
|
|
1960
|
+
|
|
1961
|
+
Alignment: both offset and size must be a multiple of 4.
|
|
1962
|
+
"""
|
|
1963
|
+
raise NotImplementedError()
|
|
1964
|
+
|
|
1965
|
+
# IDL: undefined copyBufferToBuffer( GPUBuffer source, GPUSize64 sourceOffset, GPUBuffer destination, GPUSize64 destinationOffset, GPUSize64 size);
|
|
1966
|
+
def copy_buffer_to_buffer(
|
|
1967
|
+
self,
|
|
1968
|
+
source: GPUBuffer,
|
|
1969
|
+
source_offset: int,
|
|
1970
|
+
destination: GPUBuffer,
|
|
1971
|
+
destination_offset: int,
|
|
1972
|
+
size: int,
|
|
1973
|
+
):
|
|
1974
|
+
"""Copy the contents of a buffer to another buffer.
|
|
1975
|
+
|
|
1976
|
+
Arguments:
|
|
1977
|
+
source (GPUBuffer): The source buffer.
|
|
1978
|
+
source_offset (int): The byte offset.
|
|
1979
|
+
destination (GPUBuffer): The target buffer.
|
|
1980
|
+
destination_offset (int): The byte offset in the destination buffer.
|
|
1981
|
+
size (int): The number of bytes to copy.
|
|
1982
|
+
|
|
1983
|
+
Alignment: the size, source offset, and destination offset must all be a multiple of 4.
|
|
1984
|
+
"""
|
|
1985
|
+
raise NotImplementedError()
|
|
1986
|
+
|
|
1987
|
+
# IDL: undefined copyBufferToTexture( GPUImageCopyBuffer source, GPUImageCopyTexture destination, GPUExtent3D copySize);
|
|
1988
|
+
def copy_buffer_to_texture(
|
|
1989
|
+
self,
|
|
1990
|
+
source: structs.ImageCopyBuffer,
|
|
1991
|
+
destination: structs.ImageCopyTexture,
|
|
1992
|
+
copy_size: Union[List[int], structs.Extent3D],
|
|
1993
|
+
):
|
|
1994
|
+
"""Copy the contents of a buffer to a texture (view).
|
|
1995
|
+
|
|
1996
|
+
Arguments:
|
|
1997
|
+
source (GPUBuffer): A dict with fields: buffer, offset, bytes_per_row, rows_per_image.
|
|
1998
|
+
destination (GPUTexture): A dict with fields: texture, mip_level, origin.
|
|
1999
|
+
copy_size (int): The number of bytes to copy.
|
|
2000
|
+
|
|
2001
|
+
Alignment: the ``bytes_per_row`` must be a multiple of 256.
|
|
2002
|
+
"""
|
|
2003
|
+
raise NotImplementedError()
|
|
2004
|
+
|
|
2005
|
+
# IDL: undefined copyTextureToBuffer( GPUImageCopyTexture source, GPUImageCopyBuffer destination, GPUExtent3D copySize);
|
|
2006
|
+
def copy_texture_to_buffer(
|
|
2007
|
+
self,
|
|
2008
|
+
source: structs.ImageCopyTexture,
|
|
2009
|
+
destination: structs.ImageCopyBuffer,
|
|
2010
|
+
copy_size: Union[List[int], structs.Extent3D],
|
|
2011
|
+
):
|
|
2012
|
+
"""Copy the contents of a texture (view) to a buffer.
|
|
2013
|
+
|
|
2014
|
+
Arguments:
|
|
2015
|
+
source (GPUTexture): A dict with fields: texture, mip_level, origin.
|
|
2016
|
+
destination (GPUBuffer): A dict with fields: buffer, offset, bytes_per_row, rows_per_image.
|
|
2017
|
+
copy_size (int): The number of bytes to copy.
|
|
2018
|
+
|
|
2019
|
+
Alignment: the ``bytes_per_row`` must be a multiple of 256.
|
|
2020
|
+
"""
|
|
2021
|
+
raise NotImplementedError()
|
|
2022
|
+
|
|
2023
|
+
# IDL: undefined copyTextureToTexture( GPUImageCopyTexture source, GPUImageCopyTexture destination, GPUExtent3D copySize);
|
|
2024
|
+
def copy_texture_to_texture(
|
|
2025
|
+
self,
|
|
2026
|
+
source: structs.ImageCopyTexture,
|
|
2027
|
+
destination: structs.ImageCopyTexture,
|
|
2028
|
+
copy_size: Union[List[int], structs.Extent3D],
|
|
2029
|
+
):
|
|
2030
|
+
"""Copy the contents of a texture (view) to another texture (view).
|
|
2031
|
+
|
|
2032
|
+
Arguments:
|
|
2033
|
+
source (GPUTexture): A dict with fields: texture, mip_level, origin.
|
|
2034
|
+
destination (GPUTexture): A dict with fields: texture, mip_level, origin.
|
|
2035
|
+
copy_size (int): The number of bytes to copy.
|
|
2036
|
+
"""
|
|
2037
|
+
raise NotImplementedError()
|
|
2038
|
+
|
|
2039
|
+
# IDL: GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor = {}); -> USVString label = ""
|
|
2040
|
+
def finish(self, *, label: str = ""):
|
|
2041
|
+
"""Finish recording. Returns a `GPUCommandBuffer` to
|
|
2042
|
+
submit to a `GPUQueue`.
|
|
2043
|
+
|
|
2044
|
+
Arguments:
|
|
2045
|
+
label (str): A human-readable label. Optional.
|
|
2046
|
+
"""
|
|
2047
|
+
raise NotImplementedError()
|
|
2048
|
+
|
|
2049
|
+
# IDL: undefined resolveQuerySet( GPUQuerySet querySet, GPUSize32 firstQuery, GPUSize32 queryCount, GPUBuffer destination, GPUSize64 destinationOffset);
|
|
2050
|
+
def resolve_query_set(
|
|
2051
|
+
self,
|
|
2052
|
+
query_set: GPUQuerySet,
|
|
2053
|
+
first_query: int,
|
|
2054
|
+
query_count: int,
|
|
2055
|
+
destination: GPUBuffer,
|
|
2056
|
+
destination_offset: int,
|
|
2057
|
+
):
|
|
2058
|
+
"""
|
|
2059
|
+
Resolves query results from a ``GPUQuerySet`` out into a range of a ``GPUBuffer``.
|
|
2060
|
+
|
|
2061
|
+
Arguments:
|
|
2062
|
+
query_set (GPUQuerySet): The source query set.
|
|
2063
|
+
first_query (int): The first query to resolve.
|
|
2064
|
+
query_count (int): The amount of queries to resolve.
|
|
2065
|
+
destination (GPUBuffer): The buffer to write the results to.
|
|
2066
|
+
destination_offset (int): The byte offset in the buffer.
|
|
2067
|
+
|
|
2068
|
+
Alignment: the destination offset must be a multiple of 256.
|
|
2069
|
+
"""
|
|
2070
|
+
raise NotImplementedError()
|
|
2071
|
+
|
|
2072
|
+
|
|
2073
|
+
class GPUComputePassEncoder(
|
|
2074
|
+
GPUCommandsMixin, GPUDebugCommandsMixin, GPUBindingCommandsMixin, GPUObjectBase
|
|
2075
|
+
):
|
|
2076
|
+
"""Object to records commands for a compute pass.
|
|
2077
|
+
|
|
2078
|
+
Create a compute pass encoder using `GPUCommandEncoder.begin_compute_pass()`.
|
|
2079
|
+
"""
|
|
2080
|
+
|
|
2081
|
+
# IDL: undefined setPipeline(GPUComputePipeline pipeline);
|
|
2082
|
+
def set_pipeline(self, pipeline: GPUComputePipeline):
|
|
2083
|
+
"""Set the pipeline for this compute pass.
|
|
2084
|
+
|
|
2085
|
+
Arguments:
|
|
2086
|
+
pipeline (GPUComputePipeline): The pipeline to use.
|
|
2087
|
+
"""
|
|
2088
|
+
raise NotImplementedError()
|
|
2089
|
+
|
|
2090
|
+
# IDL: undefined dispatchWorkgroups(GPUSize32 workgroupCountX, optional GPUSize32 workgroupCountY = 1, optional GPUSize32 workgroupCountZ = 1);
|
|
2091
|
+
def dispatch_workgroups(
|
|
2092
|
+
self,
|
|
2093
|
+
workgroup_count_x: int,
|
|
2094
|
+
workgroup_count_y: int = 1,
|
|
2095
|
+
workgroup_count_z: int = 1,
|
|
2096
|
+
):
|
|
2097
|
+
"""Run the compute shader.
|
|
2098
|
+
|
|
2099
|
+
Arguments:
|
|
2100
|
+
x (int): The number of cycles in index x.
|
|
2101
|
+
y (int): The number of cycles in index y. Default 1.
|
|
2102
|
+
z (int): The number of cycles in index z. Default 1.
|
|
2103
|
+
"""
|
|
2104
|
+
raise NotImplementedError()
|
|
2105
|
+
|
|
2106
|
+
# IDL: undefined dispatchWorkgroupsIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
|
|
2107
|
+
def dispatch_workgroups_indirect(
|
|
2108
|
+
self, indirect_buffer: GPUBuffer, indirect_offset: int
|
|
2109
|
+
):
|
|
2110
|
+
"""Like `dispatch_workgroups()`, but the function arguments are in a buffer.
|
|
2111
|
+
|
|
2112
|
+
Arguments:
|
|
2113
|
+
indirect_buffer (GPUBuffer): The buffer that contains the arguments.
|
|
2114
|
+
indirect_offset (int): The byte offset at which the arguments are.
|
|
2115
|
+
"""
|
|
2116
|
+
raise NotImplementedError()
|
|
2117
|
+
|
|
2118
|
+
# IDL: undefined end();
|
|
2119
|
+
def end(self):
|
|
2120
|
+
"""Record the end of the compute pass."""
|
|
2121
|
+
raise NotImplementedError()
|
|
2122
|
+
|
|
2123
|
+
|
|
2124
|
+
class GPURenderPassEncoder(
|
|
2125
|
+
GPUCommandsMixin,
|
|
2126
|
+
GPUDebugCommandsMixin,
|
|
2127
|
+
GPUBindingCommandsMixin,
|
|
2128
|
+
GPURenderCommandsMixin,
|
|
2129
|
+
GPUObjectBase,
|
|
2130
|
+
):
|
|
2131
|
+
"""Object to records commands for a render pass.
|
|
2132
|
+
|
|
2133
|
+
Create a render pass encoder using `GPUCommandEncoder.begin_render_pass`.
|
|
2134
|
+
"""
|
|
2135
|
+
|
|
2136
|
+
# IDL: undefined setViewport(float x, float y, float width, float height, float minDepth, float maxDepth);
|
|
2137
|
+
def set_viewport(
|
|
2138
|
+
self,
|
|
2139
|
+
x: float,
|
|
2140
|
+
y: float,
|
|
2141
|
+
width: float,
|
|
2142
|
+
height: float,
|
|
2143
|
+
min_depth: float,
|
|
2144
|
+
max_depth: float,
|
|
2145
|
+
):
|
|
2146
|
+
"""Set the viewport for this render pass. The whole scene is rendered
|
|
2147
|
+
to this sub-rectangle.
|
|
2148
|
+
|
|
2149
|
+
Arguments:
|
|
2150
|
+
x (int): Horizontal coordinate.
|
|
2151
|
+
y (int): Vertical coordinate.
|
|
2152
|
+
width (int): Horizontal size.
|
|
2153
|
+
height (int): Vertical size.
|
|
2154
|
+
min_depth (int): Clipping in depth.
|
|
2155
|
+
max_depth (int): Clipping in depth.
|
|
2156
|
+
|
|
2157
|
+
"""
|
|
2158
|
+
raise NotImplementedError()
|
|
2159
|
+
|
|
2160
|
+
# IDL: undefined setScissorRect(GPUIntegerCoordinate x, GPUIntegerCoordinate y, GPUIntegerCoordinate width, GPUIntegerCoordinate height);
|
|
2161
|
+
def set_scissor_rect(self, x: int, y: int, width: int, height: int):
|
|
2162
|
+
"""Set the scissor rectangle for this render pass. The scene
|
|
2163
|
+
is rendered as usual, but is only applied to this sub-rectangle.
|
|
2164
|
+
|
|
2165
|
+
Arguments:
|
|
2166
|
+
x (int): Horizontal coordinate.
|
|
2167
|
+
y (int): Vertical coordinate.
|
|
2168
|
+
width (int): Horizontal size.
|
|
2169
|
+
height (int): Vertical size.
|
|
2170
|
+
"""
|
|
2171
|
+
raise NotImplementedError()
|
|
2172
|
+
|
|
2173
|
+
# IDL: undefined setBlendConstant(GPUColor color);
|
|
2174
|
+
def set_blend_constant(self, color: Union[List[float], structs.Color]):
|
|
2175
|
+
"""Set the blend color for the render pass.
|
|
2176
|
+
|
|
2177
|
+
Arguments:
|
|
2178
|
+
color (tuple or dict): A color with fields (r, g, b, a).
|
|
2179
|
+
"""
|
|
2180
|
+
raise NotImplementedError()
|
|
2181
|
+
|
|
2182
|
+
# IDL: undefined setStencilReference(GPUStencilValue reference);
|
|
2183
|
+
def set_stencil_reference(self, reference: int):
|
|
2184
|
+
"""Set the reference stencil value for this render pass.
|
|
2185
|
+
|
|
2186
|
+
Arguments:
|
|
2187
|
+
reference (int): The reference value.
|
|
2188
|
+
"""
|
|
2189
|
+
raise NotImplementedError()
|
|
2190
|
+
|
|
2191
|
+
# IDL: undefined executeBundles(sequence<GPURenderBundle> bundles);
|
|
2192
|
+
def execute_bundles(self, bundles: List[GPURenderBundle]):
|
|
2193
|
+
"""Executes commands previously recorded into the render bundles
|
|
2194
|
+
as part of this render pass.
|
|
2195
|
+
|
|
2196
|
+
Arguments:
|
|
2197
|
+
bundles (Sequence[GPURenderBundle]): A sequence of Render Bundle objects.
|
|
2198
|
+
"""
|
|
2199
|
+
raise NotImplementedError()
|
|
2200
|
+
|
|
2201
|
+
# IDL: undefined end();
|
|
2202
|
+
def end(self):
|
|
2203
|
+
"""Record the end of the render pass."""
|
|
2204
|
+
raise NotImplementedError()
|
|
2205
|
+
|
|
2206
|
+
# IDL: undefined beginOcclusionQuery(GPUSize32 queryIndex);
|
|
2207
|
+
def begin_occlusion_query(self, query_index: int):
|
|
2208
|
+
"""Begins an occlusion query.
|
|
2209
|
+
|
|
2210
|
+
Arguments:
|
|
2211
|
+
query_index (int): The index in the GPUQuerySet at which to write the
|
|
2212
|
+
result of the occlusion query. The Query Set is specified as the
|
|
2213
|
+
occlusion_query_set argument in begin_render_pass().
|
|
2214
|
+
"""
|
|
2215
|
+
|
|
2216
|
+
raise NotImplementedError()
|
|
2217
|
+
|
|
2218
|
+
# IDL: undefined endOcclusionQuery();
|
|
2219
|
+
def end_occlusion_query(self):
|
|
2220
|
+
"""Ends an occlusion query."""
|
|
2221
|
+
raise NotImplementedError()
|
|
2222
|
+
|
|
2223
|
+
|
|
2224
|
+
class GPURenderBundle(GPUObjectBase):
|
|
2225
|
+
"""A reusable bundle of render commands."""
|
|
2226
|
+
|
|
2227
|
+
pass
|
|
2228
|
+
|
|
2229
|
+
|
|
2230
|
+
class GPURenderBundleEncoder(
|
|
2231
|
+
GPUCommandsMixin,
|
|
2232
|
+
GPUDebugCommandsMixin,
|
|
2233
|
+
GPUBindingCommandsMixin,
|
|
2234
|
+
GPURenderCommandsMixin,
|
|
2235
|
+
GPUObjectBase,
|
|
2236
|
+
):
|
|
2237
|
+
"""Encodes a series of render commands into a reusable render bundle."""
|
|
2238
|
+
|
|
2239
|
+
# IDL: GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {}); -> USVString label = ""
|
|
2240
|
+
def finish(self, *, label: str = ""):
|
|
2241
|
+
"""Finish recording and return a `GPURenderBundle`.
|
|
2242
|
+
|
|
2243
|
+
Arguments:
|
|
2244
|
+
label (str): A human-readable label. Optional.
|
|
2245
|
+
"""
|
|
2246
|
+
raise NotImplementedError()
|
|
2247
|
+
|
|
2248
|
+
|
|
2249
|
+
class GPUQueue(GPUObjectBase):
|
|
2250
|
+
"""Object to submit command buffers to.
|
|
2251
|
+
|
|
2252
|
+
You can obtain a queue object via the :attr:`GPUDevice.queue` property.
|
|
2253
|
+
"""
|
|
2254
|
+
|
|
2255
|
+
# IDL: undefined submit(sequence<GPUCommandBuffer> commandBuffers);
|
|
2256
|
+
def submit(self, command_buffers: List[GPUCommandBuffer]):
|
|
2257
|
+
"""Submit a `GPUCommandBuffer` to the queue.
|
|
2258
|
+
|
|
2259
|
+
Arguments:
|
|
2260
|
+
command_buffers (list): The `GPUCommandBuffer` objects to add.
|
|
2261
|
+
"""
|
|
2262
|
+
raise NotImplementedError()
|
|
2263
|
+
|
|
2264
|
+
# IDL: undefined writeBuffer( GPUBuffer buffer, GPUSize64 bufferOffset, AllowSharedBufferSource data, optional GPUSize64 dataOffset = 0, optional GPUSize64 size);
|
|
2265
|
+
def write_buffer(
|
|
2266
|
+
self,
|
|
2267
|
+
buffer: GPUBuffer,
|
|
2268
|
+
buffer_offset: int,
|
|
2269
|
+
data: memoryview,
|
|
2270
|
+
data_offset: int = 0,
|
|
2271
|
+
size: Optional[int] = None,
|
|
2272
|
+
):
|
|
2273
|
+
"""Takes the data contents and schedules a write operation to the buffer.
|
|
2274
|
+
|
|
2275
|
+
Changes to the data after this function is called don't affect
|
|
2276
|
+
the buffer contents.
|
|
2277
|
+
|
|
2278
|
+
Arguments:
|
|
2279
|
+
buffer: The `GPUBuffer` object to write to.
|
|
2280
|
+
buffer_offset (int): The offset in the buffer to start writing at.
|
|
2281
|
+
data: The data to write to the buffer. Must be an object that supports
|
|
2282
|
+
the buffer protocol, e.g. bytes, memoryview, numpy array, etc.
|
|
2283
|
+
Must be contiguous.
|
|
2284
|
+
data_offset: The offset in the data, in elements. Default 0.
|
|
2285
|
+
size: The number of bytes to write. Default all minus offset.
|
|
2286
|
+
|
|
2287
|
+
This maps the data to a temporary buffer and then copies that buffer
|
|
2288
|
+
to the given buffer. The given buffer's usage must include COPY_DST.
|
|
2289
|
+
|
|
2290
|
+
Alignment: the buffer offset must be a multiple of 4, the total size to write must be a multiple of 4 bytes.
|
|
2291
|
+
|
|
2292
|
+
Also see `GPUBuffer.map_sync()` and `GPUBuffer.map_async()`.
|
|
2293
|
+
|
|
2294
|
+
"""
|
|
2295
|
+
raise NotImplementedError()
|
|
2296
|
+
|
|
2297
|
+
@apidiff.add("For symmetry with queue.write_buffer")
|
|
2298
|
+
def read_buffer(self, buffer, buffer_offset=0, size=None):
|
|
2299
|
+
"""Takes the data contents of the buffer and return them as a memoryview.
|
|
2300
|
+
|
|
2301
|
+
Arguments:
|
|
2302
|
+
buffer: The `GPUBuffer` object to read from.
|
|
2303
|
+
buffer_offset (int): The offset in the buffer to start reading from.
|
|
2304
|
+
size: The number of bytes to read. Default all minus offset.
|
|
2305
|
+
|
|
2306
|
+
This copies the data in the given buffer to a temporary buffer
|
|
2307
|
+
and then maps that buffer to read the data. The given buffer's
|
|
2308
|
+
usage must include COPY_SRC.
|
|
2309
|
+
|
|
2310
|
+
Also see `GPUBuffer._sync()` and `GPUBuffer._async()`.
|
|
2311
|
+
"""
|
|
2312
|
+
raise NotImplementedError()
|
|
2313
|
+
|
|
2314
|
+
# IDL: undefined writeTexture( GPUImageCopyTexture destination, AllowSharedBufferSource data, GPUImageDataLayout dataLayout, GPUExtent3D size);
|
|
2315
|
+
def write_texture(
|
|
2316
|
+
self,
|
|
2317
|
+
destination: structs.ImageCopyTexture,
|
|
2318
|
+
data: memoryview,
|
|
2319
|
+
data_layout: structs.ImageDataLayout,
|
|
2320
|
+
size: Union[List[int], structs.Extent3D],
|
|
2321
|
+
):
|
|
2322
|
+
"""Takes the data contents and schedules a write operation of
|
|
2323
|
+
these contents to the destination texture in the queue. A
|
|
2324
|
+
snapshot of the data is taken; any changes to the data after
|
|
2325
|
+
this function is called do not affect the texture contents.
|
|
2326
|
+
|
|
2327
|
+
Arguments:
|
|
2328
|
+
destination: A dict with fields: "texture" (a texture object),
|
|
2329
|
+
"origin" (a 3-tuple), "mip_level" (an int, default 0).
|
|
2330
|
+
data: The data to write to the texture. Must be an object that supports
|
|
2331
|
+
the buffer protocol, e.g. bytes, memoryview, numpy array, etc.
|
|
2332
|
+
Must be contiguous.
|
|
2333
|
+
data_layout: A dict with fields: "offset" (an int, default 0),
|
|
2334
|
+
"bytes_per_row" (an int), "rows_per_image" (an int, default 0).
|
|
2335
|
+
size: A 3-tuple of ints specifying the size to write.
|
|
2336
|
+
|
|
2337
|
+
Unlike `GPUCommandEncoder.copyBufferToTexture()`, there is
|
|
2338
|
+
no alignment requirement on `bytes_per_row`.
|
|
2339
|
+
"""
|
|
2340
|
+
raise NotImplementedError()
|
|
2341
|
+
|
|
2342
|
+
@apidiff.add("For symmetry, and to help work around the bytes_per_row constraint")
|
|
2343
|
+
def read_texture(self, source, data_layout, size):
|
|
2344
|
+
"""Reads the contents of the texture and return them as a memoryview.
|
|
2345
|
+
|
|
2346
|
+
Arguments:
|
|
2347
|
+
source: A dict with fields: "texture" (a texture object),
|
|
2348
|
+
"origin" (a 3-tuple), "mip_level" (an int, default 0).
|
|
2349
|
+
data_layout: A dict with fields: "offset" (an int, default 0),
|
|
2350
|
+
"bytes_per_row" (an int), "rows_per_image" (an int, default 0).
|
|
2351
|
+
size: A 3-tuple of ints specifying the size to write.
|
|
2352
|
+
|
|
2353
|
+
Unlike `GPUCommandEncoder.copyBufferToTexture()`, there is
|
|
2354
|
+
no alignment requirement on `bytes_per_row`, although in the
|
|
2355
|
+
current implementation there will be a performance penalty if
|
|
2356
|
+
``bytes_per_row`` is not a multiple of 256 (because we'll be
|
|
2357
|
+
copying data row-by-row in Python).
|
|
2358
|
+
"""
|
|
2359
|
+
raise NotImplementedError()
|
|
2360
|
+
|
|
2361
|
+
# IDL: undefined copyExternalImageToTexture( GPUImageCopyExternalImage source, GPUImageCopyTextureTagged destination, GPUExtent3D copySize);
|
|
2362
|
+
@apidiff.hide("Specific to browsers")
|
|
2363
|
+
def copy_external_image_to_texture(
|
|
2364
|
+
self,
|
|
2365
|
+
source: structs.ImageCopyExternalImage,
|
|
2366
|
+
destination: structs.ImageCopyTextureTagged,
|
|
2367
|
+
copy_size: Union[List[int], structs.Extent3D],
|
|
2368
|
+
):
|
|
2369
|
+
raise NotImplementedError()
|
|
2370
|
+
|
|
2371
|
+
# IDL: Promise<undefined> onSubmittedWorkDone();
|
|
2372
|
+
def on_submitted_work_done_sync(self):
|
|
2373
|
+
"""Sync version of `on_submitted_work_done_async()`.
|
|
2374
|
+
|
|
2375
|
+
Provided by wgpu-py, but not compatible with WebGPU.
|
|
2376
|
+
"""
|
|
2377
|
+
raise NotImplementedError()
|
|
2378
|
+
|
|
2379
|
+
# IDL: Promise<undefined> onSubmittedWorkDone();
|
|
2380
|
+
async def on_submitted_work_done_async(self):
|
|
2381
|
+
"""TODO"""
|
|
2382
|
+
raise NotImplementedError()
|
|
2383
|
+
|
|
2384
|
+
|
|
2385
|
+
# %% Further non-GPUObject classes
|
|
2386
|
+
|
|
2387
|
+
|
|
2388
|
+
class GPUDeviceLostInfo:
|
|
2389
|
+
"""An object that contains information about the device being lost."""
|
|
2390
|
+
|
|
2391
|
+
# Not used at the moment, see device.lost prop
|
|
2392
|
+
|
|
2393
|
+
def __init__(self, reason, message):
|
|
2394
|
+
self._reason = reason
|
|
2395
|
+
self._message = message
|
|
2396
|
+
|
|
2397
|
+
# IDL: readonly attribute DOMString message;
|
|
2398
|
+
@property
|
|
2399
|
+
def message(self):
|
|
2400
|
+
"""The error message specifying the reason for the device being lost."""
|
|
2401
|
+
return self._message
|
|
2402
|
+
|
|
2403
|
+
# IDL: readonly attribute GPUDeviceLostReason reason;
|
|
2404
|
+
@property
|
|
2405
|
+
def reason(self):
|
|
2406
|
+
"""The reason (enums.GPUDeviceLostReason) for the device getting lost. Can be None."""
|
|
2407
|
+
return self._reason
|
|
2408
|
+
|
|
2409
|
+
|
|
2410
|
+
class GPUError(Exception):
|
|
2411
|
+
"""A generic GPU error."""
|
|
2412
|
+
|
|
2413
|
+
def __init__(self, message):
|
|
2414
|
+
super().__init__(message)
|
|
2415
|
+
|
|
2416
|
+
# IDL: readonly attribute DOMString message;
|
|
2417
|
+
@property
|
|
2418
|
+
def message(self):
|
|
2419
|
+
"""The error message."""
|
|
2420
|
+
return self.args[0]
|
|
2421
|
+
|
|
2422
|
+
|
|
2423
|
+
class GPUOutOfMemoryError(GPUError, MemoryError):
|
|
2424
|
+
"""An error raised when the GPU is out of memory."""
|
|
2425
|
+
|
|
2426
|
+
# IDL: constructor(DOMString message);
|
|
2427
|
+
def __init__(self, message: str):
|
|
2428
|
+
super().__init__(message or "GPU is out of memory.")
|
|
2429
|
+
|
|
2430
|
+
|
|
2431
|
+
class GPUValidationError(GPUError):
|
|
2432
|
+
"""An error raised when the pipeline could not be validated."""
|
|
2433
|
+
|
|
2434
|
+
# IDL: constructor(DOMString message);
|
|
2435
|
+
def __init__(self, message: str):
|
|
2436
|
+
super().__init__(message)
|
|
2437
|
+
|
|
2438
|
+
|
|
2439
|
+
class GPUPipelineError(Exception):
|
|
2440
|
+
"""An error raised when a pipeline could not be created."""
|
|
2441
|
+
|
|
2442
|
+
# IDL: constructor(optional DOMString message = "", GPUPipelineErrorInit options);
|
|
2443
|
+
def __init__(self, message: str, options: structs.PipelineErrorInit):
|
|
2444
|
+
super().__init__(message or "")
|
|
2445
|
+
self._options = options
|
|
2446
|
+
|
|
2447
|
+
# IDL: readonly attribute GPUPipelineErrorReason reason;
|
|
2448
|
+
@property
|
|
2449
|
+
def reason(self):
|
|
2450
|
+
"""The reason for the failure."""
|
|
2451
|
+
return self.args[0]
|
|
2452
|
+
|
|
2453
|
+
|
|
2454
|
+
class GPUInternalError(GPUError):
|
|
2455
|
+
"""An error raised for implementation-specific reasons.
|
|
2456
|
+
|
|
2457
|
+
An operation failed for a system or implementation-specific
|
|
2458
|
+
reason even when all validation requirements have been satisfied.
|
|
2459
|
+
"""
|
|
2460
|
+
|
|
2461
|
+
# IDL: constructor(DOMString message);
|
|
2462
|
+
def __init__(self, message: str):
|
|
2463
|
+
super().__init__(message)
|
|
2464
|
+
|
|
2465
|
+
|
|
2466
|
+
# %% Not implemented
|
|
2467
|
+
|
|
2468
|
+
|
|
2469
|
+
class GPUCompilationMessage:
|
|
2470
|
+
"""An object that contains information about a problem with shader compilation."""
|
|
2471
|
+
|
|
2472
|
+
# IDL: readonly attribute DOMString message;
|
|
2473
|
+
@property
|
|
2474
|
+
def message(self):
|
|
2475
|
+
"""The warning/error message."""
|
|
2476
|
+
raise NotImplementedError()
|
|
2477
|
+
|
|
2478
|
+
# IDL: readonly attribute GPUCompilationMessageType type;
|
|
2479
|
+
@property
|
|
2480
|
+
def type(self):
|
|
2481
|
+
"""The type of warning/problem."""
|
|
2482
|
+
raise NotImplementedError()
|
|
2483
|
+
|
|
2484
|
+
# IDL: readonly attribute unsigned long long lineNum;
|
|
2485
|
+
@property
|
|
2486
|
+
def line_num(self):
|
|
2487
|
+
"""The corresponding line number in the shader source."""
|
|
2488
|
+
raise NotImplementedError()
|
|
2489
|
+
|
|
2490
|
+
# IDL: readonly attribute unsigned long long linePos;
|
|
2491
|
+
@property
|
|
2492
|
+
def line_pos(self):
|
|
2493
|
+
"""The position on the line in the shader source."""
|
|
2494
|
+
raise NotImplementedError()
|
|
2495
|
+
|
|
2496
|
+
# IDL: readonly attribute unsigned long long offset;
|
|
2497
|
+
@property
|
|
2498
|
+
def offset(self):
|
|
2499
|
+
"""Offset of ..."""
|
|
2500
|
+
raise NotImplementedError()
|
|
2501
|
+
|
|
2502
|
+
# IDL: readonly attribute unsigned long long length;
|
|
2503
|
+
@property
|
|
2504
|
+
def length(self):
|
|
2505
|
+
"""The length of the line?"""
|
|
2506
|
+
raise NotImplementedError()
|
|
2507
|
+
|
|
2508
|
+
|
|
2509
|
+
class GPUCompilationInfo:
|
|
2510
|
+
"""TODO"""
|
|
2511
|
+
|
|
2512
|
+
# IDL: readonly attribute FrozenArray<GPUCompilationMessage> messages;
|
|
2513
|
+
@property
|
|
2514
|
+
def messages(self):
|
|
2515
|
+
"""A list of `GPUCompilationMessage` objects."""
|
|
2516
|
+
raise NotImplementedError()
|
|
2517
|
+
|
|
2518
|
+
|
|
2519
|
+
class GPUQuerySet(GPUObjectBase):
|
|
2520
|
+
"""An object to store the results of queries on passes.
|
|
2521
|
+
|
|
2522
|
+
You can obtain a query set object via :attr:`GPUDevice.create_query_set`.
|
|
2523
|
+
"""
|
|
2524
|
+
|
|
2525
|
+
def __init__(self, label, internal, device, type, count):
|
|
2526
|
+
super().__init__(label, internal, device)
|
|
2527
|
+
self._type = type
|
|
2528
|
+
self._count = count
|
|
2529
|
+
|
|
2530
|
+
# IDL: readonly attribute GPUQueryType type;
|
|
2531
|
+
@property
|
|
2532
|
+
def type(self):
|
|
2533
|
+
"""The type of the queries managed by this queryset."""
|
|
2534
|
+
return self._type
|
|
2535
|
+
|
|
2536
|
+
# IDL: readonly attribute GPUSize32Out count;
|
|
2537
|
+
@property
|
|
2538
|
+
def count(self):
|
|
2539
|
+
"""The number of the queries managed by this queryset."""
|
|
2540
|
+
return self._count
|
|
2541
|
+
|
|
2542
|
+
# IDL: undefined destroy();
|
|
2543
|
+
def destroy(self):
|
|
2544
|
+
"""Destroy the QuerySet.
|
|
2545
|
+
|
|
2546
|
+
This cleans up all its resources and puts it in an unusable state.
|
|
2547
|
+
Note that all objects get cleaned up properly automatically; this
|
|
2548
|
+
is only intended to support explicit destroying.
|
|
2549
|
+
|
|
2550
|
+
NOTE: not yet implemented; for the moment this does nothing.
|
|
2551
|
+
"""
|
|
2552
|
+
raise NotImplementedError()
|
|
2553
|
+
|
|
2554
|
+
|
|
2555
|
+
# %%%%% Post processing
|
|
2556
|
+
|
|
2557
|
+
# Note that some toplevel classes are already filtered out by the codegen,
|
|
2558
|
+
# like GPUExternalTexture and GPUUncapturedErrorEvent, and more.
|
|
2559
|
+
|
|
2560
|
+
apidiff.remove_hidden_methods(globals())
|
|
2561
|
+
|
|
2562
|
+
|
|
2563
|
+
def _seed_object_counts():
|
|
2564
|
+
m = globals()
|
|
2565
|
+
for class_name in __all__:
|
|
2566
|
+
cls = m[class_name]
|
|
2567
|
+
if not class_name.endswith(("Base", "Mixin")):
|
|
2568
|
+
if hasattr(cls, "_ot"):
|
|
2569
|
+
object_tracker.counts[class_name] = 0
|
|
2570
|
+
|
|
2571
|
+
|
|
2572
|
+
def generic_repr(self):
|
|
2573
|
+
try:
|
|
2574
|
+
module_name = self.__module__
|
|
2575
|
+
if module_name.startswith("wgpu"):
|
|
2576
|
+
if module_name == "wgpu._classes":
|
|
2577
|
+
module_name = "wgpu"
|
|
2578
|
+
elif "backends." in module_name:
|
|
2579
|
+
backend_name = self.__module__.split("backends")[-1].split(".")[1]
|
|
2580
|
+
module_name = f"wgpu.backends.{backend_name}"
|
|
2581
|
+
object_str = "object"
|
|
2582
|
+
if isinstance(self, GPUObjectBase):
|
|
2583
|
+
object_str = f"object '{self.label}'"
|
|
2584
|
+
return (
|
|
2585
|
+
f"<{module_name}.{self.__class__.__name__} {object_str} at {hex(id(self))}>"
|
|
2586
|
+
)
|
|
2587
|
+
except Exception: # easy fallback
|
|
2588
|
+
return object.__repr__(self)
|
|
2589
|
+
|
|
2590
|
+
|
|
2591
|
+
def _set_repr_methods():
|
|
2592
|
+
m = globals()
|
|
2593
|
+
for class_name in __all__:
|
|
2594
|
+
cls = m[class_name]
|
|
2595
|
+
if len(cls.mro()) == 2: # class itself and object
|
|
2596
|
+
cls.__repr__ = generic_repr
|
|
2597
|
+
|
|
2598
|
+
|
|
2599
|
+
_async_warnings = {}
|
|
2600
|
+
|
|
2601
|
+
|
|
2602
|
+
def _set_compat_methods_for_async_methods():
|
|
2603
|
+
def create_new_method(name):
|
|
2604
|
+
def proxy_method(self, *args, **kwargs):
|
|
2605
|
+
warning = _async_warnings.pop(name, None)
|
|
2606
|
+
if warning:
|
|
2607
|
+
logger.warning(warning)
|
|
2608
|
+
return getattr(self, name)(*args, **kwargs)
|
|
2609
|
+
|
|
2610
|
+
proxy_method.__name__ = name + "_backwards_compat_proxy"
|
|
2611
|
+
proxy_method.__doc__ = f"Backwards compatible method for {name}()"
|
|
2612
|
+
return proxy_method
|
|
2613
|
+
|
|
2614
|
+
m = globals()
|
|
2615
|
+
for class_name in __all__:
|
|
2616
|
+
cls = m[class_name]
|
|
2617
|
+
for name, func in list(cls.__dict__.items()):
|
|
2618
|
+
if name.endswith("_sync") and callable(func):
|
|
2619
|
+
old_name = name[:-5]
|
|
2620
|
+
setattr(cls, old_name, create_new_method(name))
|
|
2621
|
+
_async_warnings[name] = (
|
|
2622
|
+
f"WGPU: {old_name}() is deprecated, use {name}() instead."
|
|
2623
|
+
)
|
|
2624
|
+
|
|
2625
|
+
|
|
2626
|
+
_seed_object_counts()
|
|
2627
|
+
_set_repr_methods()
|
|
2628
|
+
_set_compat_methods_for_async_methods()
|