Skip to content

Resizing camera target image causes Validation Error #5595

@zaycev

Description

@zaycev

Bevy version

0.8

[Optional] Relevant system information

2022-08-06T16:11:23.218862Z  INFO bevy_render::renderer: AdapterInfo { name: "Apple M1", vendor: 0, device: 0, device_type: IntegratedGpu, backend: Metal }

What you did

  1. Used post_processing as an example, made my main camera output to an Image target.
  2. Subscribed to window resize events.
  3. Updated camera target image descriptor size and size.

What went wrong

Panic due to validation error.

2022-08-06T16:14:40.407438Z ERROR wgpu::backend::direct: Handling wgpu errors as fatal by default    
thread 'main' panicked at 'wgpu error: Validation Error

Caused by:
    In a RenderPass
      note: encoder = `<CommandBuffer-(0, 8478, Metal)>`
    In a pass parameter
      note: command buffer = `<CommandBuffer-(0, 8478, Metal)>`
    attachments have differing sizes: ("color", Extent3d { width: 800, height: 800, depth_or_array_layers: 1 }) is followed by ("resolve", Extent3d { width: 798, height: 780, depth_or_array_layers: 1 })

Additional information

Resizing code that causes error:

fn update_target_on_resize(
    ....
    mut events:              EventReader<WindowResized>,
    mut query_camera: Query<(Entity, &Camera, &CameraVelocity, &Transform, &OrthographicProjection), With<CameraMain>>,
) {

    // Take the last resize event.
    let mut window_resized = None;
    for event in events.iter() {
        window_resized = Some(event);
    }

    if let Some(event) = window_resized {
        if let Ok(post_processing_material_handle) = query_handle.get_single() {
            if let Some(post_processing_material) = materials.get_mut(&post_processing_material_handle.handle) {
                if let Some(camera_target) = images.get_mut(&post_processing_material.source_image) {

                    // TODO: use physical dimensions.
                    let size = Extent3d{
                        width:  event.width  as u32,
                        height: event.height as u32,
                        ..default()
                    };
                    camera_target.texture_descriptor.size = size;
                    camera_target.resize(camera_target.texture_descriptor.size);

Workaround with despawning main camera:

fn update_target_on_resize(
    mut commands:     Commands,
    mut events:       EventReader<WindowResized>,
        query_handle: Query<&PostProcessingHandle>,
        config:       Res<MainCameraConfig>,
    mut materials:    ResMut<Assets<PostProcessingMaterial>>,
    mut images:       ResMut<Assets<Image>>,
    mut query_camera: Query<(Entity, &Camera, &CameraVelocity, &Transform, &OrthographicProjection), With<CameraMain>>,
) {

    // Take the last resize event.
    let mut window_resized = None;
    for event in events.iter() {
        window_resized = Some(event);
    }

    // Resize image for post-processing material and re-spawn main camera.
    if let Some(event) = window_resized {
        if let Ok(post_processing_material_handle) = query_handle.get_single() {
            if let Some(post_processing_material) = materials.get_mut(&post_processing_material_handle.handle) {
                if let Some(camera_target) = images.get_mut(&post_processing_material.source_image) {

                    // TODO: use physical dimensions.
                    let size = Extent3d{
                        width:  event.width  as u32,
                        height: event.height as u32,
                        ..default()
                    };
                    camera_target.texture_descriptor.size = size;
                    camera_target.resize(camera_target.texture_descriptor.size);

                    let (
                        old_main_camera_entity,
                        old_main_camera,
                        old_main_camera_velocity,
                        old_main_camera_transform,
                        old_main_camera_projection,
                    ) = query_camera.single_mut();
                    
                    commands.entity(old_main_camera_entity).despawn();
                    
                    let mut main_camera = Camera2dBundle {
                        camera_2d: Camera2d {
                            clear_color: CLEAR_COLOR,
                            ..default()
                        },
                        camera: Camera {
                            priority: old_main_camera.priority - 1,
                            target: RenderTarget::Image(post_processing_material.source_image.clone()),
                            ..default()
                        },
                        ..default()
                    };
                    
                    let resolution = event.width / event.height;
                    
                    main_camera.projection.top           =  1.0;
                    main_camera.projection.bottom        = -1.0;
                    main_camera.projection.right         =  1.0 * resolution;
                    main_camera.projection.left          = -1.0 * resolution;
                    main_camera.projection.scaling_mode  = ScalingMode::Auto {
                        min_width: 100.0,
                        min_height: 100.0,
                    };
                    main_camera.projection.scale         = old_main_camera_projection.scale;
                    main_camera.transform                = *old_main_camera_transform;
                    
                    commands
                        .spawn_bundle(main_camera)
                        .insert(CameraMain)
                        .insert(RenderLayers::from_layers(&[0, 1, 2, 3, 4, 5, 6]))
                        .insert(*old_main_camera_velocity)
                        .insert(config.movement.clone())
                        .insert(UiCameraConfig {
                            show_ui: false,
                            ..default()
                        });
                }

            }
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-RenderingDrawing game state to the screenC-BugAn unexpected or incorrect behaviorS-Ready-For-ImplementationThis issue is ready for an implementation PR. Go for it!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions