Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  main.rs

  Sprache: Rust
 

//! This example shows basic usage of wgpu-hal by rendering
//! a ton of moving sprites, each with a separate texture and draw call.
extern crate wgpu_hal as hal;

use hal::{
    Adapter as _, CommandEncoder as _, Device as _, Instance as _, Queue as _, Surface as _,
};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use winit::{
    event::{ElementState, Event, KeyEvent, WindowEvent},
    event_loop::ControlFlow,
    keyboard::{Key, NamedKey},
};

use std::{
    borrow::{Borrow, Cow},
    iter,
    mem::size_of,
    ptr,
    time::Instant,
};

const MAX_BUNNIES: usize = 1 << 20;
const BUNNY_SIZE: f32 = 0.15 * 256.0;
const GRAVITY: f32 = -9.8 * 100.0;
const MAX_VELOCITY: f32 = 750.0;
const DESIRED_MAX_LATENCY: u32 = 2;

#[repr(C)]
#[derive(Clone, Copy)]
struct Globals {
    mvp: [[f32; 4]; 4],
    size: [f32; 2],
    pad: [f32; 2],
}

#[repr(C, align(256))]
#[derive(Clone, Copy)]
struct Locals {
    position: [f32; 2],
    velocity: [f32; 2],
    color: u32,
    _pad: u32,
}

struct ExecutionContext<A: hal::Api> {
    encoder: A::CommandEncoder,
    fence: A::Fence,
    fence_value: hal::FenceValue,
    used_views: Vec<A::TextureView>,
    used_cmd_bufs: Vec<A::CommandBuffer>,
    frames_recorded: usize,
}

impl<A: hal::Api> ExecutionContext<A> {
    unsafe fn wait_and_clear(&mut self, device: &A::Device) {
        device.wait(&self.fence, self.fence_value, !0).unwrap();
        self.encoder.reset_all(self.used_cmd_bufs.drain(..));
        for view in self.used_views.drain(..) {
            device.destroy_texture_view(view);
        }
        self.frames_recorded = 0;
    }
}

#[allow(dead_code)]
struct Example<A: hal::Api> {
    instance: A::Instance,
    adapter: A::Adapter,
    surface: A::Surface,
    surface_format: wgt::TextureFormat,
    device: A::Device,
    queue: A::Queue,
    global_group: A::BindGroup,
    local_group: A::BindGroup,
    global_group_layout: A::BindGroupLayout,
    local_group_layout: A::BindGroupLayout,
    pipeline_layout: A::PipelineLayout,
    shader: A::ShaderModule,
    pipeline: A::RenderPipeline,
    bunnies: Vec<Locals>,
    local_buffer: A::Buffer,
    local_alignment: u32,
    global_buffer: A::Buffer,
    sampler: A::Sampler,
    texture: A::Texture,
    texture_view: A::TextureView,
    contexts: Vec<ExecutionContext<A>>,
    context_index: usize,
    extent: [u32; 2],
    start: Instant,
}

impl<A: hal::Api> Example<A> {
    fn init(window: &winit::window::Window) -> Result<SelfBox<dyn std::error::Error>> {
        let instance_desc = hal::InstanceDescriptor {
            name: "example",
            flags: wgt::InstanceFlags::from_build_config().with_env(),
            // Can't rely on having DXC available, so use FXC instead
            dx12_shader_compiler: wgt::Dx12Compiler::Fxc,
            gles_minor_version: wgt::Gles3MinorVersion::default(),
        };
        let instance = unsafe { A::Instance::init(&instance_desc)? };
        let surface = {
            let raw_window_handle = window.window_handle()?.as_raw();
            let raw_display_handle = window.display_handle()?.as_raw();

            unsafe {
                instance
                    .create_surface(raw_display_handle, raw_window_handle)
                    .unwrap()
            }
        };

        let (adapter, capabilities) = unsafe {
            let mut adapters = instance.enumerate_adapters(Some(&surface));
            if adapters.is_empty() {
                return Err("no adapters found".into());
            }
            let exposed = adapters.swap_remove(0);
            (exposed.adapter, exposed.capabilities)
        };

        let surface_caps = unsafe { adapter.surface_capabilities(&surface) }
            .ok_or("failed to get surface capabilities")?;
        log::info!("Surface caps: {:#?}", surface_caps);

        let hal::OpenDevice { device, queue } = unsafe {
            adapter
                .open(
                    wgt::Features::empty(),
                    &wgt::Limits::default(),
                    &wgt::MemoryHints::default(),
                )
                .unwrap()
        };

        let window_size: (u32, u32) = window.inner_size().into();
        let surface_config = hal::SurfaceConfiguration {
            maximum_frame_latency: DESIRED_MAX_LATENCY.clamp(
                *surface_caps.maximum_frame_latency.start(),
                *surface_caps.maximum_frame_latency.end(),
            ),
            present_mode: wgt::PresentMode::Fifo,
            composite_alpha_mode: wgt::CompositeAlphaMode::Opaque,
            format: wgt::TextureFormat::Bgra8UnormSrgb,
            extent: wgt::Extent3d {
                width: window_size.0,
                height: window_size.1,
                depth_or_array_layers: 1,
            },
            usage: hal::TextureUses::COLOR_TARGET,
            view_formats: vec![],
        };
        unsafe {
            surface.configure(&device, &surface_config).unwrap();
        };

        let naga_shader = {
            let shader_file = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
                .join("examples")
                .join("halmark")
                .join("shader.wgsl");
            let source = std::fs::read_to_string(shader_file).unwrap();
            let module = naga::front::wgsl::Frontend::new().parse(&source).unwrap();
            let info = naga::valid::Validator::new(
                naga::valid::ValidationFlags::all(),
                naga::valid::Capabilities::empty(),
            )
            .validate(&module)
            .unwrap();
            hal::NagaShader {
                module: Cow::Owned(module),
                info,
                debug_source: None,
            }
        };
        let shader_desc = hal::ShaderModuleDescriptor {
            label: None,
            runtime_checks: wgt::ShaderRuntimeChecks::checked(),
        };
        let shader = unsafe {
            device
                .create_shader_module(&shader_desc, hal::ShaderInput::Naga(naga_shader))
                .unwrap()
        };

        let global_bgl_desc = hal::BindGroupLayoutDescriptor {
            label: None,
            flags: hal::BindGroupLayoutFlags::empty(),
            entries: &[
                wgt::BindGroupLayoutEntry {
                    binding: 0,
                    visibility: wgt::ShaderStages::VERTEX,
                    ty: wgt::BindingType::Buffer {
                        ty: wgt::BufferBindingType::Uniform,
                        has_dynamic_offset: false,
                        min_binding_size: wgt::BufferSize::new(size_of::<Globals>() as _),
                    },
                    count: None,
                },
                wgt::BindGroupLayoutEntry {
                    binding: 1,
                    visibility: wgt::ShaderStages::FRAGMENT,
                    ty: wgt::BindingType::Texture {
                        sample_type: wgt::TextureSampleType::Float { filterable: true },
                        view_dimension: wgt::TextureViewDimension::D2,
                        multisampled: false,
                    },
                    count: None,
                },
                wgt::BindGroupLayoutEntry {
                    binding: 2,
                    visibility: wgt::ShaderStages::FRAGMENT,
                    ty: wgt::BindingType::Sampler(wgt::SamplerBindingType::Filtering),
                    count: None,
                },
            ],
        };

        let global_group_layout =
            unsafe { device.create_bind_group_layout(&global_bgl_desc).unwrap() };

        let local_bgl_desc = hal::BindGroupLayoutDescriptor {
            label: None,
            flags: hal::BindGroupLayoutFlags::empty(),
            entries: &[wgt::BindGroupLayoutEntry {
                binding: 0,
                visibility: wgt::ShaderStages::VERTEX,
                ty: wgt::BindingType::Buffer {
                    ty: wgt::BufferBindingType::Uniform,
                    has_dynamic_offset: true,
                    min_binding_size: wgt::BufferSize::new(size_of::<Locals>() as _),
                },
                count: None,
            }],
        };
        let local_group_layout =
            unsafe { device.create_bind_group_layout(&local_bgl_desc).unwrap() };

        let pipeline_layout_desc = hal::PipelineLayoutDescriptor {
            label: None,
            flags: hal::PipelineLayoutFlags::empty(),
            bind_group_layouts: &[&global_group_layout, &local_group_layout],
            push_constant_ranges: &[],
        };
        let pipeline_layout = unsafe {
            device
                .create_pipeline_layout(&pipeline_layout_desc)
                .unwrap()
        };

        let constants = naga::back::PipelineConstants::default();
        let pipeline_desc = hal::RenderPipelineDescriptor {
            label: None,
            layout: &pipeline_layout,
            vertex_stage: hal::ProgrammableStage {
                module: &shader,
                entry_point: "vs_main",
                constants: &constants,
                zero_initialize_workgroup_memory: true,
            },
            vertex_buffers: &[],
            fragment_stage: Some(hal::ProgrammableStage {
                module: &shader,
                entry_point: "fs_main",
                constants: &constants,
                zero_initialize_workgroup_memory: true,
            }),
            primitive: wgt::PrimitiveState {
                topology: wgt::PrimitiveTopology::TriangleStrip,
                ..wgt::PrimitiveState::default()
            },
            depth_stencil: None,
            multisample: wgt::MultisampleState::default(),
            color_targets: &[Some(wgt::ColorTargetState {
                format: surface_config.format,
                blend: Some(wgt::BlendState::ALPHA_BLENDING),
                write_mask: wgt::ColorWrites::default(),
            })],
            multiview: None,
            cache: None,
        };
        let pipeline = unsafe { device.create_render_pipeline(&pipeline_desc).unwrap() };

        let texture_data = [0xFFu8; 4];

        let staging_buffer_desc = hal::BufferDescriptor {
            label: Some("stage"),
            size: texture_data.len() as wgt::BufferAddress,
            usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::COPY_SRC,
            memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT,
        };
        let staging_buffer = unsafe { device.create_buffer(&staging_buffer_desc).unwrap() };
        unsafe {
            let mapping = device
                .map_buffer(&staging_buffer, 0..staging_buffer_desc.size)
                .unwrap();
            ptr::copy_nonoverlapping(
                texture_data.as_ptr(),
                mapping.ptr.as_ptr(),
                texture_data.len(),
            );
            device.unmap_buffer(&staging_buffer);
            assert!(mapping.is_coherent);
        }

        let texture_desc = hal::TextureDescriptor {
            label: None,
            size: wgt::Extent3d {
                width: 1,
                height: 1,
                depth_or_array_layers: 1,
            },
            mip_level_count: 1,
            sample_count: 1,
            dimension: wgt::TextureDimension::D2,
            format: wgt::TextureFormat::Rgba8UnormSrgb,
            usage: hal::TextureUses::COPY_DST | hal::TextureUses::RESOURCE,
            memory_flags: hal::MemoryFlags::empty(),
            view_formats: vec![],
        };
        let texture = unsafe { device.create_texture(&texture_desc).unwrap() };

        let cmd_encoder_desc = hal::CommandEncoderDescriptor {
            label: None,
            queue: &queue,
        };
        let mut cmd_encoder = unsafe { device.create_command_encoder(&cmd_encoder_desc).unwrap() };
        unsafe { cmd_encoder.begin_encoding(Some("init")).unwrap() };
        {
            let buffer_barrier = hal::BufferBarrier {
                buffer: &staging_buffer,
                usage: hal::StateTransition {
                    from: hal::BufferUses::empty(),
                    to: hal::BufferUses::COPY_SRC,
                },
            };
            let texture_barrier1 = hal::TextureBarrier {
                texture: &texture,
                range: wgt::ImageSubresourceRange::default(),
                usage: hal::StateTransition {
                    from: hal::TextureUses::UNINITIALIZED,
                    to: hal::TextureUses::COPY_DST,
                },
            };
            let texture_barrier2 = hal::TextureBarrier {
                texture: &texture,
                range: wgt::ImageSubresourceRange::default(),
                usage: hal::StateTransition {
                    from: hal::TextureUses::COPY_DST,
                    to: hal::TextureUses::RESOURCE,
                },
            };
            let copy = hal::BufferTextureCopy {
                buffer_layout: wgt::TexelCopyBufferLayout {
                    offset: 0,
                    bytes_per_row: Some(4),
                    rows_per_image: None,
                },
                texture_base: hal::TextureCopyBase {
                    origin: wgt::Origin3d::ZERO,
                    mip_level: 0,
                    array_layer: 0,
                    aspect: hal::FormatAspects::COLOR,
                },
                size: hal::CopyExtent {
                    width: 1,
                    height: 1,
                    depth: 1,
                },
            };
            unsafe {
                cmd_encoder.transition_buffers(iter::once(buffer_barrier));
                cmd_encoder.transition_textures(iter::once(texture_barrier1));
                cmd_encoder.copy_buffer_to_texture(&staging_buffer, &texture, iter::once(copy));
                cmd_encoder.transition_textures(iter::once(texture_barrier2));
            }
        }

        let sampler_desc = hal::SamplerDescriptor {
            label: None,
            address_modes: [wgt::AddressMode::ClampToEdge; 3],
            mag_filter: wgt::FilterMode::Linear,
            min_filter: wgt::FilterMode::Nearest,
            mipmap_filter: wgt::FilterMode::Nearest,
            lod_clamp: 0.0..32.0,
            compare: None,
            anisotropy_clamp: 1,
            border_color: None,
        };
        let sampler = unsafe { device.create_sampler(&sampler_desc).unwrap() };

        let globals = Globals {
            // cgmath::ortho() projection
            mvp: [
                [2.0 / window_size.0 as f32, 0.00.00.0],
                [0.02.0 / window_size.1 as f32, 0.00.0],
                [0.00.01.00.0],
                [-1.0, -1.00.01.0],
            ],
            size: [BUNNY_SIZE; 2],
            pad: [0.02],
        };

        let global_buffer_desc = hal::BufferDescriptor {
            label: Some("global"),
            size: size_of::<Globals>() as wgt::BufferAddress,
            usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::UNIFORM,
            memory_flags: hal::MemoryFlags::PREFER_COHERENT,
        };
        let global_buffer = unsafe {
            let buffer = device.create_buffer(&global_buffer_desc).unwrap();
            let mapping = device
                .map_buffer(&buffer, 0..global_buffer_desc.size)
                .unwrap();
            ptr::copy_nonoverlapping(
                &globals as *const Globals as *const u8,
                mapping.ptr.as_ptr(),
                size_of::<Globals>(),
            );
            device.unmap_buffer(&buffer);
            assert!(mapping.is_coherent);
            buffer
        };

        let local_alignment = wgt::math::align_to(
            size_of::<Locals>() as u32,
            capabilities.limits.min_uniform_buffer_offset_alignment,
        );
        let local_buffer_desc = hal::BufferDescriptor {
            label: Some("local"),
            size: (MAX_BUNNIES as wgt::BufferAddress) * (local_alignment as wgt::BufferAddress),
            usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::UNIFORM,
            memory_flags: hal::MemoryFlags::PREFER_COHERENT,
        };
        let local_buffer = unsafe { device.create_buffer(&local_buffer_desc).unwrap() };

        let view_desc = hal::TextureViewDescriptor {
            label: None,
            format: texture_desc.format,
            dimension: wgt::TextureViewDimension::D2,
            usage: hal::TextureUses::RESOURCE,
            range: wgt::ImageSubresourceRange::default(),
        };
        let texture_view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() };

        let global_group = {
            let global_buffer_binding = hal::BufferBinding {
                buffer: &global_buffer,
                offset: 0,
                size: None,
            };
            let texture_binding = hal::TextureBinding {
                view: &texture_view,
                usage: hal::TextureUses::RESOURCE,
            };
            let global_group_desc = hal::BindGroupDescriptor {
                label: Some("global"),
                layout: &global_group_layout,
                buffers: &[global_buffer_binding],
                samplers: &[&sampler],
                textures: &[texture_binding],
                acceleration_structures: &[],
                entries: &[
                    hal::BindGroupEntry {
                        binding: 0,
                        resource_index: 0,
                        count: 1,
                    },
                    hal::BindGroupEntry {
                        binding: 1,
                        resource_index: 0,
                        count: 1,
                    },
                    hal::BindGroupEntry {
                        binding: 2,
                        resource_index: 0,
                        count: 1,
                    },
                ],
            };
            unsafe { device.create_bind_group(&global_group_desc).unwrap() }
        };

        let local_group = {
            let local_buffer_binding = hal::BufferBinding {
                buffer: &local_buffer,
                offset: 0,
                size: wgt::BufferSize::new(size_of::<Locals>() as _),
            };
            let local_group_desc = hal::BindGroupDescriptor {
                label: Some("local"),
                layout: &local_group_layout,
                buffers: &[local_buffer_binding],
                samplers: &[],
                textures: &[],
                acceleration_structures: &[],
                entries: &[hal::BindGroupEntry {
                    binding: 0,
                    resource_index: 0,
                    count: 1,
                }],
            };
            unsafe { device.create_bind_group(&local_group_desc).unwrap() }
        };

        let init_fence_value = 1;
        let fence = unsafe {
            let mut fence = device.create_fence().unwrap();
            let init_cmd = cmd_encoder.end_encoding().unwrap();
            queue
                .submit(&[&init_cmd], &[], (&mut fence, init_fence_value))
                .unwrap();
            device.wait(&fence, init_fence_value, !0).unwrap();
            device.destroy_buffer(staging_buffer);
            cmd_encoder.reset_all(iter::once(init_cmd));
            fence
        };

        Ok(Example {
            instance,
            surface,
            surface_format: surface_config.format,
            adapter,
            device,
            queue,
            pipeline_layout,
            shader,
            pipeline,
            global_group,
            local_group,
            global_group_layout,
            local_group_layout,
            bunnies: Vec::new(),
            local_buffer,
            local_alignment,
            global_buffer,
            sampler,
            texture,
            texture_view,
            contexts: vec![ExecutionContext {
                encoder: cmd_encoder,
                fence,
                fence_value: init_fence_value + 1,
                used_views: Vec::new(),
                used_cmd_bufs: Vec::new(),
                frames_recorded: 0,
            }],
            context_index: 0,
            extent: [window_size.0, window_size.1],
            start: Instant::now(),
        })
    }

    fn is_empty(&self) -> bool {
        self.bunnies.is_empty()
    }

    fn exit(mut self) {
        unsafe {
            {
                let ctx = &mut self.contexts[self.context_index];
                self.queue
                    .submit(&[], &[], (&mut ctx.fence, ctx.fence_value))
                    .unwrap();
            }

            for mut ctx in self.contexts {
                ctx.wait_and_clear(&self.device);
                drop(ctx.encoder);
                self.device.destroy_fence(ctx.fence);
            }

            self.device.destroy_bind_group(self.local_group);
            self.device.destroy_bind_group(self.global_group);
            self.device.destroy_buffer(self.local_buffer);
            self.device.destroy_buffer(self.global_buffer);
            self.device.destroy_texture_view(self.texture_view);
            self.device.destroy_texture(self.texture);
            self.device.destroy_sampler(self.sampler);
            self.device.destroy_shader_module(self.shader);
            self.device.destroy_render_pipeline(self.pipeline);
            self.device
                .destroy_bind_group_layout(self.local_group_layout);
            self.device
                .destroy_bind_group_layout(self.global_group_layout);
            self.device.destroy_pipeline_layout(self.pipeline_layout);

            self.surface.unconfigure(&self.device);
            drop(self.queue);
            drop(self.device);
            drop(self.surface);
            drop(self.adapter);
        }
    }

    fn update(&mut self, event: winit::event::WindowEvent) {
        if let winit::event::WindowEvent::KeyboardInput {
            event:
                KeyEvent {
                    logical_key: Key::Named(NamedKey::Space),
                    state: ElementState::Pressed,
                    ..
                },
            ..
        } = event
        {
            let spawn_count = 64 + self.bunnies.len() / 2;
            let elapsed = self.start.elapsed();
            let color = elapsed.as_nanos() as u32;
            println!(
                "Spawning {} bunnies, total at {}",
                spawn_count,
                self.bunnies.len() + spawn_count
            );
            for i in 0..spawn_count {
                let random = ((elapsed.as_nanos() * (i + 1as u128) & 0xFF) as f32 / 255.0;
                let speed = random * MAX_VELOCITY - (MAX_VELOCITY * 0.5);
                self.bunnies.push(Locals {
                    position: [0.00.5 * (self.extent[1as f32)],
                    velocity: [speed, 0.0],
                    color,
                    _pad: 0,
                });
            }
        }
    }

    fn render(&mut self) {
        let delta = 0.01;
        for bunny in self.bunnies.iter_mut() {
            bunny.position[0] += bunny.velocity[0] * delta;
            bunny.position[1] += bunny.velocity[1] * delta;
            bunny.velocity[1] += GRAVITY * delta;
            if (bunny.velocity[0] > 0.0
                && bunny.position[0] + 0.5 * BUNNY_SIZE > self.extent[0as f32)
                || (bunny.velocity[0] < 0.0 && bunny.position[0] - 0.5 * BUNNY_SIZE < 0.0)
            {
                bunny.velocity[0] *= -1.0;
            }
            if bunny.velocity[1] < 0.0 && bunny.position[1] < 0.5 * BUNNY_SIZE {
                bunny.velocity[1] *= -1.0;
            }
        }

        if !self.bunnies.is_empty() {
            let size = self.bunnies.len() * self.local_alignment as usize;
            unsafe {
                let mapping = self
                    .device
                    .map_buffer(&self.local_buffer, 0..size as wgt::BufferAddress)
                    .unwrap();
                ptr::copy_nonoverlapping(
                    self.bunnies.as_ptr() as *const u8,
                    mapping.ptr.as_ptr(),
                    size,
                );
                assert!(mapping.is_coherent);
                self.device.unmap_buffer(&self.local_buffer);
            }
        }

        let ctx = &mut self.contexts[self.context_index];

        let surface_tex = unsafe {
            self.surface
                .acquire_texture(None, &ctx.fence)
                .unwrap()
                .unwrap()
                .texture
        };

        let target_barrier0 = hal::TextureBarrier {
            texture: surface_tex.borrow(),
            range: wgt::ImageSubresourceRange::default(),
            usage: hal::StateTransition {
                from: hal::TextureUses::UNINITIALIZED,
                to: hal::TextureUses::COLOR_TARGET,
            },
        };
        unsafe {
            ctx.encoder.begin_encoding(Some("frame")).unwrap();
            ctx.encoder.transition_textures(iter::once(target_barrier0));
        }

        let surface_view_desc = hal::TextureViewDescriptor {
            label: None,
            format: self.surface_format,
            dimension: wgt::TextureViewDimension::D2,
            usage: hal::TextureUses::COLOR_TARGET,
            range: wgt::ImageSubresourceRange::default(),
        };
        let surface_tex_view = unsafe {
            self.device
                .create_texture_view(surface_tex.borrow(), &surface_view_desc)
                .unwrap()
        };
        let pass_desc = hal::RenderPassDescriptor {
            label: None,
            extent: wgt::Extent3d {
                width: self.extent[0],
                height: self.extent[1],
                depth_or_array_layers: 1,
            },
            sample_count: 1,
            color_attachments: &[Some(hal::ColorAttachment {
                target: hal::Attachment {
                    view: &surface_tex_view,
                    usage: hal::TextureUses::COLOR_TARGET,
                },
                resolve_target: None,
                ops: hal::AttachmentOps::STORE,
                clear_value: wgt::Color {
                    r: 0.1,
                    g: 0.2,
                    b: 0.3,
                    a: 1.0,
                },
            })],
            depth_stencil_attachment: None,
            multiview: None,
            timestamp_writes: None,
            occlusion_query_set: None,
        };
        unsafe {
            ctx.encoder.begin_render_pass(&pass_desc);
            ctx.encoder.set_render_pipeline(&self.pipeline);
            ctx.encoder
                .set_bind_group(&self.pipeline_layout, 0, &self.global_group, &[]);
        }

        for i in 0..self.bunnies.len() {
            let offset = (i as wgt::DynamicOffset) * (self.local_alignment as wgt::DynamicOffset);
            unsafe {
                ctx.encoder
                    .set_bind_group(&self.pipeline_layout, 1, &self.local_group, &[offset]);
                ctx.encoder.draw(0401);
            }
        }

        ctx.frames_recorded += 1;

        let target_barrier1 = hal::TextureBarrier {
            texture: surface_tex.borrow(),
            range: wgt::ImageSubresourceRange::default(),
            usage: hal::StateTransition {
                from: hal::TextureUses::COLOR_TARGET,
                to: hal::TextureUses::PRESENT,
            },
        };
        unsafe {
            ctx.encoder.end_render_pass();
            ctx.encoder.transition_textures(iter::once(target_barrier1));
        }

        unsafe {
            let cmd_buf = ctx.encoder.end_encoding().unwrap();
            self.queue
                .submit(
                    &[&cmd_buf],
                    &[&surface_tex],
                    (&mut ctx.fence, ctx.fence_value),
                )
                .unwrap();
            self.queue.present(&self.surface, surface_tex).unwrap();
            ctx.used_cmd_bufs.push(cmd_buf);
            ctx.used_views.push(surface_tex_view);
        };

        log::debug!("Context switch from {}"self.context_index);
        let old_fence_value = ctx.fence_value;
        if self.contexts.len() == 1 {
            let hal_desc = hal::CommandEncoderDescriptor {
                label: None,
                queue: &self.queue,
            };
            self.contexts.push(unsafe {
                ExecutionContext {
                    encoder: self.device.create_command_encoder(&hal_desc).unwrap(),
                    fence: self.device.create_fence().unwrap(),
                    fence_value: 0,
                    used_views: Vec::new(),
                    used_cmd_bufs: Vec::new(),
                    frames_recorded: 0,
                }
            });
        }
        self.context_index = (self.context_index + 1) % self.contexts.len();
        let next = &mut self.contexts[self.context_index];
        unsafe {
            next.wait_and_clear(&self.device);
        }
        next.fence_value = old_fence_value + 1;
    }
}

cfg_if::cfg_if! {
    // Apple + Metal
    if #[cfg(all(target_vendor = "apple", feature = "metal"))] {
        type Api = hal::api::Metal;
    }
    // Wasm + Vulkan
    else if #[cfg(all(not(target_arch = "wasm32"), feature = "vulkan"))] {
        type Api = hal::api::Vulkan;
    }
    // Windows + DX12
    else if #[cfg(all(windows, feature = "dx12"))] {
        type Api = hal::api::Dx12;
    }
    // Anything + GLES
    else if #[cfg(feature = "gles")] {
        type Api = hal::api::Gles;
    }
    // Fallback
    else {
        type Api = hal::api::Empty;
    }
}

fn main() {
    env_logger::init();

    let event_loop = winit::event_loop::EventLoop::new().unwrap();
    let window = winit::window::WindowBuilder::new()
        .with_title("hal-bunnymark")
        .build(&event_loop)
        .unwrap();

    let example_result = Example::<Api>::init(&window);
    let mut example = Some(example_result.expect("Selected backend is not supported"));

    println!("Press space to spawn bunnies.");

    let mut last_frame_inst = Instant::now();
    let (mut frame_count, mut accum_time) = (00.0);

    event_loop
        .run(move |event, target| {
            let _ = &window; // force ownership by the closure
            target.set_control_flow(ControlFlow::Poll);

            match event {
                Event::LoopExiting => {
                    example.take().unwrap().exit();
                }
                Event::WindowEvent { event, .. } => match event {
                    WindowEvent::KeyboardInput {
                        event:
                            KeyEvent {
                                logical_key: Key::Named(NamedKey::Escape),
                                state: ElementState::Pressed,
                                ..
                            },
                        ..
                    }
                    | WindowEvent::CloseRequested => target.exit(),
                    WindowEvent::RedrawRequested => {
                        let ex = example.as_mut().unwrap();
                        {
                            accum_time += last_frame_inst.elapsed().as_secs_f32();
                            last_frame_inst = Instant::now();
                            frame_count += 1;
                            if frame_count == 100 && !ex.is_empty() {
                                println!(
                                    "Avg frame time {}ms",
                                    accum_time * 1000.0 / frame_count as f32
                                );
                                accum_time = 0.0;
                                frame_count = 0;
                            }
                        }
                        ex.render();
                        window.request_redraw();
                    }
                    _ => {
                        example.as_mut().unwrap().update(event);
                    }
                },
                _ => {}
            }
        })
        .unwrap();
}

Messung V0.5 in Prozent
C=99 H=79 G=89

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-06-18) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik