Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combining more code #640

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion tests/test_wgpu_native_basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ def test_wgpu_native_tracer():
@mark.skipif(not can_use_wgpu_lib, reason="Needs wgpu lib")
def test_enumerate_adapters():
# Get all available adapters
adapters = wgpu.gpu.enumerate_adapters_sync()
adapters = list(wgpu.gpu.enumerate_adapters_sync())
assert len(adapters) > 0

# Check adapter summaries
Expand All @@ -357,6 +357,25 @@ def test_enumerate_adapters():
assert isinstance(d, wgpu.backends.wgpu_native.GPUDevice)


@mark.skipif(not can_use_wgpu_lib, reason="Needs wgpu lib")
@mark.asyncio
async def test_enumerate_adapters_async():
# Get all available adapters
adapters = []
async for adapter in wgpu.gpu.enumerate_adapters_async():
assert isinstance(adapter.summary, str)
assert "\n" not in adapter.summary
assert len(adapter.summary.strip()) > 10
adapters.append(adapter)

assert len(adapters) > 0

# Check that we can get a device from each adapter
for adapter in adapters:
d = adapter.request_device_sync()
assert isinstance(d, wgpu.backends.wgpu_native.GPUDevice)


@mark.skipif(not can_use_wgpu_lib, reason="Needs wgpu lib")
def test_adapter_destroy():
adapter = wgpu.gpu.request_adapter_sync(power_preference="high-performance")
Expand Down
162 changes: 91 additions & 71 deletions wgpu/backends/wgpu_native/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,25 @@
# Allow using class names in type annotations, before the class is defined. Py3.7+
from __future__ import annotations

import os
import logging
import os
from typing import Dict, List, Optional, Union
from weakref import WeakKeyDictionary
from typing import List, Dict, Union, Optional

from ... import classes, flags, enums, structs
from ..._coreutils import str_flag_to_int

from ._ffi import ffi, lib
from ._mappings import cstructfield2enum, enummap, enum_str2int, enum_int2str
from ._helpers import (
get_wgpu_instance,
get_surface_id_from_info,
get_memoryview_from_address,
get_memoryview_and_address,
to_snake_case,
ErrorHandler,
WgpuAwaitable,
SafeLibCalls,
WgpuAwaitable,
get_memoryview_and_address,
get_memoryview_from_address,
get_surface_id_from_info,
get_wgpu_instance,
to_snake_case,
)
from ._mappings import cstructfield2enum, enum_int2str, enum_str2int, enummap
from ... import classes, enums, flags, structs
from ..._coreutils import str_flag_to_int

logger = logging.getLogger("wgpu")

Expand Down Expand Up @@ -429,25 +428,29 @@ def enumerate_adapters_sync(self):
This is the implementation based on wgpu-native.
"""
check_can_use_sync_variants()
return self._enumerate_adapters()
adapter_ids = self._enumerate_adapter_ids()
for adapter_id in adapter_ids:
yield self._create_adapter(adapter_id)

async def enumerate_adapters_async(self):
"""Get a list of adapter objects available on the current system.
This is the implementation based on wgpu-native.
"""
return self._enumerate_adapters()
adapter_ids = self._enumerate_adapter_ids()
for adapter_id in adapter_ids:
yield self._create_adapter(adapter_id)

def _enumerate_adapters(self):
def _enumerate_adapter_ids(self):
# The first call is to get the number of adapters, and the second call
# is to get the actual adapters. Note that the second arg (now NULL) can
# be a `WGPUInstanceEnumerateAdapterOptions` to filter by backend.
instance = get_wgpu_instance()
# H: size_t f(WGPUInstance instance, WGPUInstanceEnumerateAdapterOptions const * options, WGPUAdapter * adapters)
count = libf.wgpuInstanceEnumerateAdapters(instance, ffi.NULL, ffi.NULL)
adapters = ffi.new("WGPUAdapter[]", count)
adapter_ids = ffi.new("WGPUAdapter[]", count)
# H: size_t f(WGPUInstance instance, WGPUInstanceEnumerateAdapterOptions const * options, WGPUAdapter * adapters)
libf.wgpuInstanceEnumerateAdapters(instance, ffi.NULL, adapters)
return [self._create_adapter(adapter) for adapter in adapters]
libf.wgpuInstanceEnumerateAdapters(instance, ffi.NULL, adapter_ids)
return adapter_ids

def _create_adapter(self, adapter_id):
# ----- Get adapter info
Expand Down Expand Up @@ -2465,6 +2468,62 @@ def set_bind_group(
function = type(self)._set_bind_group_function
function(self._internal, index, bind_group._internal, len(offsets), c_offsets)

##
# It is unfortunate that there is no common Mixin that includes just
# GPUComputePassEncoder and GPURenderPassEncodeer, but not GPURenderBundleEncoder.
# We put set_push_constants, and XX_pipeline_statistics_query here because they
# don't really fit anywhere else.
#

def _set_push_constants(self, visibility, offset, size_in_bytes, data, data_offset):
# Implementation of set_push_constant. The public API is in extras.py since
# this is a wgpu extension.

# We support anything that memoryview supports, i.e. anything
# that implements the buffer protocol, including, bytes,
# bytearray, ctypes arrays, numpy arrays, etc.
m, address = get_memoryview_and_address(data)

# Deal with offset and size
offset = int(offset)
data_offset = int(data_offset)
size = int(size_in_bytes)
if isinstance(visibility, str):
visibility = str_flag_to_int(flags.ShaderStage, visibility)

if not (0 <= size_in_bytes <= m.nbytes):
raise ValueError("Invalid size_in_bytes")
if not (0 <= size_in_bytes <= m.nbytes):
raise ValueError("Invalid data_offset")
if size_in_bytes + data_offset > m.nbytes:
raise ValueError("size_in_bytes + data_offset is too large")

c_data = ffi.cast("void *", address) # do we want to add data_offset?
# H: void wgpuRenderPassEncoderSetPushConstants(WGPURenderPassEncoder encoder, WGPUShaderStageFlags stages, uint32_t offset, uint32_t sizeBytes, void const * data)
function = type(self)._set_push_constants_function
if function is None:
self._not_implemented("set_push_constants")
function(self._internal, int(visibility), offset, size, c_data + data_offset)

def _begin_pipeline_statistics_query(self, query_set, query_index):
# H: void wgpuComputePassEncoderBeginPipelineStatisticsQuery(WGPUComputePassEncoder computePassEncoder, WGPUQuerySet querySet, uint32_t queryIndex)
# H: void wgpuRenderPassEncoderBeginPipelineStatisticsQuery(WGPURenderPassEncoder renderPassEncoder, WGPUQuerySet querySet, uint32_t queryIndex)
function = type(self)._begin_pipeline_statistics_query_function
if function is None:
self._not_implemented("begin_pipeline_statistics")
function(self._internal, query_set._internal, int(query_index))

def _end_pipeline_statistics_query(self):
# H: void wgpuComputePassEncoderEndPipelineStatisticsQuery(WGPUComputePassEncoder computePassEncoder)
# H: void wgpuRenderPassEncoderEndPipelineStatisticsQuery(WGPURenderPassEncoder renderPassEncoder)
function = type(self)._end_pipeline_statistics_query_function
if function is None:
self._not_implemented("end_pipeline_statistics")
function(self._internal)

def _not_implemented(self, name):
raise RuntimeError(f"{name} not implemented for {type(self).__name__}")


class GPUDebugCommandsMixin(classes.GPUDebugCommandsMixin):
# whole class is likely going to be solved better: https://github.com/pygfx/wgpu-py/pull/546
Expand Down Expand Up @@ -3083,6 +3142,9 @@ class GPUComputePassEncoder(

# GPUBindingCommandsMixin
_set_bind_group_function = libf.wgpuComputePassEncoderSetBindGroup
_begin_pipeline_statistics_query_function = libf.wgpuComputePassEncoderBeginPipelineStatisticsQuery # fmt: skip
_end_pipeline_statistics_query_function = libf.wgpuComputePassEncoderEndPipelineStatisticsQuery # fmt: skip
_set_push_constants_function = None # coming soon

# GPUObjectBaseMixin
_release_function = libf.wgpuComputePassEncoderRelease
Expand Down Expand Up @@ -3112,16 +3174,6 @@ def dispatch_workgroups_indirect(
self._internal, buffer_id, int(indirect_offset)
)

def _begin_pipeline_statistics_query(self, query_set, query_index):
# H: void f(WGPUComputePassEncoder computePassEncoder, WGPUQuerySet querySet, uint32_t queryIndex)
libf.wgpuComputePassEncoderBeginPipelineStatisticsQuery(
self._internal, query_set._internal, int(query_index)
)

def _end_pipeline_statistics_query(self):
# H: void f(WGPUComputePassEncoder computePassEncoder)
libf.wgpuComputePassEncoderEndPipelineStatisticsQuery(self._internal)

def end(self):
# H: void f(WGPUComputePassEncoder computePassEncoder)
libf.wgpuComputePassEncoderEnd(self._internal)
Expand All @@ -3148,6 +3200,9 @@ class GPURenderPassEncoder(

# GPUBindingCommandsMixin
_set_bind_group_function = libf.wgpuRenderPassEncoderSetBindGroup
_set_push_constants_function = libf.wgpuRenderPassEncoderSetPushConstants
_begin_pipeline_statistics_query_function = libf.wgpuRenderPassEncoderBeginPipelineStatisticsQuery # fmt: skip
_end_pipeline_statistics_query_function = libf.wgpuRenderPassEncoderEndPipelineStatisticsQuery # fmt: skip

# GPURenderCommandsMixin
_set_pipeline_function = libf.wgpuRenderPassEncoderSetPipeline
Expand Down Expand Up @@ -3191,13 +3246,14 @@ def set_blend_constant(self, color: Union[List[float], structs.Color]):
if isinstance(color, dict):
check_struct("Color", color)
color = _tuple_from_color(color)
red, green, blue, alpha = color
# H: r: float, g: float, b: float, a: float
c_color = new_struct_p(
"WGPUColor *",
r=color[0],
g=color[1],
b=color[2],
a=color[3],
r=red,
g=green,
b=blue,
a=alpha,
)
# H: void f(WGPURenderPassEncoder renderPassEncoder, WGPUColor const * color)
libf.wgpuRenderPassEncoderSetBlendConstant(self._internal, c_color)
Expand Down Expand Up @@ -3229,35 +3285,6 @@ def end_occlusion_query(self):
# H: void f(WGPURenderPassEncoder renderPassEncoder)
libf.wgpuRenderPassEncoderEndOcclusionQuery(self._internal)

def _set_push_constants(self, visibility, offset, size_in_bytes, data, data_offset):
# Implementation of set_push_constant. The public API is in extras.py since
# this is a wgpu extension.

# We support anything that memoryview supports, i.e. anything
# that implements the buffer protocol, including, bytes,
# bytearray, ctypes arrays, numpy arrays, etc.
m, address = get_memoryview_and_address(data)

# Deal with offset and size
offset = int(offset)
data_offset = int(data_offset)
size = int(size_in_bytes)
if isinstance(visibility, str):
visibility = str_flag_to_int(flags.ShaderStage, visibility)

if not (0 <= size_in_bytes <= m.nbytes):
raise ValueError("Invalid size_in_bytes")
if not (0 <= size_in_bytes <= m.nbytes):
raise ValueError("Invalid data_offset")
if size_in_bytes + data_offset > m.nbytes:
raise ValueError("size_in_bytes + data_offset is too large")

c_data = ffi.cast("void *", address) # do we want to add data_offset?
# H: void f(WGPURenderPassEncoder encoder, WGPUShaderStageFlags stages, uint32_t offset, uint32_t sizeBytes, void const * data)
libf.wgpuRenderPassEncoderSetPushConstants(
self._internal, int(visibility), offset, size, c_data + data_offset
)

def _multi_draw_indirect(self, buffer, offset, count):
# H: void f(WGPURenderPassEncoder encoder, WGPUBuffer buffer, uint64_t offset, uint32_t count)
libf.wgpuRenderPassEncoderMultiDrawIndirect(
Expand All @@ -3270,16 +3297,6 @@ def _multi_draw_indexed_indirect(self, buffer, offset, count):
self._internal, buffer._internal, int(offset), int(count)
)

def _begin_pipeline_statistics_query(self, query_set, query_index):
# H: void f(WGPURenderPassEncoder renderPassEncoder, WGPUQuerySet querySet, uint32_t queryIndex)
libf.wgpuRenderPassEncoderBeginPipelineStatisticsQuery(
self._internal, query_set._internal, int(query_index)
)

def _end_pipeline_statistics_query(self):
# H: void f(WGPURenderPassEncoder renderPassEncoder)
libf.wgpuRenderPassEncoderEndPipelineStatisticsQuery(self._internal)

def _maybe_keep_alive(self, object):
pass

Expand All @@ -3299,6 +3316,9 @@ class GPURenderBundleEncoder(

# GPUBindingCommandsMixin
_set_bind_group_function = libf.wgpuRenderBundleEncoderSetBindGroup
_set_push_constants_function = None
_begin_pipeline_statistics_query_function = None
_end_pipeline_statistics_query_function = None

# GPURenderCommandsMixin
_set_pipeline_function = libf.wgpuRenderBundleEncoderSetPipeline
Expand Down
2 changes: 1 addition & 1 deletion wgpu/resources/codegen_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* Diffs for GPUQueue: add read_buffer, add read_texture, hide copy_external_image_to_texture
* Validated 37 classes, 121 methods, 46 properties
### Patching API for backends/wgpu_native/_api.py
* Validated 37 classes, 120 methods, 0 properties
* Validated 37 classes, 119 methods, 0 properties
## Validating backends/wgpu_native/_api.py
* Enum field FeatureName.texture-compression-bc-sliced-3d missing in wgpu.h
* Enum field FeatureName.clip-distances missing in wgpu.h
Expand Down