diff --git a/tests/test_wgpu_native_texture.py b/tests/test_wgpu_native_texture.py index e36b0d85..5e4ff58a 100644 --- a/tests/test_wgpu_native_texture.py +++ b/tests/test_wgpu_native_texture.py @@ -324,5 +324,37 @@ def test_16bit_norm(): assert "r16unorm" in texture.format +@mark.skipif(not can_use_wgpu_lib, reason="Needs wgpu lib") +def test_view_formats(): + # A view may reinterpret a texture as any format declared in view_formats, + # and only those. The srgb/non-srgb pair is the useful case: it reads the + # bytes that were written, without the transfer function. + device = wgpu.utils.get_default_device() + + usage = wgpu.TextureUsage.RENDER_ATTACHMENT | wgpu.TextureUsage.TEXTURE_BINDING + tex = device.create_texture( + size=(64, 64, 1), + format=wgpu.TextureFormat.rgba8unorm_srgb, + usage=usage, + view_formats=[wgpu.TextureFormat.rgba8unorm], + ) + view = tex.create_view(format=wgpu.TextureFormat.rgba8unorm) + assert view is not None + + # The texture's own format is always viewable. + assert tex.create_view(format=wgpu.TextureFormat.rgba8unorm_srgb) is not None + + # A format that was not declared is still rejected. + with raises(wgpu.GPUValidationError): + tex.create_view(format=wgpu.TextureFormat.rgba8snorm) + + # And declaring none keeps the old behaviour. + plain = device.create_texture( + size=(64, 64, 1), format=wgpu.TextureFormat.rgba8unorm_srgb, usage=usage + ) + with raises(wgpu.GPUValidationError): + plain.create_view(format=wgpu.TextureFormat.rgba8unorm) + + if __name__ == "__main__": run_tests(globals()) diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index c59d8dd0..c29194c2 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -1498,10 +1498,11 @@ def create_texture( depthOrArrayLayers=size[2], ) - if view_formats: - raise NotImplementedError( - "create_texture(.. view_formats is not yet supported." - ) + # Formats that views of this texture may reinterpret it as. The main + # use is taking a non-srgb view of an srgb target (or the reverse) to + # read or write the raw bytes without the transfer function applied. + view_formats_list = [enummap["TextureFormat." + x] for x in view_formats] + c_view_formats = new_array("WGPUTextureFormat[]", view_formats_list) if not mip_level_count: mip_level_count = 1 # or lib.WGPU_MIP_LEVEL_COUNT_UNDEFINED ? @@ -1522,8 +1523,8 @@ def create_texture( dimension=dimension, format=format, usage=usage, - # not used: viewFormatCount - # not used: viewFormats + viewFormatCount=len(view_formats), + viewFormats=c_view_formats, ) # H: WGPUTexture f(WGPUDevice device, WGPUTextureDescriptor const * descriptor) id = libf.wgpuDeviceCreateTexture(self._internal, struct)