diff --git a/Cargo.toml b/Cargo.toml index 3f4577f..5919779 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,10 +63,6 @@ rand = "0.10.0" [target.'cfg(target_os = "linux")'.dev-dependencies] processing_glfw = { workspace = true, features = ["wayland"] } -[[example]] -name = "test" -path = "examples/test.rs" - [patch."https://github.com/bevyengine/bevy"] bevy = { git = "https://github.com/processing/bevy", branch = "main" } diff --git a/crates/processing_render/Cargo.toml b/crates/processing_render/Cargo.toml index a2097a3..5c83a5c 100644 --- a/crates/processing_render/Cargo.toml +++ b/crates/processing_render/Cargo.toml @@ -22,6 +22,7 @@ half = "2.7" crossbeam-channel = "0.5" processing_core = { workspace = true } processing_midi = { workspace = true } +wgpu = { version = "29.0.1", default-features = false } [build-dependencies] wesl = { workspace = true, features = ["package"] } diff --git a/crates/processing_render/src/graphics.rs b/crates/processing_render/src/graphics.rs index ffbc56c..bfb7af5 100644 --- a/crates/processing_render/src/graphics.rs +++ b/crates/processing_render/src/graphics.rs @@ -15,7 +15,8 @@ use bevy::{ render::{ RenderApp, render_resource::{ - CommandEncoderDescriptor, Extent3d, MapMode, Origin3d, PollType, TexelCopyBufferInfo, + CommandEncoderDescriptor, Extent3d, LoadOp, MapMode, Operations, Origin3d, PollType, + RenderPassColorAttachment, RenderPassDescriptor, StoreOp, TexelCopyBufferInfo, TexelCopyBufferLayout, TexelCopyTextureInfo, Texture, TextureFormat, TextureUsages, }, renderer::{RenderDevice, RenderQueue}, @@ -36,6 +37,8 @@ use crate::{ }; use processing_core::error::{ProcessingError, Result}; +pub const DEFAULT_CLEAR_COLOR: Color = Color::srgba_u8(208, 208, 208, 255); + pub struct GraphicsPlugin; impl Plugin for GraphicsPlugin { @@ -483,6 +486,60 @@ pub fn end_draw(app: &mut App, entity: Entity) -> Result<()> { present(app, entity) } +/// Do some work on the GPU to ensure that the render target texture is initialized and can be read +/// from/written to. +/// +/// This is necessary on some platforms (notably macOS) to avoid issues with the first few frames of +/// rendering being corrupted or not appearing at all. +/// +// TODO: why is metal particularly affected by this? can we remove this? +pub fn warmup(app: &mut App, entity: Entity) -> Result<()> { + let main_texture = { + let render_world = app.sub_app_mut(RenderApp).world_mut(); + let mut query = render_world.query::<(&MainEntity, &ViewTarget)>(); + let mut found = None; + for (main_entity, vt) in query.iter(render_world) { + if **main_entity == entity { + found = Some(vt.main_texture().clone()); + break; + } + } + found.ok_or(ProcessingError::GraphicsNotFound)? + }; + + let render_app = app.sub_app(RenderApp); + let render_device = render_app.world().resource::(); + let render_queue = render_app.world().resource::(); + + let view = main_texture.create_view(&bevy::render::render_resource::TextureViewDescriptor { + label: Some("processing_warmup_view"), + ..Default::default() + }); + let mut encoder = render_device.create_command_encoder(&CommandEncoderDescriptor { + label: Some("processing_warmup_encoder"), + }); + { + let _pass = encoder.begin_render_pass(&RenderPassDescriptor { + label: Some("processing_warmup_clear"), + color_attachments: &[Some(RenderPassColorAttachment { + view: &view, + depth_slice: None, + resolve_target: None, + ops: Operations { + load: LoadOp::Clear(wgpu::Color::TRANSPARENT), + store: StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + multiview_mask: None, + }); + } + render_queue.submit([encoder.finish()]); + Ok(()) +} + pub fn record_command( In((graphics_entity, cmd)): In<(Entity, DrawCommand)>, mut graphics_query: Query<&mut CommandBuffer>, diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index 27636dd..9a91a69 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -27,7 +27,7 @@ use processing_core::config::*; use processing_core::error; use crate::geometry::{AttributeFormat, AttributeValue}; -use crate::graphics::flush; +use crate::graphics::{DEFAULT_CLEAR_COLOR, flush}; use crate::image::gpu_image; use crate::render::command::DrawCommand; @@ -254,13 +254,26 @@ pub fn graphics_create( height: u32, texture_format: TextureFormat, ) -> error::Result { - app_mut(|app| { - app.world_mut() + app_mut(|app| -> error::Result { + let entity = app + .world_mut() .run_system_cached_with( graphics::create, (width, height, surface_entity, texture_format), ) - .unwrap() + .unwrap()?; + + app.update(); + #[cfg(target_os = "macos")] + graphics::warmup(app, entity)?; + + app.world_mut() + .run_system_cached_with( + graphics::record_command, + (entity, DrawCommand::BackgroundColor(DEFAULT_CLEAR_COLOR)), + ) + .unwrap()?; + Ok(entity) }) }