mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Make multi-planar textures renderable (#8307)
This commit is contained in:
parent
7a2afeb014
commit
e7fcb94888
@ -84,6 +84,7 @@ SamplerDescriptor {
|
|||||||
- Texture now has `from_custom`. By @R-Cramer4 in [#8315](https://github.com/gfx-rs/wgpu/pull/8315).
|
- Texture now has `from_custom`. By @R-Cramer4 in [#8315](https://github.com/gfx-rs/wgpu/pull/8315).
|
||||||
- Using both the wgpu command encoding APIs and `CommandEncoder::as_hal_mut` on the same encoder will now result in a panic.
|
- Using both the wgpu command encoding APIs and `CommandEncoder::as_hal_mut` on the same encoder will now result in a panic.
|
||||||
- Allow `include_spirv!` and `include_spirv_raw!` macros to be used in constants and statics. By @clarfonthey in [#8250](https://github.com/gfx-rs/wgpu/pull/8250).
|
- Allow `include_spirv!` and `include_spirv_raw!` macros to be used in constants and statics. By @clarfonthey in [#8250](https://github.com/gfx-rs/wgpu/pull/8250).
|
||||||
|
- Added support for rendering onto multi-planar textures. By @noituri in [#8307](https://github.com/gfx-rs/wgpu/pull/8307).
|
||||||
|
|
||||||
### Added/New Features
|
### Added/New Features
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ pub fn all_tests(tests: &mut Vec<GpuTestInitializer>) {
|
|||||||
tests.extend([
|
tests.extend([
|
||||||
NV12_TEXTURE_CREATION_SAMPLING,
|
NV12_TEXTURE_CREATION_SAMPLING,
|
||||||
P010_TEXTURE_CREATION_SAMPLING,
|
P010_TEXTURE_CREATION_SAMPLING,
|
||||||
|
NV12_TEXTURE_RENDERING,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ fn test_planar_texture_creation_sampling(
|
|||||||
|
|
||||||
let shader = ctx
|
let shader = ctx
|
||||||
.device
|
.device
|
||||||
.create_shader_module(wgpu::include_wgsl!("planar_texture.wgsl"));
|
.create_shader_module(wgpu::include_wgsl!("planar_texture_sampling.wgsl"));
|
||||||
let pipeline = ctx
|
let pipeline = ctx
|
||||||
.device
|
.device
|
||||||
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
@ -105,7 +106,112 @@ fn test_planar_texture_creation_sampling(
|
|||||||
rpass.set_bind_group(0, &bind_group, &[]);
|
rpass.set_bind_group(0, &bind_group, &[]);
|
||||||
rpass.draw(0..4, 0..1);
|
rpass.draw(0..4, 0..1);
|
||||||
drop(rpass);
|
drop(rpass);
|
||||||
ctx.queue.submit(Some(encoder.finish()));
|
ctx.queue.submit([encoder.finish()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to test rendering onto planar texture.
|
||||||
|
fn test_planar_texture_rendering(
|
||||||
|
ctx: &TestingContext,
|
||||||
|
(y_view, y_format): (&wgpu::TextureView, wgpu::TextureFormat),
|
||||||
|
(uv_view, uv_format): (&wgpu::TextureView, wgpu::TextureFormat),
|
||||||
|
) {
|
||||||
|
let shader = ctx
|
||||||
|
.device
|
||||||
|
.create_shader_module(wgpu::include_wgsl!("planar_texture_rendering.wgsl"));
|
||||||
|
let y_pipeline = ctx
|
||||||
|
.device
|
||||||
|
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("y plane pipeline"),
|
||||||
|
layout: None,
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("vs_main"),
|
||||||
|
compilation_options: Default::default(),
|
||||||
|
buffers: &[],
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("fs_y_main"),
|
||||||
|
compilation_options: Default::default(),
|
||||||
|
targets: &[Some(y_format.into())],
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
||||||
|
strip_index_format: Some(wgpu::IndexFormat::Uint32),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let uv_pipeline = ctx
|
||||||
|
.device
|
||||||
|
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("uv plane pipeline"),
|
||||||
|
layout: None,
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("vs_main"),
|
||||||
|
compilation_options: Default::default(),
|
||||||
|
buffers: &[],
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("fs_uv_main"),
|
||||||
|
compilation_options: Default::default(),
|
||||||
|
targets: &[Some(uv_format.into())],
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
||||||
|
strip_index_format: Some(wgpu::IndexFormat::Uint32),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut encoder = ctx
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
ops: wgpu::Operations::default(),
|
||||||
|
resolve_target: None,
|
||||||
|
view: y_view,
|
||||||
|
depth_slice: None,
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
rpass.set_pipeline(&y_pipeline);
|
||||||
|
rpass.draw(0..3, 0..1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
ops: wgpu::Operations::default(),
|
||||||
|
resolve_target: None,
|
||||||
|
view: uv_view,
|
||||||
|
depth_slice: None,
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
rpass.set_pipeline(&uv_pipeline);
|
||||||
|
rpass.draw(0..3, 0..1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.queue.submit([encoder.finish()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures that creation and sampling of an NV12 format texture works as
|
/// Ensures that creation and sampling of an NV12 format texture works as
|
||||||
@ -187,3 +293,45 @@ static P010_TEXTURE_CREATION_SAMPLING: GpuTestConfiguration = GpuTestConfigurati
|
|||||||
|
|
||||||
test_planar_texture_creation_sampling(&ctx, &y_view, &uv_view);
|
test_planar_texture_creation_sampling(&ctx, &y_view, &uv_view);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Ensures that rendering on to NV12 format texture works as expected.
|
||||||
|
#[gpu_test]
|
||||||
|
static NV12_TEXTURE_RENDERING: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
|
.parameters(
|
||||||
|
TestParameters::default()
|
||||||
|
.features(wgpu::Features::TEXTURE_FORMAT_NV12)
|
||||||
|
.enable_noop(),
|
||||||
|
)
|
||||||
|
.run_sync(|ctx| {
|
||||||
|
let size = wgpu::Extent3d {
|
||||||
|
width: 256,
|
||||||
|
height: 256,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
};
|
||||||
|
let tex = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
size,
|
||||||
|
format: wgpu::TextureFormat::NV12,
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
let y_view = tex.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
format: Some(wgpu::TextureFormat::R8Unorm),
|
||||||
|
aspect: wgpu::TextureAspect::Plane0,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let uv_view = tex.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
format: Some(wgpu::TextureFormat::Rg8Unorm),
|
||||||
|
aspect: wgpu::TextureAspect::Plane1,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
test_planar_texture_rendering(
|
||||||
|
&ctx,
|
||||||
|
(&y_view, wgpu::TextureFormat::R8Unorm),
|
||||||
|
(&uv_view, wgpu::TextureFormat::Rg8Unorm),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) position: vec4<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const VERTICES: array<vec3<f32>, 3> = array<vec3<f32>, 3>(
|
||||||
|
vec3<f32>(-0.5, 0.0, 0.0),
|
||||||
|
vec3<f32>(0.5, 0.0, 0.0),
|
||||||
|
vec3<f32>(0.0, 1.0, 0.0),
|
||||||
|
);
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main(@builtin(vertex_index) idx: u32) -> VertexOutput {
|
||||||
|
var output: VertexOutput;
|
||||||
|
output.position = vec4(VERTICES[idx], 1.0);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_y_main(input: VertexOutput) -> @location(0) f32 {
|
||||||
|
let color = vec3<f32>(1.0);
|
||||||
|
let conversion_weights = vec3<f32>(0.2126, 0.7152, 0.0722);
|
||||||
|
return clamp(dot(color, conversion_weights), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_uv_main(input: VertexOutput) -> @location(0) vec2<f32> {
|
||||||
|
let color = vec3<f32>(1.0);
|
||||||
|
let conversion_weights = mat3x2<f32>(
|
||||||
|
-0.1146, 0.5,
|
||||||
|
-0.3854, -0.4542,
|
||||||
|
0.5, -0.0458,
|
||||||
|
);
|
||||||
|
let conversion_bias = vec2<f32>(0.5, 0.5);
|
||||||
|
return clamp(conversion_weights * color + conversion_bias, vec2(0.0, 0.0), vec2(1.0, 1.0));
|
||||||
|
}
|
||||||
@ -287,6 +287,90 @@ fn planar_texture_bad_size() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensures that creating a planar textures that support `RENDER_ATTACHMENT` usage
|
||||||
|
/// is possible.
|
||||||
|
#[test]
|
||||||
|
fn planar_texture_render_attachment() {
|
||||||
|
let required_features = wgpu::Features::TEXTURE_FORMAT_NV12;
|
||||||
|
let device_desc = wgpu::DeviceDescriptor {
|
||||||
|
required_features,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let (device, _queue) = wgpu::Device::noop(&device_desc);
|
||||||
|
let size = wgpu::Extent3d {
|
||||||
|
width: 256,
|
||||||
|
height: 256,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (tex_format, view_format, view_aspect) in [
|
||||||
|
(
|
||||||
|
wgpu::TextureFormat::NV12,
|
||||||
|
wgpu::TextureFormat::R8Unorm,
|
||||||
|
wgpu::TextureAspect::Plane0,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
wgpu::TextureFormat::NV12,
|
||||||
|
wgpu::TextureFormat::Rg8Unorm,
|
||||||
|
wgpu::TextureAspect::Plane1,
|
||||||
|
),
|
||||||
|
] {
|
||||||
|
valid(&device, || {
|
||||||
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
size,
|
||||||
|
format: tex_format,
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = texture.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
format: Some(view_format),
|
||||||
|
aspect: view_aspect,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensures that creating a planar textures with `RENDER_ATTACHMENT`
|
||||||
|
/// for non renderable planar formats fails validation.
|
||||||
|
#[test]
|
||||||
|
fn planar_texture_render_attachment_unsupported() {
|
||||||
|
let required_features =
|
||||||
|
wgpu::Features::TEXTURE_FORMAT_P010 | wgpu::Features::TEXTURE_FORMAT_16BIT_NORM;
|
||||||
|
let device_desc = wgpu::DeviceDescriptor {
|
||||||
|
required_features,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let (device, _queue) = wgpu::Device::noop(&device_desc);
|
||||||
|
let size = wgpu::Extent3d {
|
||||||
|
width: 256,
|
||||||
|
height: 256,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
fail(
|
||||||
|
&device,
|
||||||
|
|| {
|
||||||
|
let _ = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
size,
|
||||||
|
format: wgpu::TextureFormat::P010,
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Some("Texture usages TextureUsages(RENDER_ATTACHMENT) are not allowed on a texture of type P010"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a texture and a buffer, and encodes a copy from the texture to the
|
/// Creates a texture and a buffer, and encodes a copy from the texture to the
|
||||||
/// buffer.
|
/// buffer.
|
||||||
fn encode_copy_texture_to_buffer(
|
fn encode_copy_texture_to_buffer(
|
||||||
|
|||||||
@ -1207,11 +1207,12 @@ impl RenderPassInfo {
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if !color_view
|
if !color_view.desc.aspects().intersects(
|
||||||
.desc
|
hal::FormatAspects::COLOR
|
||||||
.aspects()
|
| hal::FormatAspects::PLANE_0
|
||||||
.contains(hal::FormatAspects::COLOR)
|
| hal::FormatAspects::PLANE_1
|
||||||
{
|
| hal::FormatAspects::PLANE_2,
|
||||||
|
) {
|
||||||
return Err(RenderPassErrorInner::ColorAttachment(
|
return Err(RenderPassErrorInner::ColorAttachment(
|
||||||
ColorAttachmentError::InvalidFormat(color_view.desc.format),
|
ColorAttachmentError::InvalidFormat(color_view.desc.format),
|
||||||
));
|
));
|
||||||
|
|||||||
@ -111,7 +111,12 @@ pub fn map_texture_usage(
|
|||||||
flags.contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE),
|
flags.contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let is_color = aspect.contains(hal::FormatAspects::COLOR);
|
let is_color = aspect.intersects(
|
||||||
|
hal::FormatAspects::COLOR
|
||||||
|
| hal::FormatAspects::PLANE_0
|
||||||
|
| hal::FormatAspects::PLANE_1
|
||||||
|
| hal::FormatAspects::PLANE_2,
|
||||||
|
);
|
||||||
u.set(
|
u.set(
|
||||||
wgt::TextureUses::COLOR_TARGET,
|
wgt::TextureUses::COLOR_TARGET,
|
||||||
usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) && is_color,
|
usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) && is_color,
|
||||||
|
|||||||
@ -1355,7 +1355,24 @@ impl Device {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let missing_allowed_usages = desc.usage - format_features.allowed_usages;
|
let missing_allowed_usages = match desc.format.planes() {
|
||||||
|
Some(planes) => {
|
||||||
|
let mut planes_usages = wgt::TextureUsages::all();
|
||||||
|
for plane in 0..planes {
|
||||||
|
let aspect = wgt::TextureAspect::from_plane(plane).unwrap();
|
||||||
|
let format = desc.format.aspect_specific_format(aspect).unwrap();
|
||||||
|
let format_features = self
|
||||||
|
.describe_format_features(format)
|
||||||
|
.map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?;
|
||||||
|
|
||||||
|
planes_usages &= format_features.allowed_usages;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.usage - planes_usages
|
||||||
|
}
|
||||||
|
None => desc.usage - format_features.allowed_usages,
|
||||||
|
};
|
||||||
|
|
||||||
if !missing_allowed_usages.is_empty() {
|
if !missing_allowed_usages.is_empty() {
|
||||||
// detect downlevel incompatibilities
|
// detect downlevel incompatibilities
|
||||||
let wgpu_allowed_usages = desc
|
let wgpu_allowed_usages = desc
|
||||||
@ -1722,13 +1739,15 @@ impl Device {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if aspects != hal::FormatAspects::from(texture.desc.format) {
|
if !texture.desc.format.is_multi_planar_format()
|
||||||
|
&& aspects != hal::FormatAspects::from(texture.desc.format)
|
||||||
|
{
|
||||||
break 'error Err(TextureViewNotRenderableReason::Aspects(aspects));
|
break 'error Err(TextureViewNotRenderableReason::Aspects(aspects));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(texture
|
Ok(texture
|
||||||
.desc
|
.desc
|
||||||
.compute_render_extent(desc.range.base_mip_level))
|
.compute_render_extent(desc.range.base_mip_level, desc.range.aspect.to_plane()))
|
||||||
};
|
};
|
||||||
|
|
||||||
// filter the usages based on the other criteria
|
// filter the usages based on the other criteria
|
||||||
|
|||||||
@ -590,7 +590,8 @@ impl super::Device {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if desc.format.is_multi_planar_format() {
|
if desc.format.is_multi_planar_format() {
|
||||||
raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
|
raw_flags |=
|
||||||
|
vk::ImageCreateFlags::MUTABLE_FORMAT | vk::ImageCreateFlags::EXTENDED_USAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vk_info = vk::ImageCreateInfo::default()
|
let mut vk_info = vk::ImageCreateInfo::default()
|
||||||
|
|||||||
@ -134,6 +134,32 @@ fn test_uniqueness_in_texture_format_list() {
|
|||||||
assert_eq!(duplicated, vec![]);
|
assert_eq!(duplicated, vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_compute_render_extent() {
|
||||||
|
for format in TEXTURE_FORMAT_LIST {
|
||||||
|
let desc = wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: 1280,
|
||||||
|
height: 720,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format,
|
||||||
|
usage: wgpu::TextureUsages::empty(),
|
||||||
|
view_formats: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
if format.is_multi_planar_format() {
|
||||||
|
let _ = desc.compute_render_extent(0, Some(0));
|
||||||
|
} else {
|
||||||
|
let _ = desc.compute_render_extent(0, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn max_texture_format_string_size() -> usize {
|
pub fn max_texture_format_string_size() -> usize {
|
||||||
TEXTURE_FORMAT_LIST
|
TEXTURE_FORMAT_LIST
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@ -2772,6 +2772,17 @@ impl TextureAspect {
|
|||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the plane for a given texture aspect.
|
||||||
|
#[must_use]
|
||||||
|
pub fn to_plane(&self) -> Option<u32> {
|
||||||
|
match self {
|
||||||
|
TextureAspect::Plane0 => Some(0),
|
||||||
|
TextureAspect::Plane1 => Some(1),
|
||||||
|
TextureAspect::Plane2 => Some(2),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are some additional texture format helpers in `wgpu-core/src/conv.rs`,
|
// There are some additional texture format helpers in `wgpu-core/src/conv.rs`,
|
||||||
@ -6416,10 +6427,22 @@ impl<L, V> TextureDescriptor<L, V> {
|
|||||||
///
|
///
|
||||||
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-compute-render-extent>
|
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-compute-render-extent>
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn compute_render_extent(&self, mip_level: u32) -> Extent3d {
|
pub fn compute_render_extent(&self, mip_level: u32, plane: Option<u32>) -> Extent3d {
|
||||||
|
let width = self.size.width >> mip_level;
|
||||||
|
let height = self.size.height >> mip_level;
|
||||||
|
|
||||||
|
let (width, height) = match (self.format, plane) {
|
||||||
|
(TextureFormat::NV12 | TextureFormat::P010, Some(0)) => (width, height),
|
||||||
|
(TextureFormat::NV12 | TextureFormat::P010, Some(1)) => (width / 2, height / 2),
|
||||||
|
_ => {
|
||||||
|
debug_assert!(!self.format.is_multi_planar_format());
|
||||||
|
(width, height)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Extent3d {
|
Extent3d {
|
||||||
width: u32::max(1, self.size.width >> mip_level),
|
width,
|
||||||
height: u32::max(1, self.size.height >> mip_level),
|
height,
|
||||||
depth_or_array_layers: 1,
|
depth_or_array_layers: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user