Added compute to the new pipelined renderer.

This commit is contained in:
StarArawn 2021-05-30 18:54:48 -04:00 committed by Carter Anderson
parent 4ac2ed7cc6
commit cdf06ea293
29 changed files with 297 additions and 60 deletions

View file

@ -15,10 +15,7 @@ pub use schedule_runner::*;
pub mod prelude {
#[doc(hidden)]
pub use crate::{
app::App, CoreStage, DynamicPlugin, Plugin, PluginGroup,
StartupStage,
};
pub use crate::{app::App, CoreStage, DynamicPlugin, Plugin, PluginGroup, StartupStage};
}
use bevy_ecs::schedule::StageLabel;

View file

@ -1229,7 +1229,9 @@ mod tests {
fn clear_entities() {
let mut world = World::default();
world.register_component(ComponentDescriptor::new::<f32>(StorageType::SparseSet)).unwrap();
world
.register_component(ComponentDescriptor::new::<f32>(StorageType::SparseSet))
.unwrap();
world.insert_resource::<i32>(0);
world.spawn().insert(1u32);
world.spawn().insert(1.0f32);
@ -1243,9 +1245,25 @@ mod tests {
world.clear_entities();
assert_eq!(q1.iter(&world).len(), 0, "world should not contain table components");
assert_eq!(q2.iter(&world).len(), 0, "world should not contain sparse set components");
assert_eq!(world.entities().len(), 0, "world should not have any entities");
assert_eq!(*world.get_resource::<i32>().unwrap(), 0, "world should still contain resources");
assert_eq!(
q1.iter(&world).len(),
0,
"world should not contain table components"
);
assert_eq!(
q2.iter(&world).len(),
0,
"world should not contain sparse set components"
);
assert_eq!(
world.entities().len(),
0,
"world should not have any entities"
);
assert_eq!(
*world.get_resource::<i32>().unwrap(),
0,
"world should still contain resources"
);
}
}

View file

@ -139,4 +139,4 @@ pub mod internal;
#[cfg(feature = "mint")]
mod mint;
mod glam;
mod glam;

View file

@ -1,4 +1,7 @@
use crate::camera::{CAMERA_2D, CAMERA_3D, Camera, DepthCalculation, OrthographicProjection, PerspectiveProjection, ScalingMode};
use crate::camera::{
Camera, DepthCalculation, OrthographicProjection, PerspectiveProjection, ScalingMode,
CAMERA_2D, CAMERA_3D,
};
use bevy_ecs::bundle::Bundle;
use bevy_transform::components::{GlobalTransform, Transform};

View file

@ -2,4 +2,4 @@ mod color;
mod colorspace;
pub use color::*;
pub use colorspace::*;
pub use colorspace::*;

View file

@ -1,20 +1,17 @@
mod draw_state;
mod draw;
mod draw_state;
pub use draw_state::*;
pub use draw::*;
pub use draw_state::*;
use crate::{RenderStage, pass::RenderPassColorAttachment, renderer::RenderContext};
use crate::{
camera::CameraPlugin,
color::Color,
pass::{
LoadOp, Operations, PassDescriptor, RenderPass,
TextureAttachment,
},
pass::{LoadOp, Operations, PassDescriptor, RenderPass, TextureAttachment},
render_graph::{Node, RenderGraph, ResourceSlotInfo, ResourceSlots, WindowSwapChainNode},
render_resource::RenderResourceType,
};
use crate::{pass::RenderPassColorAttachment, renderer::RenderContext, RenderStage};
use bevy_app::{App, Plugin};
use bevy_ecs::prelude::*;
use bevy_window::WindowId;
@ -120,17 +117,20 @@ impl Node for MainPassNode {
let transparent_phase = world.get_resource::<RenderPhase>().unwrap();
let draw_functions = world.get_resource::<DrawFunctions>().unwrap();
render_context.begin_pass(&pass_descriptor, &mut |render_pass: &mut dyn RenderPass| {
let mut draw_functions = draw_functions.draw_function.lock();
let mut tracked_pass = TrackedRenderPass::new(render_pass);
for drawable in transparent_phase.drawn_things.iter() {
draw_functions[drawable.draw_function].draw(
world,
&mut tracked_pass,
drawable.draw_key,
drawable.sort_key,
);
}
})
render_context.begin_render_pass(
&pass_descriptor,
&mut |render_pass: &mut dyn RenderPass| {
let mut draw_functions = draw_functions.draw_function.lock();
let mut tracked_pass = TrackedRenderPass::new(render_pass);
for drawable in transparent_phase.drawn_things.iter() {
draw_functions[drawable.draw_function].draw(
world,
&mut tracked_pass,
drawable.draw_key,
drawable.sort_key,
);
}
},
)
}
}

View file

@ -1,6 +1,9 @@
mod conversions;
use crate::pipeline::{IndexFormat, InputStepMode, PrimitiveTopology, VertexAttribute, VertexBufferLayout, VertexFormat};
use crate::pipeline::{
IndexFormat, InputStepMode, PrimitiveTopology, VertexAttribute, VertexBufferLayout,
VertexFormat,
};
use bevy_core::cast_slice;
use bevy_math::*;
use bevy_reflect::TypeUuid;

View file

@ -0,0 +1,18 @@
use crate::{
pipeline::{BindGroupDescriptorId, PipelineId},
render_resource::BindGroupId,
renderer::RenderContext,
};
pub trait ComputePass {
fn get_render_context(&self) -> &dyn RenderContext;
fn set_pipeline(&mut self, pipeline: PipelineId);
fn dispatch(&mut self, x: u32, y: u32, z: u32);
fn set_bind_group(
&mut self,
index: u32,
bind_group_descriptor_id: BindGroupDescriptorId,
bind_group: BindGroupId,
dynamic_uniform_indices: Option<&[u32]>,
);
}

View file

@ -1,8 +1,10 @@
mod compute_pass;
mod ops;
#[allow(clippy::module_inception)]
mod pass;
mod render_pass;
pub use compute_pass::*;
pub use ops::*;
pub use pass::*;
pub use render_pass::*;

View file

@ -1,6 +1,5 @@
use crate::{color::Color, pass::Operations, render_resource::TextureId};
#[derive(Debug, Clone)]
pub enum TextureAttachment {
Id(TextureId),

View file

@ -0,0 +1,29 @@
use super::PipelineLayout;
use crate::shader::ComputeShaderStages;
use bevy_reflect::TypeUuid;
#[derive(Clone, Debug, TypeUuid)]
#[uuid = "359c1fff-0c86-4fbb-8b66-4e2af422a2f1"]
pub struct ComputePipelineDescriptor {
pub name: Option<String>,
pub layout: PipelineLayout,
pub shader_stages: ComputeShaderStages,
}
impl ComputePipelineDescriptor {
pub fn new(shader_stages: ComputeShaderStages, layout: PipelineLayout) -> Self {
ComputePipelineDescriptor {
name: None,
layout,
shader_stages,
}
}
pub fn default_config(shader_stages: ComputeShaderStages, layout: PipelineLayout) -> Self {
ComputePipelineDescriptor {
name: None,
layout,
shader_stages,
}
}
}

View file

@ -1,5 +1,6 @@
mod bind_group;
mod binding;
mod compute_pipeline;
#[allow(clippy::module_inception)]
mod pipeline;
mod pipeline_layout;
@ -9,6 +10,7 @@ mod vertex_format;
pub use bind_group::*;
pub use binding::*;
pub use compute_pipeline::*;
pub use pipeline::*;
pub use pipeline_layout::*;
pub use state_descriptors::*;

View file

@ -10,7 +10,7 @@ use crate::{
BlendComponent, BlendState, ColorTargetState, DepthBiasState, DepthStencilState,
MultisampleState, PolygonMode, PrimitiveState, StencilFaceState, StencilState,
},
shader::{ShaderStages},
shader::ShaderStages,
texture::TextureFormat,
};
use bevy_reflect::{TypeUuid, Uuid};

View file

@ -2,15 +2,15 @@ mod edge;
mod graph;
mod node;
mod node_slot;
mod schedule;
mod nodes;
mod schedule;
pub use edge::*;
pub use graph::*;
pub use node::*;
pub use node_slot::*;
pub use schedule::*;
pub use nodes::*;
pub use schedule::*;
use thiserror::Error;

View file

@ -1,3 +1,3 @@
mod window_swap_chain_node;
pub use window_swap_chain_node::*;
pub use window_swap_chain_node::*;

View file

@ -124,4 +124,4 @@ impl BindGroupBuilder {
}
}
}
}
}

View file

@ -2,7 +2,7 @@ use crate::{
render_resource::{BufferId, BufferInfo, BufferMapMode, BufferUsage},
renderer::{RenderContext, RenderResources},
};
use bevy_core::{Pod, cast_slice};
use bevy_core::{cast_slice, Pod};
pub struct BufferVec<T: Pod> {
values: Vec<T>,

View file

@ -38,4 +38,4 @@ impl RenderResourceId {
None
}
}
}
}

View file

@ -1,6 +1,6 @@
use super::RenderResourceContext;
use crate::{
pipeline::{BindGroupDescriptorId, PipelineDescriptor, PipelineId},
pipeline::{BindGroupDescriptorId, ComputePipelineDescriptor, PipelineDescriptor, PipelineId},
render_resource::{
BindGroup, BufferId, BufferInfo, BufferMapMode, SamplerId, SwapChainDescriptor, TextureId,
},
@ -101,6 +101,13 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
PipelineId::new()
}
fn create_compute_pipeline(
&self,
_pipeline_descriptor: &ComputePipelineDescriptor,
) -> PipelineId {
PipelineId::new()
}
fn create_bind_group(
&self,
_bind_group_descriptor_id: BindGroupDescriptorId,

View file

@ -1,6 +1,6 @@
use super::RenderResourceContext;
use crate::{
pass::{PassDescriptor, RenderPass},
pass::{ComputePass, PassDescriptor, RenderPass},
render_resource::{BufferId, TextureId},
texture::Extent3d,
};
@ -49,9 +49,11 @@ pub trait RenderContext {
destination_mip_level: u32,
size: Extent3d,
);
fn begin_pass(
fn begin_render_pass(
&mut self,
pass_descriptor: &PassDescriptor,
run_pass: &mut dyn FnMut(&mut dyn RenderPass),
);
fn begin_compute_pass(&mut self, run_pass: &mut dyn FnMut(&mut dyn ComputePass));
}

View file

@ -1,5 +1,5 @@
use crate::{
pipeline::{BindGroupDescriptorId, PipelineDescriptor, PipelineId},
pipeline::{BindGroupDescriptorId, ComputePipelineDescriptor, PipelineDescriptor, PipelineId},
render_resource::{
BindGroup, BufferId, BufferInfo, BufferMapMode, SamplerId, SwapChainDescriptor, TextureId,
},
@ -65,6 +65,10 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
fn get_aligned_uniform_size(&self, size: usize, dynamic: bool) -> usize;
fn get_aligned_texture_size(&self, data_size: usize) -> usize;
fn create_render_pipeline(&self, pipeline_descriptor: &PipelineDescriptor) -> PipelineId;
fn create_compute_pipeline(
&self,
_pipeline_descriptor: &ComputePipelineDescriptor,
) -> PipelineId;
fn bind_group_descriptor_exists(&self, bind_group_descriptor_id: BindGroupDescriptorId)
-> bool;
fn create_bind_group(

View file

@ -253,6 +253,12 @@ pub struct ShaderStages {
pub fragment: Option<ShaderId>,
}
/// All stages in a compute shader program
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ComputeShaderStages {
pub compute: ShaderId,
}
#[derive(Default)]
pub struct ShaderLoader;

View file

@ -1,12 +1,12 @@
mod bundle;
mod render;
mod rect;
mod render;
mod sprite;
pub use bundle::*;
pub use rect::*;
pub use render::*;
pub use sprite::*;
pub use bundle::*;
use bevy_app::prelude::*;
use bevy_ecs::prelude::IntoSystem;

View file

@ -36,4 +36,4 @@ impl Sprite {
flip_y: false,
}
}
}
}

View file

@ -0,0 +1,74 @@
use crate::{resources::WgpuResourceRefs, WgpuRenderContext};
use bevy_render2::{
pass::ComputePass,
pipeline::{BindGroupDescriptorId, ComputePipelineDescriptor, PipelineId},
render_resource::BindGroupId,
renderer::RenderContext,
};
use bevy_utils::tracing::trace;
#[derive(Debug)]
pub struct WgpuComputePass<'a> {
pub compute_pass: wgpu::ComputePass<'a>,
pub render_context: &'a WgpuRenderContext,
pub wgpu_resources: WgpuResourceRefs<'a>,
pub pipeline_descriptor: Option<&'a ComputePipelineDescriptor>,
}
impl<'a> ComputePass for WgpuComputePass<'a> {
fn get_render_context(&self) -> &dyn RenderContext {
self.render_context
}
fn set_bind_group(
&mut self,
index: u32,
bind_group_descriptor_id: BindGroupDescriptorId,
bind_group: BindGroupId,
dynamic_uniform_indices: Option<&[u32]>,
) {
if let Some(bind_group_info) = self
.wgpu_resources
.bind_groups
.get(&bind_group_descriptor_id)
{
if let Some(wgpu_bind_group) = bind_group_info.bind_groups.get(&bind_group) {
const EMPTY: &[u32] = &[];
let dynamic_uniform_indices =
if let Some(dynamic_uniform_indices) = dynamic_uniform_indices {
dynamic_uniform_indices
} else {
EMPTY
};
self.wgpu_resources
.used_bind_group_sender
.send(bind_group)
.unwrap();
trace!(
"set bind group {:?} {:?}: {:?}",
bind_group_descriptor_id,
dynamic_uniform_indices,
bind_group
);
self.compute_pass
.set_bind_group(index, wgpu_bind_group, dynamic_uniform_indices);
}
}
}
fn set_pipeline(&mut self, pipeline: PipelineId) {
let pipeline = self
.wgpu_resources
.compute_pipelines
.get(&pipeline)
.expect(
"Attempted to use a pipeline that does not exist in this `RenderPass`'s `RenderContext`.",
);
self.compute_pass.set_pipeline(pipeline);
}
fn dispatch(&mut self, x: u32, y: u32, z: u32) {
self.compute_pass.dispatch(x, y, z);
}
}

View file

@ -1,5 +1,6 @@
pub mod diagnostic;
mod compute_pass;
mod render_context;
mod render_graph_executor;
mod render_pass;
@ -8,6 +9,7 @@ mod renderer;
mod resources;
mod type_converter;
pub use compute_pass::*;
pub use render_context::*;
pub use render_pass::*;
pub use render_resource_context::*;

View file

@ -1,9 +1,12 @@
use super::WgpuRenderResourceContext;
use crate::{WgpuRenderPass, resources::WgpuResourceRefs, type_converter::WgpuInto};
use crate::{
compute_pass::WgpuComputePass, resources::WgpuResourceRefs, type_converter::WgpuInto,
WgpuRenderPass,
};
use bevy_render2::{
pass::{
PassDescriptor, RenderPass, RenderPassColorAttachment,
ComputePass, PassDescriptor, RenderPass, RenderPassColorAttachment,
RenderPassDepthStencilAttachment, TextureAttachment,
},
render_resource::{BufferId, TextureId},
@ -165,7 +168,7 @@ impl RenderContext for WgpuRenderContext {
&mut self.render_resource_context
}
fn begin_pass(
fn begin_render_pass(
&mut self,
pass_descriptor: &PassDescriptor,
run_pass: &mut dyn FnMut(&mut dyn RenderPass),
@ -190,6 +193,29 @@ impl RenderContext for WgpuRenderContext {
self.command_encoder.set(encoder);
}
fn begin_compute_pass(&mut self, run_pass: &mut dyn FnMut(&mut dyn ComputePass)) {
if !self.command_encoder.is_some() {
self.command_encoder.create(&self.device);
}
let resource_lock = self.render_resource_context.resources.read();
let refs = resource_lock.refs();
let mut encoder = self.command_encoder.take().unwrap();
{
let compute_pass =
encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None });
let mut wgpu_render_pass = WgpuComputePass {
compute_pass,
render_context: self,
wgpu_resources: refs,
pipeline_descriptor: None,
};
run_pass(&mut wgpu_render_pass);
}
self.command_encoder.set(encoder);
}
}
pub fn create_render_pass<'a, 'b>(
@ -225,10 +251,7 @@ fn create_wgpu_color_attachment<'a>(
refs: &WgpuResourceRefs<'a>,
color_attachment: &RenderPassColorAttachment,
) -> wgpu::RenderPassColorAttachment<'a> {
let view = get_texture_view(
refs,
&color_attachment.attachment,
);
let view = get_texture_view(refs, &color_attachment.attachment);
let resolve_target = color_attachment
.resolve_target
@ -246,10 +269,7 @@ fn create_wgpu_depth_stencil_attachment<'a>(
refs: &WgpuResourceRefs<'a>,
depth_stencil_attachment: &RenderPassDepthStencilAttachment,
) -> wgpu::RenderPassDepthStencilAttachment<'a> {
let view = get_texture_view(
refs,
&depth_stencil_attachment.attachment,
);
let view = get_texture_view(refs, &depth_stencil_attachment.attachment);
wgpu::RenderPassDepthStencilAttachment {
view,

View file

@ -4,8 +4,8 @@ use crate::{
};
use bevy_render2::{
pipeline::{
BindGroupDescriptor, BindGroupDescriptorId, BindingShaderStage, PipelineDescriptor,
PipelineId,
BindGroupDescriptor, BindGroupDescriptorId, BindingShaderStage, ComputePipelineDescriptor,
PipelineDescriptor, PipelineId,
},
render_resource::{
BindGroup, BufferId, BufferInfo, BufferMapMode, RenderResourceBinding, SamplerId,
@ -483,6 +483,52 @@ impl RenderResourceContext for WgpuRenderResourceContext {
id
}
fn create_compute_pipeline(
&self,
pipeline_descriptor: &ComputePipelineDescriptor,
) -> PipelineId {
let layout = &pipeline_descriptor.layout;
for bind_group_descriptor in layout.bind_groups.iter() {
self.create_bind_group_layout(&bind_group_descriptor);
}
let bind_group_layouts = self.resources.bind_group_layouts.read();
// setup and collect bind group layouts
let bind_group_layouts = layout
.bind_groups
.iter()
.map(|bind_group| bind_group_layouts.get(&bind_group.id).unwrap())
.collect::<Vec<&wgpu::BindGroupLayout>>();
let pipeline_layout = self
.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
bind_group_layouts: bind_group_layouts.as_slice(),
push_constant_ranges: &[],
});
let shader_modules = self.resources.shader_modules.read();
let compute_shader_module = shader_modules
.get(&pipeline_descriptor.shader_stages.compute)
.unwrap();
let compute_pipeline_descriptor = wgpu::ComputePipelineDescriptor {
label: None,
layout: Some(&pipeline_layout),
entry_point: "main",
module: compute_shader_module,
};
let compute_pipeline = self
.device
.create_compute_pipeline(&compute_pipeline_descriptor);
let mut compute_pipelines = self.resources.compute_pipelines.write();
let id = PipelineId::new();
compute_pipelines.insert(id, compute_pipeline);
id
}
fn bind_group_descriptor_exists(
&self,
bind_group_descriptor_id: BindGroupDescriptorId,

View file

@ -48,6 +48,7 @@ pub struct WgpuResourcesReadLock<'a> {
pub textures: RwLockReadGuard<'a, HashMap<TextureId, wgpu::TextureView>>,
pub swap_chain_frames: RwLockReadGuard<'a, HashMap<TextureId, wgpu::SwapChainFrame>>,
pub render_pipelines: RwLockReadGuard<'a, HashMap<PipelineId, wgpu::RenderPipeline>>,
pub compute_pipelines: RwLockReadGuard<'a, HashMap<PipelineId, wgpu::ComputePipeline>>,
pub bind_groups: RwLockReadGuard<'a, HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>>,
pub used_bind_group_sender: Sender<BindGroupId>,
}
@ -59,6 +60,7 @@ impl<'a> WgpuResourcesReadLock<'a> {
textures: &self.textures,
swap_chain_frames: &self.swap_chain_frames,
render_pipelines: &self.render_pipelines,
compute_pipelines: &self.compute_pipelines,
bind_groups: &self.bind_groups,
used_bind_group_sender: &self.used_bind_group_sender,
}
@ -73,6 +75,7 @@ pub struct WgpuResourceRefs<'a> {
pub textures: &'a HashMap<TextureId, wgpu::TextureView>,
pub swap_chain_frames: &'a HashMap<TextureId, wgpu::SwapChainFrame>,
pub render_pipelines: &'a HashMap<PipelineId, wgpu::RenderPipeline>,
pub compute_pipelines: &'a HashMap<PipelineId, wgpu::ComputePipeline>,
pub bind_groups: &'a HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>,
pub used_bind_group_sender: &'a Sender<BindGroupId>,
}
@ -90,6 +93,7 @@ pub struct WgpuResources {
pub samplers: Arc<RwLock<HashMap<SamplerId, wgpu::Sampler>>>,
pub shader_modules: Arc<RwLock<HashMap<ShaderId, wgpu::ShaderModule>>>,
pub render_pipelines: Arc<RwLock<HashMap<PipelineId, wgpu::RenderPipeline>>>,
pub compute_pipelines: Arc<RwLock<HashMap<PipelineId, wgpu::ComputePipeline>>>,
pub bind_groups: Arc<RwLock<HashMap<BindGroupDescriptorId, WgpuBindGroupInfo>>>,
pub bind_group_layouts: Arc<RwLock<HashMap<BindGroupDescriptorId, wgpu::BindGroupLayout>>>,
pub bind_group_counter: BindGroupCounter,
@ -102,6 +106,7 @@ impl WgpuResources {
textures: self.texture_views.read(),
swap_chain_frames: self.swap_chain_frames.read(),
render_pipelines: self.render_pipelines.read(),
compute_pipelines: self.compute_pipelines.read(),
bind_groups: self.bind_groups.read(),
used_bind_group_sender: self.bind_group_counter.used_bind_group_sender.clone(),
}