//! //! The mighty triangle example. //! This examples shows colord triangle on white background. //! Nothing fancy. Just prove that `rendy` works. //! use rendy::{ command::{Families, QueueId, RenderPassEncoder}, factory::{Config, Factory}, graph::{ present::PresentNode, render::*, Graph, GraphBuilder, GraphContext, NodeBuffer, NodeImage, }, hal, init::winit::{ event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, }, init::AnyWindowedRendy, memory::Dynamic, mesh::PosColor, resource::{Buffer, BufferInfo, DescriptorSetLayout, Escape, Handle}, shader::{ShaderKind, SourceLanguage, SourceShaderInfo, SpirvShader}, }; #[cfg(feature = "spirv-reflection")] use rendy::shader::SpirvReflection; #[cfg(not(feature = "spirv-reflection"))] use rendy::mesh::AsVertex; lazy_static::lazy_static! { static ref VERTEX: SpirvShader = SourceShaderInfo::new( " #version 450 #extension GL_ARB_separate_shader_objects : enable layout(location = 0) in vec3 pos; layout(location = 1) in vec4 color; layout(location = 0) out vec4 frag_color; void main() { frag_color = color; gl_Position = vec4(pos, 1.0); } ", "triangle.vert", ShaderKind::Vertex, SourceLanguage::GLSL, "main", ).precompile().unwrap(); static ref FRAGMENT: SpirvShader = SourceShaderInfo::new( " #version 450 #extension GL_ARB_separate_shader_objects : enable layout(early_fragment_tests) in; layout(location = 0) in vec4 frag_color; layout(location = 0) out vec4 color; void main() { color = frag_color; } ", "triangle.frag", ShaderKind::Fragment, SourceLanguage::GLSL, "main", ).precompile().unwrap(); static ref SHADERS: rendy::shader::ShaderSetBuilder = rendy::shader::ShaderSetBuilder::default() .with_vertex(&*VERTEX).unwrap() .with_fragment(&*FRAGMENT).unwrap(); } #[cfg(feature = "spirv-reflection")] lazy_static::lazy_static! { static ref SHADER_REFLECTION: SpirvReflection = SHADERS.reflect().unwrap(); } #[derive(Debug, Default)] struct TriangleRenderPipelineDesc; #[derive(Debug)] struct TriangleRenderPipeline { vertex: Option>>, } impl SimpleGraphicsPipelineDesc for TriangleRenderPipelineDesc where B: hal::Backend, T: ?Sized, { type Pipeline = TriangleRenderPipeline; fn depth_stencil(&self) -> Option { None } fn load_shader_set(&self, factory: &mut Factory, _aux: &T) -> rendy_shader::ShaderSet { SHADERS.build(factory, Default::default()).unwrap() } fn vertices( &self, ) -> Vec<( Vec>, hal::pso::ElemStride, hal::pso::VertexInputRate, )> { #[cfg(feature = "spirv-reflection")] return vec![SHADER_REFLECTION .attributes_range(..) .unwrap() .gfx_vertex_input_desc(hal::pso::VertexInputRate::Vertex)]; #[cfg(not(feature = "spirv-reflection"))] return vec![PosColor::vertex().gfx_vertex_input_desc(hal::pso::VertexInputRate::Vertex)]; } fn build<'a>( self, _ctx: &GraphContext, _factory: &mut Factory, _queue: QueueId, _aux: &T, buffers: Vec, images: Vec, set_layouts: &[Handle>], ) -> Result, rendy_core::hal::pso::CreationError> { assert!(buffers.is_empty()); assert!(images.is_empty()); assert!(set_layouts.is_empty()); Ok(TriangleRenderPipeline { vertex: None }) } } impl SimpleGraphicsPipeline for TriangleRenderPipeline where B: hal::Backend, T: ?Sized, { type Desc = TriangleRenderPipelineDesc; fn prepare( &mut self, factory: &Factory, _queue: QueueId, _set_layouts: &[Handle>], _index: usize, _aux: &T, ) -> PrepareResult { if self.vertex.is_none() { #[cfg(feature = "spirv-reflection")] let vbuf_size = SHADER_REFLECTION.attributes_range(..).unwrap().stride as u64 * 3; #[cfg(not(feature = "spirv-reflection"))] let vbuf_size = PosColor::vertex().stride as u64 * 3; let mut vbuf = factory .create_buffer( BufferInfo { size: vbuf_size, usage: hal::buffer::Usage::VERTEX, }, Dynamic, ) .unwrap(); unsafe { // Fresh buffer. factory .upload_visible_buffer( &mut vbuf, 0, &[ PosColor { position: [0.0, -0.5, 0.0].into(), color: [1.0, 0.0, 0.0, 1.0].into(), }, PosColor { position: [0.5, 0.5, 0.0].into(), color: [0.0, 1.0, 0.0, 1.0].into(), }, PosColor { position: [-0.5, 0.5, 0.0].into(), color: [0.0, 0.0, 1.0, 1.0].into(), }, ], ) .unwrap(); } self.vertex = Some(vbuf); } PrepareResult::DrawReuse } fn draw( &mut self, _layout: &B::PipelineLayout, mut encoder: RenderPassEncoder<'_, B>, _index: usize, _aux: &T, ) { let vbuf = self.vertex.as_ref().unwrap(); unsafe { encoder.bind_vertex_buffers(0, Some((vbuf.raw(), 0))); encoder.draw(0..3, 0..1); } } fn dispose(self, _factory: &mut Factory, _aux: &T) {} } fn run( event_loop: EventLoop<()>, mut factory: Factory, mut families: Families, graph: Graph, ) { let started = std::time::Instant::now(); let mut frame = 0u64; let mut elapsed = started.elapsed(); let mut graph = Some(graph); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, _ => {} }, Event::EventsCleared => { factory.maintain(&mut families); if let Some(ref mut graph) = graph { graph.run(&mut factory, &mut families, &()); frame += 1; } elapsed = started.elapsed(); if elapsed >= std::time::Duration::new(5, 0) { *control_flow = ControlFlow::Exit } } _ => {} } if *control_flow == ControlFlow::Exit && graph.is_some() { let elapsed_ns = elapsed.as_secs() * 1_000_000_000 + elapsed.subsec_nanos() as u64; log::info!( "Elapsed: {:?}. Frames: {}. FPS: {}", elapsed, frame, frame * 1_000_000_000 / elapsed_ns ); graph.take().unwrap().dispose(&mut factory, &()); } }); } fn main() { env_logger::Builder::from_default_env() .filter_module("source_shaders", log::LevelFilter::Trace) .init(); let config: Config = Default::default(); let event_loop = EventLoop::new(); let window = WindowBuilder::new() .with_title("Rendy example") .with_inner_size((960, 640).into()); let rendy = AnyWindowedRendy::init_auto(&config, window, &event_loop).unwrap(); rendy::with_any_windowed_rendy!((rendy) (mut factory, mut families, surface, window) => { let mut graph_builder = GraphBuilder::<_, ()>::new(); let size = window.inner_size().to_physical(window.hidpi_factor()); let color = graph_builder.create_image( hal::image::Kind::D2(size.width as u32, size.height as u32, 1, 1), 1, factory.get_surface_format(&surface), Some(hal::command::ClearValue { color: hal::command::ClearColor { float32: [1.0, 1.0, 1.0, 1.0], }, }), ); let pass = graph_builder.add_node( TriangleRenderPipeline::builder() .into_subpass() .with_color(color) .into_pass(), ); graph_builder.add_node(PresentNode::builder(&factory, surface, color).with_dependency(pass)); let graph = graph_builder .build(&mut factory, &mut families, &mut ()) .unwrap(); run(event_loop, factory, families, graph); } ); }