diff --git a/tests/test_wgpu_native_basics.py b/tests/test_wgpu_native_basics.py index fa662d31..61a65625 100644 --- a/tests/test_wgpu_native_basics.py +++ b/tests/test_wgpu_native_basics.py @@ -481,5 +481,82 @@ def test_limits_are_not_legal(): assert not are_limits_wgpu_legal({"max-bind-group": 8}) +def test_bind_group_resources(): + # make sure every resource type can be created in a bind group. + device = wgpu.utils.get_default_device() + + sampler = device.create_sampler() + texture1 = device.create_texture( + label="texture1", + size=(8, 8, 1), + format=wgpu.TextureFormat.rgba8unorm, + usage=wgpu.TextureUsage.TEXTURE_BINDING | wgpu.TextureUsage.COPY_DST, + ) + texture2 = device.create_texture( + label="texture2", + size=(8, 8, 1), + format=wgpu.TextureFormat.rgba8unorm, + usage=wgpu.TextureUsage.TEXTURE_BINDING | wgpu.TextureUsage.COPY_DST, + ) + texture_view = texture2.create_view() + + buffer = device.create_buffer( + size=256, + usage=wgpu.BufferUsage.UNIFORM, + ) + + entires = [ + wgpu.structs.BindGroupEntry(binding=0, resource=sampler), + wgpu.structs.BindGroupEntry(binding=1, resource=texture1), + wgpu.structs.BindGroupEntry(binding=2, resource=texture_view), + wgpu.structs.BindGroupEntry( + binding=3, + resource=buffer, + ), + wgpu.structs.BindGroupEntry( + binding=4, + resource=wgpu.structs.BufferBinding( + buffer=buffer, + ), + ), + # maybe external texture one day + ] + + # maybe we should write a bit of compute shader so we can use auto layout mode instead. + layout_entries = [ + wgpu.BindGroupLayoutEntry( + binding=0, + visibility=wgpu.ShaderStage.COMPUTE, + sampler=wgpu.structs.SamplerBindingLayout(), + ), + wgpu.BindGroupLayoutEntry( + binding=1, + visibility=wgpu.ShaderStage.COMPUTE, + texture=wgpu.structs.TextureBindingLayout(), + ), + wgpu.BindGroupLayoutEntry( + binding=2, + visibility=wgpu.ShaderStage.COMPUTE, + texture=wgpu.structs.TextureBindingLayout(), + ), + wgpu.BindGroupLayoutEntry( + binding=3, + visibility=wgpu.ShaderStage.COMPUTE, + buffer=wgpu.structs.BufferBindingLayout(), + ), + wgpu.BindGroupLayoutEntry( + binding=4, + visibility=wgpu.ShaderStage.COMPUTE, + buffer=wgpu.structs.BufferBindingLayout(), + ), + ] + + layout = device.create_bind_group_layout(entries=layout_entries) + + bind_group = device.create_bind_group(layout=layout, entries=entires) + + assert bind_group + + if __name__ == "__main__": run_tests(globals()) diff --git a/wgpu/_classes.py b/wgpu/_classes.py index adb19a5c..09ed8b12 100644 --- a/wgpu/_classes.py +++ b/wgpu/_classes.py @@ -965,7 +965,7 @@ def create_bind_group( layout (GPUBindGroupLayout): The layout (abstract representation) for this bind group. entries (list): A list of `structs.BindGroupEntry`s. The ``resource`` field - is either `GPUSampler`, `GPUTextureView` or `structs.BufferBinding`. + is either `GPUBuffer`, `GPUSampler`, `GPUTexture`, `GPUTextureView` or `structs.BufferBinding`. Example entry dicts: diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index c59d8dd0..a4398585 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -1699,9 +1699,10 @@ def create_bind_group( entries: Sequence[structs.BindGroupEntryStruct], ) -> GPUBindGroup: c_entries_list = [] + _keep_alive = [] for entry in entries: check_struct("BindGroupEntry", entry) - # The resource can be a buffer, sampler, texture view, or buffer descriptor + # The resource can be a buffer, sampler, texture, texture view, or buffer descriptor resource = entry["resource"] if isinstance(resource, GPUBuffer): # H: nextInChain: WGPUChainedStruct *, binding: int, buffer: WGPUBuffer, offset: int, size: int, sampler: WGPUSampler, textureView: WGPUTextureView @@ -1727,7 +1728,11 @@ def create_bind_group( sampler=resource._internal, textureView=ffi.NULL, ) - elif isinstance(resource, GPUTextureView): + elif isinstance(resource, (GPUTextureView, GPUTexture)): + if type(resource) is GPUTexture: + # also see https://github.com/pygfx/wgpu-py/issues/825 + resource = resource.create_view() + _keep_alive.append(resource) # H: nextInChain: WGPUChainedStruct *, binding: int, buffer: WGPUBuffer, offset: int, size: int, sampler: WGPUSampler, textureView: WGPUTextureView c_entry = new_struct( "WGPUBindGroupEntry", @@ -1767,6 +1772,7 @@ def create_bind_group( # H: WGPUBindGroup f(WGPUDevice device, WGPUBindGroupDescriptor const * descriptor) id = libf.wgpuDeviceCreateBindGroup(self._internal, struct) + del _keep_alive return GPUBindGroup(label, id, self) def create_pipeline_layout(