render: move pipeline compilation and bind group creation into draw stage. impl ResourceSet for DrawContext. progress on text drawing. general cleanup

This commit is contained in:
Carter Anderson 2020-06-18 17:27:20 -07:00
parent 085cda8bc6
commit 4246d47fec
11 changed files with 334 additions and 363 deletions

View file

@ -33,7 +33,7 @@ impl<'a, T: 'a> Clone for Res<'a, T> {
impl<'a, T: 'a> Res<'a, T> { impl<'a, T: 'a> Res<'a, T> {
#[inline(always)] #[inline(always)]
fn new(resource: *const T) -> Self { pub fn new(resource: *const T) -> Self {
Self { Self {
value: resource, value: resource,
_marker: PhantomData::default(), _marker: PhantomData::default(),
@ -120,7 +120,7 @@ impl<'a, T: 'a> Clone for ResMut<'a, T> {
impl<'a, T: 'a> ResMut<'a, T> { impl<'a, T: 'a> ResMut<'a, T> {
#[inline(always)] #[inline(always)]
fn new(resource: *mut T) -> Self { pub fn new(resource: *mut T) -> Self {
Self { Self {
value: resource, value: resource,
_marker: PhantomData::default(), _marker: PhantomData::default(),

View file

@ -1,18 +1,25 @@
use crate::{ use crate::{
pipeline::{PipelineDescriptor, PipelineLayout}, pipeline::{
PipelineCompiler, PipelineDescriptor, PipelineLayout, PipelineSpecialization,
VertexBufferDescriptors,
},
render_resource::{ render_resource::{
AssetRenderResourceBindings, BindGroup, BindGroupId, BufferId, BufferUsage, RenderResource, AssetRenderResourceBindings, BindGroup, BindGroupId, BufferId, BufferUsage, RenderResource,
RenderResourceBinding, RenderResourceBindings, SharedBuffers, RenderResourceBinding, RenderResourceBindings, SharedBuffers,
}, },
renderer::RenderResourceContext, renderer::RenderResourceContext,
shader::Shader,
}; };
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_property::Properties; use bevy_property::Properties;
use legion::{ use legion::{
prelude::{ComMut, Res}, prelude::{ComMut, Res, ResourceSet},
storage::Component, systems::{resource::ResourceTypeId, ResMut},
};
use std::{
ops::{Deref, DerefMut, Range},
sync::Arc,
}; };
use std::{ops::Range, sync::Arc};
use thiserror::Error; use thiserror::Error;
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
@ -58,84 +65,12 @@ impl Default for Draw {
} }
impl Draw { impl Draw {
pub fn get_context<'a>(
&'a mut self,
pipelines: &'a Assets<PipelineDescriptor>,
render_resource_context: &'a dyn RenderResourceContext,
render_resource_bindings: &'a RenderResourceBindings,
asset_render_resource_bindings: &'a AssetRenderResourceBindings,
shared_buffers: &'a SharedBuffers,
) -> DrawContext {
DrawContext {
draw: self,
pipelines,
render_resource_context,
render_resource_bindings,
asset_render_resource_bindings,
shared_buffers,
current_pipeline: None,
}
}
pub fn clear_render_commands(&mut self) { pub fn clear_render_commands(&mut self) {
self.render_commands.clear(); self.render_commands.clear();
} }
}
#[derive(Debug, Error)] pub fn set_pipeline(&mut self, pipeline: Handle<PipelineDescriptor>) {
pub enum DrawError { self.render_command(RenderCommand::SetPipeline { pipeline });
#[error("Pipeline does not exist.")]
NonExistentPipeline,
#[error("No pipeline set")]
NoPipelineSet,
#[error("Pipeline has no layout")]
PipelineHasNoLayout,
#[error("A BindGroup with the given index does not exist")]
BindGroupDescriptorDoesNotExist { index: u32 },
#[error("Failed to get a buffer for the given RenderResource.")]
BufferAllocationFailure,
}
pub struct DrawContext<'a> {
pub draw: &'a mut Draw,
pub pipelines: &'a Assets<PipelineDescriptor>,
pub render_resource_context: &'a dyn RenderResourceContext,
pub render_resource_bindings: &'a RenderResourceBindings,
pub asset_render_resource_bindings: &'a AssetRenderResourceBindings,
pub shared_buffers: &'a SharedBuffers,
pub current_pipeline: Option<&'a PipelineDescriptor>,
}
impl<'a> DrawContext<'a> {
pub fn get_uniform_buffer<T: RenderResource>(
&self,
render_resource: &T,
) -> Result<RenderResourceBinding, DrawError> {
self.get_buffer(render_resource, BufferUsage::UNIFORM)
}
pub fn get_buffer<T: RenderResource>(
&self,
render_resource: &T,
buffer_usage: BufferUsage,
) -> Result<RenderResourceBinding, DrawError> {
self.shared_buffers
.get_buffer(render_resource, buffer_usage)
.ok_or_else(|| DrawError::BufferAllocationFailure)
}
pub fn set_pipeline(
&mut self,
pipeline_handle: Handle<PipelineDescriptor>,
) -> Result<(), DrawError> {
let pipeline = self
.pipelines
.get(&pipeline_handle)
.ok_or_else(|| DrawError::NonExistentPipeline)?;
self.current_pipeline = Some(pipeline);
self.render_command(RenderCommand::SetPipeline {
pipeline: pipeline_handle,
});
Ok(())
} }
pub fn set_vertex_buffer(&mut self, slot: u32, buffer: BufferId, offset: u64) { pub fn set_vertex_buffer(&mut self, slot: u32, buffer: BufferId, offset: u64) {
@ -166,8 +101,139 @@ impl<'a> DrawContext<'a> {
}); });
} }
#[inline]
pub fn render_command(&mut self, render_command: RenderCommand) {
self.render_commands.push(render_command);
}
}
#[derive(Debug, Error)]
pub enum DrawError {
#[error("Pipeline does not exist.")]
NonExistentPipeline,
#[error("No pipeline set")]
NoPipelineSet,
#[error("Pipeline has no layout")]
PipelineHasNoLayout,
#[error("Failed to get a buffer for the given RenderResource.")]
BufferAllocationFailure,
}
#[derive(Clone)]
pub struct DrawContext<'a> {
pub pipelines: ResMut<'a, Assets<PipelineDescriptor>>,
pub shaders: ResMut<'a, Assets<Shader>>,
pub pipeline_compiler: ResMut<'a, PipelineCompiler>,
pub render_resource_context: Res<'a, Box<dyn RenderResourceContext>>,
pub vertex_buffer_descriptors: Res<'a, VertexBufferDescriptors>,
pub asset_render_resource_bindings: Res<'a, AssetRenderResourceBindings>,
pub shared_buffers: Res<'a, SharedBuffers>,
pub current_pipeline: Option<Handle<PipelineDescriptor>>,
}
impl<'a> ResourceSet for DrawContext<'a> {
type PreparedResources = DrawContext<'a>;
unsafe fn fetch_unchecked(resources: &legion::prelude::Resources) -> Self::PreparedResources {
DrawContext {
render_resource_context: Res::new(
resources
.get::<Box<dyn RenderResourceContext>>()
.unwrap()
.deref() as *const Box<dyn RenderResourceContext>,
),
vertex_buffer_descriptors: Res::new(
resources.get::<VertexBufferDescriptors>().unwrap().deref()
as *const VertexBufferDescriptors,
),
asset_render_resource_bindings: Res::new(
resources
.get::<AssetRenderResourceBindings>()
.unwrap()
.deref() as *const AssetRenderResourceBindings,
),
shared_buffers: Res::new(
resources.get::<SharedBuffers>().unwrap().deref() as *const SharedBuffers
),
pipelines: ResMut::new(
resources
.get_mut::<Assets<PipelineDescriptor>>()
.unwrap()
.deref_mut() as *mut Assets<PipelineDescriptor>,
),
shaders: ResMut::new(
resources.get_mut::<Assets<Shader>>().unwrap().deref_mut() as *mut Assets<Shader>
),
pipeline_compiler: ResMut::new(
resources.get_mut::<PipelineCompiler>().unwrap().deref_mut()
as *mut PipelineCompiler,
),
current_pipeline: None,
}
}
fn read_types() -> Vec<legion::systems::resource::ResourceTypeId> {
vec![
ResourceTypeId::of::<Box<dyn RenderResourceContext>>(),
ResourceTypeId::of::<VertexBufferDescriptors>(),
ResourceTypeId::of::<AssetRenderResourceBindings>(),
ResourceTypeId::of::<SharedBuffers>(),
]
}
fn write_types() -> Vec<legion::systems::resource::ResourceTypeId> {
vec![
ResourceTypeId::of::<Assets<PipelineDescriptor>>(),
ResourceTypeId::of::<Assets<Shader>>(),
ResourceTypeId::of::<PipelineCompiler>(),
]
}
}
impl<'a> DrawContext<'a> {
pub fn get_uniform_buffer<T: RenderResource>(
&self,
render_resource: &T,
) -> Result<RenderResourceBinding, DrawError> {
self.get_buffer(render_resource, BufferUsage::UNIFORM)
}
pub fn get_buffer<T: RenderResource>(
&self,
render_resource: &T,
buffer_usage: BufferUsage,
) -> Result<RenderResourceBinding, DrawError> {
self.shared_buffers
.get_buffer(render_resource, buffer_usage)
.ok_or_else(|| DrawError::BufferAllocationFailure)
}
pub fn set_pipeline(
&mut self,
draw: &mut Draw,
pipeline_handle: Handle<PipelineDescriptor>,
specialization: &PipelineSpecialization,
) -> Result<(), DrawError> {
let specialized_pipeline = if let Some(specialized_pipeline) = self
.pipeline_compiler
.get_specialized_pipeline(pipeline_handle, specialization)
{
specialized_pipeline
} else {
self.pipeline_compiler.compile_pipeline(
&**self.render_resource_context,
&mut self.pipelines,
&mut self.shaders,
pipeline_handle,
&self.vertex_buffer_descriptors,
specialization,
)
};
draw.set_pipeline(specialized_pipeline);
self.current_pipeline = Some(specialized_pipeline);
Ok(())
}
pub fn get_pipeline_descriptor(&self) -> Result<&PipelineDescriptor, DrawError> { pub fn get_pipeline_descriptor(&self) -> Result<&PipelineDescriptor, DrawError> {
self.current_pipeline self.current_pipeline
.and_then(|handle| self.pipelines.get(&handle))
.ok_or_else(|| DrawError::NoPipelineSet) .ok_or_else(|| DrawError::NoPipelineSet)
} }
@ -180,57 +246,82 @@ impl<'a> DrawContext<'a> {
} }
pub fn set_bind_groups_from_bindings( pub fn set_bind_groups_from_bindings(
&mut self, &self,
render_resource_bindings: &RenderResourceBindings, draw: &mut Draw,
render_resource_bindings: &mut [&mut RenderResourceBindings],
) -> Result<(), DrawError> { ) -> Result<(), DrawError> {
let pipeline = self let pipeline = self
.current_pipeline .current_pipeline
.ok_or_else(|| DrawError::NoPipelineSet)?; .ok_or_else(|| DrawError::NoPipelineSet)?;
let layout = pipeline let pipeline_descriptor = self
.pipelines
.get(&pipeline)
.ok_or_else(|| DrawError::NonExistentPipeline)?;
let layout = pipeline_descriptor
.get_layout() .get_layout()
.ok_or_else(|| DrawError::PipelineHasNoLayout)?; .ok_or_else(|| DrawError::PipelineHasNoLayout)?;
for bindings in render_resource_bindings.iter_mut() {
bindings.update_bind_groups(pipeline_descriptor, &**self.render_resource_context);
}
for bind_group_descriptor in layout.bind_groups.iter() { for bind_group_descriptor in layout.bind_groups.iter() {
if let Some(local_bind_group) = for bindings in render_resource_bindings.iter_mut() {
render_resource_bindings.get_descriptor_bind_group(bind_group_descriptor.id) if let Some(bind_group) =
bindings.get_descriptor_bind_group(bind_group_descriptor.id)
{ {
self.set_bind_group(bind_group_descriptor.index, local_bind_group); draw.set_bind_group(bind_group_descriptor.index, bind_group);
break;
}
} }
} }
Ok(()) Ok(())
} }
#[inline] pub fn set_vertex_buffers_from_bindings(
pub fn render_command(&mut self, render_command: RenderCommand) { &self,
self.draw.render_commands.push(render_command); draw: &mut Draw,
render_resource_bindings: &[&RenderResourceBindings],
) -> Result<Option<Range<u32>>, DrawError> {
let mut indices = None;
let pipeline = self
.current_pipeline
.ok_or_else(|| DrawError::NoPipelineSet)?;
let pipeline_descriptor = self
.pipelines
.get(&pipeline)
.ok_or_else(|| DrawError::NonExistentPipeline)?;
let layout = pipeline_descriptor
.get_layout()
.ok_or_else(|| DrawError::PipelineHasNoLayout)?;
for (slot, vertex_buffer_descriptor) in layout.vertex_buffer_descriptors.iter().enumerate()
{
for bindings in render_resource_bindings.iter() {
if let Some((vertex_buffer, index_buffer)) =
bindings.get_vertex_buffer(&vertex_buffer_descriptor.name)
{
draw.set_vertex_buffer(slot as u32, vertex_buffer, 0);
if let Some(index_buffer) = index_buffer {
if let Some(buffer_info) =
self.render_resource_context.get_buffer_info(index_buffer)
{
indices = Some(0..(buffer_info.size / 2) as u32);
} else {
panic!("expected buffer type");
}
draw.set_index_buffer(index_buffer, 0);
} }
pub fn draw<T: Drawable>(&mut self, drawable: &mut T) -> Result<(), DrawError> { break;
drawable.draw(self) }
}
}
Ok(indices)
} }
} }
pub trait Drawable { pub trait Drawable {
fn draw(&mut self, draw: &mut DrawContext) -> Result<(), DrawError>; fn draw(&mut self, draw: &mut Draw, context: &mut DrawContext) -> Result<(), DrawError>;
}
pub fn draw_system<T: Drawable + Component>(
pipelines: Res<Assets<PipelineDescriptor>>,
render_resource_bindings: Res<RenderResourceBindings>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
asset_render_resource_bindings: Res<AssetRenderResourceBindings>,
shared_buffers: Res<SharedBuffers>,
mut draw: ComMut<Draw>,
mut drawable: ComMut<T>,
) {
let mut draw_context = draw.get_context(
&pipelines,
&**render_resource_context,
&render_resource_bindings,
&asset_render_resource_bindings,
&shared_buffers,
);
draw_context.draw(drawable.as_mut()).unwrap();
} }
pub fn clear_draw_system(mut draw: ComMut<Draw>) { pub fn clear_draw_system(mut draw: ComMut<Draw>) {

View file

@ -35,12 +35,12 @@ use base_render_graph::{BaseRenderGraphBuilder, BaseRenderGraphConfig};
use bevy_app::{AppBuilder, AppPlugin}; use bevy_app::{AppBuilder, AppPlugin};
use bevy_asset::AddAsset; use bevy_asset::AddAsset;
use bevy_type_registry::RegisterType; use bevy_type_registry::RegisterType;
use draw::{clear_draw_system, draw_system, Draw}; use draw::{clear_draw_system, Draw};
use legion::prelude::IntoSystem; use legion::prelude::IntoSystem;
use mesh::mesh_resource_provider_system; use mesh::mesh_resource_provider_system;
use pipeline::{compile_pipelines_system, RenderPipelines}; use pipeline::{draw_render_pipelines_system, RenderPipelines};
use render_graph::{system::render_graph_schedule_executor_system, RenderGraph}; use render_graph::{system::render_graph_schedule_executor_system, RenderGraph};
use render_resource::{bind_groups_system, AssetRenderResourceBindings}; use render_resource::AssetRenderResourceBindings;
use std::ops::Range; use std::ops::Range;
use texture::{PngTextureLoader, TextureResourceSystemState}; use texture::{PngTextureLoader, TextureResourceSystemState};
@ -112,12 +112,7 @@ impl AppPlugin for RenderPlugin {
stage::RENDER_GRAPH_SYSTEMS, stage::RENDER_GRAPH_SYSTEMS,
render_graph_schedule_executor_system, render_graph_schedule_executor_system,
) )
.add_system_to_stage( .add_system_to_stage(stage::DRAW, draw_render_pipelines_system.system());
stage::RENDER_GRAPH_SYSTEMS,
compile_pipelines_system.system(),
)
.add_system_to_stage(stage::RENDER_GRAPH_SYSTEMS, bind_groups_system.system())
.add_system_to_stage(stage::DRAW, draw_system::<RenderPipelines>.system());
if let Some(ref config) = self.base_render_graph_config { if let Some(ref config) = self.base_render_graph_config {
let resources = app.resources(); let resources = app.resources();

View file

@ -1,15 +1,11 @@
use super::{ use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors};
state_descriptors::PrimitiveTopology, PipelineDescriptor, RenderPipelines,
VertexBufferDescriptors,
};
use crate::{ use crate::{
renderer::RenderResourceContext, renderer::RenderResourceContext,
shader::{Shader, ShaderSource}, shader::{Shader, ShaderSource},
}; };
use bevy_asset::{Assets, Handle, AssetEvent}; use bevy_asset::{Assets, Handle};
use legion::prelude::*; use once_cell::sync::Lazy;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use bevy_app::Events;
#[derive(Clone, Eq, PartialEq, Debug, Default)] #[derive(Clone, Eq, PartialEq, Debug, Default)]
pub struct PipelineSpecialization { pub struct PipelineSpecialization {
@ -18,6 +14,14 @@ pub struct PipelineSpecialization {
pub dynamic_bindings: Vec<DynamicBinding>, pub dynamic_bindings: Vec<DynamicBinding>,
} }
impl PipelineSpecialization {
pub fn empty() -> &'static PipelineSpecialization {
pub static EMPTY: Lazy<PipelineSpecialization> =
Lazy::new(|| PipelineSpecialization::default());
&EMPTY
}
}
#[derive(Clone, Eq, PartialEq, Debug, Default)] #[derive(Clone, Eq, PartialEq, Debug, Default)]
pub struct ShaderSpecialization { pub struct ShaderSpecialization {
pub shader_defs: HashSet<String>, pub shader_defs: HashSet<String>,
@ -90,7 +94,24 @@ impl PipelineCompiler {
} }
} }
fn compile_pipeline( pub fn get_specialized_pipeline(
&self,
pipeline: Handle<PipelineDescriptor>,
specialization: &PipelineSpecialization,
) -> Option<Handle<PipelineDescriptor>> {
self.specialized_pipelines
.get(&pipeline)
.and_then(|specialized_pipelines| {
specialized_pipelines
.iter()
.find(|current_specialized_pipeline| {
&current_specialized_pipeline.specialization == specialization
})
})
.map(|specialized_pipeline| specialized_pipeline.pipeline)
}
pub fn compile_pipeline(
&mut self, &mut self,
render_resource_context: &dyn RenderResourceContext, render_resource_context: &dyn RenderResourceContext,
pipelines: &mut Assets<PipelineDescriptor>, pipelines: &mut Assets<PipelineDescriptor>,
@ -152,48 +173,16 @@ impl PipelineCompiler {
specialized_pipeline_handle specialized_pipeline_handle
} }
fn compile_render_pipelines(
&mut self,
vertex_buffer_descriptors: &VertexBufferDescriptors,
pipelines: &mut Assets<PipelineDescriptor>,
shaders: &mut Assets<Shader>,
render_pipelines: &mut RenderPipelines,
render_resource_context: &dyn RenderResourceContext,
) {
for render_pipeline in render_pipelines.pipelines.iter_mut() {
let source_pipeline = render_pipeline.pipeline;
let compiled_pipeline_handle = if let Some(specialized_pipeline) =
self.specialized_pipelines
.get_mut(&source_pipeline)
.and_then(|specialized_pipelines| {
specialized_pipelines.iter().find(
|current_specialized_pipeline| {
current_specialized_pipeline.specialization == render_pipeline.specialization
},
)
}) {
specialized_pipeline.pipeline
} else {
self.compile_pipeline(
render_resource_context,
pipelines,
shaders,
source_pipeline,
vertex_buffer_descriptors,
&render_pipeline.specialization,
)
};
render_pipeline.specialized_pipeline = Some(compiled_pipeline_handle);
}
}
pub fn iter_compiled_pipelines( pub fn iter_compiled_pipelines(
&self, &self,
pipeline_handle: Handle<PipelineDescriptor>, pipeline_handle: Handle<PipelineDescriptor>,
) -> Option<impl Iterator<Item = &Handle<PipelineDescriptor>>> { ) -> Option<impl Iterator<Item = &Handle<PipelineDescriptor>>> {
if let Some(compiled_pipelines) = self.specialized_pipelines.get(&pipeline_handle) { if let Some(compiled_pipelines) = self.specialized_pipelines.get(&pipeline_handle) {
Some(compiled_pipelines.iter().map(|specialized_pipeline| &specialized_pipeline.pipeline)) Some(
compiled_pipelines
.iter()
.map(|specialized_pipeline| &specialized_pipeline.pipeline),
)
} else { } else {
None None
} }
@ -210,65 +199,3 @@ impl PipelineCompiler {
.flatten() .flatten()
} }
} }
// TODO: make this a system
pub fn compile_pipelines_system(
world: &mut SubWorld,
mut pipeline_compiler: ResMut<PipelineCompiler>,
mut shaders: ResMut<Assets<Shader>>,
mut pipelines: ResMut<Assets<PipelineDescriptor>>,
_pipeline_asset_events: Res<Events<AssetEvent<PipelineDescriptor>>>,
vertex_buffer_descriptors: Res<VertexBufferDescriptors>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
query: &mut Query<Write<RenderPipelines>>,
) {
let render_resource_context = &**render_resource_context;
// NOTE: this intentionally only handles events that happened prior to this system during this frame. this results in
// "new specialized pipeline" events being ignored.
// let default_specialization = PipelineSpecialization::default();
// for event in pipeline_asset_events.iter_current_update_events() {
// let handle_to_compile = match event {
// AssetEvent::Created { handle } => Some(*handle),
// AssetEvent::Modified { handle } => {
// // TODO: clean up old pipelines
// Some(*handle)
// }
// AssetEvent::Removed { .. } => {
// // TODO: clean up old pipelines
// None
// }
// };
// if let Some(handle_to_compile) = handle_to_compile {
// // TODO: try updating specialization here.
// pipeline_compiler.compile_pipeline(
// render_resource_context,
// &mut pipelines,
// &mut shaders,
// handle_to_compile,
// &vertex_buffer_descriptors,
// &default_specialization,
// );
// }
// }
// TODO: only update when RenderPipelines is changed
for mut render_pipelines in query.iter_mut(world) {
pipeline_compiler.compile_render_pipelines(
&vertex_buffer_descriptors,
&mut pipelines,
&mut shaders,
&mut render_pipelines,
render_resource_context,
);
// reset shader_defs so they can be changed next frame
for render_pipeline in render_pipelines.pipelines.iter_mut() {
render_pipeline
.specialization
.shader_specialization
.shader_defs
.clear();
}
}
}

View file

@ -1,16 +1,15 @@
use super::{PipelineDescriptor, PipelineSpecialization}; use super::{PipelineDescriptor, PipelineSpecialization};
use crate::{ use crate::{
draw::{DrawContext, DrawError, Drawable}, draw::{Draw, DrawContext, DrawError, Drawable},
render_resource::RenderResourceBindings, render_resource::RenderResourceBindings,
}; };
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_property::Properties; use bevy_property::Properties;
use legion::{prelude::ComMut, systems::ResMut};
#[derive(Properties, Default, Clone)] #[derive(Properties, Default, Clone)]
pub struct RenderPipeline { pub struct RenderPipeline {
pub pipeline: Handle<PipelineDescriptor>, pub pipeline: Handle<PipelineDescriptor>,
#[property(ignore)] #[property(ignore)]
pub specialized_pipeline: Option<Handle<PipelineDescriptor>>,
#[property(ignore)]
pub specialization: PipelineSpecialization, pub specialization: PipelineSpecialization,
} }
@ -22,7 +21,10 @@ impl RenderPipeline {
} }
} }
pub fn specialized(pipeline: Handle<PipelineDescriptor>, specialization: PipelineSpecialization) -> Self { pub fn specialized(
pipeline: Handle<PipelineDescriptor>,
specialization: PipelineSpecialization,
) -> Self {
RenderPipeline { RenderPipeline {
pipeline, pipeline,
specialization, specialization,
@ -68,55 +70,46 @@ impl Default for RenderPipelines {
} }
} }
impl Drawable for RenderPipelines { pub struct DrawableRenderPipelines<'a> {
fn draw(&mut self, draw: &mut DrawContext) -> Result<(), DrawError> { pub render_pipelines: &'a mut RenderPipelines,
for render_pipeline in self.pipelines.iter() { pub render_resource_bindings: &'a mut RenderResourceBindings,
let specialized_handle = if let Some(handle) = render_pipeline.specialized_pipeline { }
handle
} else {
continue;
};
let pipeline = draw.pipelines.get(&specialized_handle).unwrap();
let layout = pipeline.get_layout().unwrap();
draw.set_pipeline(specialized_handle)?;
for bind_group_descriptor in layout.bind_groups.iter() {
if let Some(local_bind_group) = self
.bindings
.get_descriptor_bind_group(bind_group_descriptor.id)
{
draw.set_bind_group(bind_group_descriptor.index, local_bind_group);
} else if let Some(global_bind_group) = draw
.render_resource_bindings
.get_descriptor_bind_group(bind_group_descriptor.id)
{
draw.set_bind_group(bind_group_descriptor.index, global_bind_group);
}
}
let mut indices = 0..0;
for (slot, vertex_buffer_descriptor) in
layout.vertex_buffer_descriptors.iter().enumerate()
{
if let Some((vertex_buffer, index_buffer)) = self
.bindings
.get_vertex_buffer(&vertex_buffer_descriptor.name)
{
draw.set_vertex_buffer(slot as u32, vertex_buffer, 0);
if let Some(index_buffer) = index_buffer {
if let Some(buffer_info) =
draw.render_resource_context.get_buffer_info(index_buffer)
{
indices = 0..(buffer_info.size / 2) as u32;
} else {
panic!("expected buffer type");
}
draw.set_index_buffer(index_buffer, 0);
}
}
}
impl<'a> Drawable for DrawableRenderPipelines<'a> {
fn draw(&mut self, draw: &mut Draw, context: &mut DrawContext) -> Result<(), DrawError> {
for render_pipeline in self.render_pipelines.pipelines.iter() {
context.set_pipeline(
draw,
render_pipeline.pipeline,
&render_pipeline.specialization,
)?;
context.set_bind_groups_from_bindings(
draw,
&mut [
&mut self.render_pipelines.bindings,
self.render_resource_bindings,
],
)?;
let indices = context
.set_vertex_buffers_from_bindings(draw, &[&self.render_pipelines.bindings])?;
if let Some(indices) = indices {
draw.draw_indexed(indices, 0, 0..1); draw.draw_indexed(indices, 0, 0..1);
} }
}
Ok(()) Ok(())
} }
} }
pub fn draw_render_pipelines_system(
mut draw_context: DrawContext,
mut render_resource_bindings: ResMut<RenderResourceBindings>,
mut draw: ComMut<Draw>,
mut render_pipelines: ComMut<RenderPipelines>,
) {
let mut drawable = DrawableRenderPipelines {
render_pipelines: &mut render_pipelines,
render_resource_bindings: &mut render_resource_bindings,
};
drawable.draw(&mut draw, &mut draw_context).unwrap();
}

View file

@ -3,7 +3,6 @@ mod buffer;
mod render_resource; mod render_resource;
mod render_resource_bindings; mod render_resource_bindings;
mod shared_buffers; mod shared_buffers;
mod systems;
mod texture; mod texture;
pub use bind_group::*; pub use bind_group::*;
@ -11,5 +10,4 @@ pub use buffer::*;
pub use render_resource::*; pub use render_resource::*;
pub use render_resource_bindings::*; pub use render_resource_bindings::*;
pub use shared_buffers::*; pub use shared_buffers::*;
pub use systems::*;
pub use texture::*; pub use texture::*;

View file

@ -1,5 +1,8 @@
use super::{BindGroup, BindGroupId, BufferId, RenderResourceId, SamplerId, TextureId}; use super::{BindGroup, BindGroupId, BufferId, RenderResourceId, SamplerId, TextureId};
use crate::{renderer::RenderResourceContext, pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor}}; use crate::{
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor},
renderer::RenderResourceContext,
};
use bevy_asset::{Handle, HandleUntyped}; use bevy_asset::{Handle, HandleUntyped};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
@ -82,10 +85,8 @@ pub struct RenderResourceBindings {
// TODO: remove this // TODO: remove this
vertex_buffers: HashMap<String, (BufferId, Option<BufferId>)>, vertex_buffers: HashMap<String, (BufferId, Option<BufferId>)>,
bind_groups: HashMap<BindGroupId, BindGroup>, bind_groups: HashMap<BindGroupId, BindGroup>,
bind_group_descriptors: HashMap<BindGroupDescriptorId, BindGroupId>, bind_group_descriptors: HashMap<BindGroupDescriptorId, Option<BindGroupId>>,
dirty_bind_groups: HashSet<BindGroupId>, dirty_bind_groups: HashSet<BindGroupId>,
// TODO: remove this
// pub pipeline_specialization: PipelineSpecialization,
} }
impl RenderResourceBindings { impl RenderResourceBindings {
@ -139,7 +140,7 @@ impl RenderResourceBindings {
if let Some(bind_group) = bind_group { if let Some(bind_group) = bind_group {
let id = bind_group.id; let id = bind_group.id;
self.bind_groups.insert(id, bind_group); self.bind_groups.insert(id, bind_group);
self.bind_group_descriptors.insert(descriptor.id, id); self.bind_group_descriptors.insert(descriptor.id, Some(id));
BindGroupStatus::Changed(id) BindGroupStatus::Changed(id)
} else { } else {
BindGroupStatus::NoMatch BindGroupStatus::NoMatch
@ -151,18 +152,26 @@ impl RenderResourceBindings {
bind_group_descriptor: &BindGroupDescriptor, bind_group_descriptor: &BindGroupDescriptor,
) -> BindGroupStatus { ) -> BindGroupStatus {
if let Some(id) = self.bind_group_descriptors.get(&bind_group_descriptor.id) { if let Some(id) = self.bind_group_descriptors.get(&bind_group_descriptor.id) {
if let Some(id) = id {
if self.dirty_bind_groups.contains(id) { if self.dirty_bind_groups.contains(id) {
self.dirty_bind_groups.remove(id); self.dirty_bind_groups.remove(id);
self.create_bind_group(bind_group_descriptor) self.create_bind_group(bind_group_descriptor)
} else { } else {
BindGroupStatus::Unchanged(*id) BindGroupStatus::Unchanged(*id)
} }
} else {
BindGroupStatus::NoMatch
}
} else { } else {
self.create_bind_group(bind_group_descriptor) self.create_bind_group(bind_group_descriptor)
} }
} }
pub fn update_bind_groups(&mut self, pipeline: &PipelineDescriptor, render_resource_context: &dyn RenderResourceContext) { pub fn update_bind_groups(
&mut self,
pipeline: &PipelineDescriptor,
render_resource_context: &dyn RenderResourceContext,
) {
let layout = pipeline.get_layout().unwrap(); let layout = pipeline.get_layout().unwrap();
for bind_group_descriptor in layout.bind_groups.iter() { for bind_group_descriptor in layout.bind_groups.iter() {
match self.update_bind_group(bind_group_descriptor) { match self.update_bind_group(bind_group_descriptor) {
@ -195,7 +204,13 @@ impl RenderResourceBindings {
pub fn get_descriptor_bind_group(&self, id: BindGroupDescriptorId) -> Option<&BindGroup> { pub fn get_descriptor_bind_group(&self, id: BindGroupDescriptorId) -> Option<&BindGroup> {
self.bind_group_descriptors self.bind_group_descriptors
.get(&id) .get(&id)
.and_then(|bind_group_id| self.get_bind_group(*bind_group_id)) .and_then(|bind_group_id| {
if let Some(bind_group_id) = bind_group_id {
self.get_bind_group(*bind_group_id)
} else {
None
}
})
} }
fn build_bind_group(&self, bind_group_descriptor: &BindGroupDescriptor) -> Option<BindGroup> { fn build_bind_group(&self, bind_group_descriptor: &BindGroupDescriptor) -> Option<BindGroup> {
@ -228,6 +243,10 @@ impl AssetRenderResourceBindings {
.entry(HandleUntyped::from(handle)) .entry(HandleUntyped::from(handle))
.or_insert_with(|| RenderResourceBindings::default()) .or_insert_with(|| RenderResourceBindings::default())
} }
pub fn get_mut<T>(&mut self, handle: Handle<T>) -> Option<&mut RenderResourceBindings> {
self.bindings.get_mut(&HandleUntyped::from(handle))
}
} }
#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)] #[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]

View file

@ -1,31 +0,0 @@
use crate::{
pipeline::{PipelineCompiler, PipelineDescriptor, RenderPipelines},
render_resource::RenderResourceBindings,
renderer::RenderResourceContext,
};
use bevy_asset::Assets;
use legion::prelude::*;
pub fn bind_groups_system(
world: &mut SubWorld,
pipelines: Res<Assets<PipelineDescriptor>>,
pipeline_compiler: Res<PipelineCompiler>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
mut render_resource_bindings: ResMut<RenderResourceBindings>,
query: &mut Query<Write<RenderPipelines>>,
) {
let render_resource_context = &**render_resource_context;
for compiled_pipeline_handle in pipeline_compiler.iter_all_compiled_pipelines() {
let pipeline = pipelines.get(compiled_pipeline_handle).unwrap();
render_resource_bindings.update_bind_groups(pipeline, render_resource_context);
}
for mut render_pipelines in query.iter_mut(world) {
let render_pipelines = render_pipelines.as_mut();
for render_pipeline in render_pipelines.pipelines.iter_mut() {
let pipeline = pipelines
.get(&render_pipeline.specialized_pipeline.unwrap())
.unwrap();
render_pipelines.bindings.update_bind_groups(pipeline, render_resource_context);
}
}
}

View file

@ -1,10 +1,10 @@
use crate::{Font, FontAtlasSet}; use crate::{Font, FontAtlasSet};
use bevy_asset::Assets; use bevy_asset::Assets;
use bevy_render::{ use bevy_render::{
draw::{DrawContext, DrawError, Drawable}, draw::{DrawContext, DrawError, Drawable, Draw},
mesh, mesh,
render_resource::{BindGroup, BufferUsage, RenderResourceId}, render_resource::{BindGroup, BufferUsage, RenderResourceId},
Color, Color, pipeline::PipelineSpecialization,
}; };
use bevy_sprite::{TextureAtlas, TextureAtlasSprite}; use bevy_sprite::{TextureAtlas, TextureAtlasSprite};
use glam::{Vec2, Vec3}; use glam::{Vec2, Vec3};
@ -45,10 +45,9 @@ impl<'a> DrawableText<'a> {
} }
impl<'a> Drawable for DrawableText<'a> { impl<'a> Drawable for DrawableText<'a> {
fn draw(&mut self, draw: &mut DrawContext) -> Result<(), DrawError> { fn draw(&mut self, draw: &mut Draw, context: &mut DrawContext) -> Result<(), DrawError> {
draw.set_pipeline(bevy_sprite::SPRITE_SHEET_PIPELINE_HANDLE)?; context.set_pipeline(draw, bevy_sprite::SPRITE_SHEET_PIPELINE_HANDLE, PipelineSpecialization::empty())?;
let render_resource_context = draw.render_resource_context; let render_resource_context = &**context.render_resource_context;
// TODO: add draw.set_mesh(slot)
if let Some(RenderResourceId::Buffer(quad_vertex_buffer)) = render_resource_context if let Some(RenderResourceId::Buffer(quad_vertex_buffer)) = render_resource_context
.get_asset_resource(bevy_sprite::QUAD_HANDLE, mesh::VERTEX_BUFFER_ASSET_INDEX) .get_asset_resource(bevy_sprite::QUAD_HANDLE, mesh::VERTEX_BUFFER_ASSET_INDEX)
{ {
@ -59,8 +58,7 @@ impl<'a> Drawable for DrawableText<'a> {
.get_asset_resource(bevy_sprite::QUAD_HANDLE, mesh::INDEX_BUFFER_ASSET_INDEX) .get_asset_resource(bevy_sprite::QUAD_HANDLE, mesh::INDEX_BUFFER_ASSET_INDEX)
{ {
draw.set_index_buffer(quad_index_buffer, 0); draw.set_index_buffer(quad_index_buffer, 0);
if let Some(buffer_info) = draw if let Some(buffer_info) = render_resource_context
.render_resource_context
.get_buffer_info(quad_index_buffer) .get_buffer_info(quad_index_buffer)
{ {
indices = 0..(buffer_info.size / 2) as u32; indices = 0..(buffer_info.size / 2) as u32;
@ -70,7 +68,7 @@ impl<'a> Drawable for DrawableText<'a> {
} }
// set global bindings // set global bindings
draw.set_bind_groups_from_bindings(&draw.render_resource_bindings)?; // context.set_bind_groups_from_bindings(draw, &mut[context.render_resource_bindings])?;
// set local per-character bindings // set local per-character bindings
for character in self.text.chars() { for character in self.text.chars() {
@ -78,17 +76,17 @@ impl<'a> Drawable for DrawableText<'a> {
.font_atlas_set .font_atlas_set
.get_glyph_atlas_info(self.style.font_size, character) .get_glyph_atlas_info(self.style.font_size, character)
{ {
let atlas_render_resource_bindings = draw // let atlas_render_resource_bindings = context
.asset_render_resource_bindings // .asset_render_resource_bindings
.get(glyph_atlas_info.texture_atlas) // .get_mut(glyph_atlas_info.texture_atlas)
.unwrap(); // .unwrap();
draw.set_bind_groups_from_bindings(&atlas_render_resource_bindings)?; // context.set_bind_groups_from_bindings(draw, &mut[atlas_render_resource_bindings])?;
let sprite_buffer = TextureAtlasSprite { let sprite_buffer = TextureAtlasSprite {
index: glyph_atlas_info.char_index, index: glyph_atlas_info.char_index,
position: Vec3::new(300.0, 300.0, 0.0), position: Vec3::new(300.0, 300.0, 0.0),
scale: 5.0, scale: 5.0,
}; };
let sprite_buffer = draw let sprite_buffer = context
.shared_buffers .shared_buffers
.get_buffer(&sprite_buffer, BufferUsage::UNIFORM) .get_buffer(&sprite_buffer, BufferUsage::UNIFORM)
.unwrap(); .unwrap();

View file

@ -1,12 +1,5 @@
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_render::{ use bevy_render::{draw::{DrawContext, Draw}, texture::Texture, Color};
draw::Draw,
pipeline::PipelineDescriptor,
render_resource::{AssetRenderResourceBindings, RenderResourceBindings, SharedBuffers},
renderer::RenderResourceContext,
texture::Texture,
Color,
};
use bevy_sprite::{ColorMaterial, ComMut, Quad, TextureAtlas}; use bevy_sprite::{ColorMaterial, ComMut, Quad, TextureAtlas};
use bevy_text::{Font, FontAtlasSet, TextStyle}; use bevy_text::{Font, FontAtlasSet, TextStyle};
use legion::prelude::{Com, Res, ResMut}; use legion::prelude::{Com, Res, ResMut};
@ -78,11 +71,7 @@ impl Label {
} }
pub fn draw_label_system( pub fn draw_label_system(
_pipelines: Res<Assets<PipelineDescriptor>>, mut _draw_context: DrawContext,
_render_resource_bindings: Res<RenderResourceBindings>,
_asset_render_resource_bindings: Res<AssetRenderResourceBindings>,
_render_resource_context: Res<Box<dyn RenderResourceContext>>,
_shared_buffers: Res<SharedBuffers>,
_fonts: Res<Assets<Font>>, _fonts: Res<Assets<Font>>,
_font_atlas_sets: Res<Assets<FontAtlasSet>>, _font_atlas_sets: Res<Assets<FontAtlasSet>>,
_texture_atlases: Res<Assets<TextureAtlas>>, _texture_atlases: Res<Assets<TextureAtlas>>,
@ -90,23 +79,16 @@ impl Label {
_label: Com<Label>, _label: Com<Label>,
_quad: Com<Quad>, _quad: Com<Quad>,
) { ) {
// let mut draw_context = draw.get_context(
// &pipelines,
// &**render_resource_context,
// &render_resource_bindings,
// &asset_render_resource_bindings,
// &shared_buffers,
// );
// TODO: getting a font mutably will send out font change events. the atlas should be split from the font to avoid this
// let mut drawable_text = DrawableText::new( // let mut drawable_text = DrawableText::new(
// fonts.get(&label.font).unwrap(), // fonts.get(&label.font).unwrap(),
// font_atlas_sets.get(&label.font.as_handle::<FontAtlasSet>()).unwrap(), // font_atlas_sets
// .get(&label.font.as_handle::<FontAtlasSet>())
// .unwrap(),
// &texture_atlases, // &texture_atlases,
// quad.position, // quad.position,
// &label.style, // &label.style,
// &label.text, // &label.text,
// ); // );
// draw_context.draw(&mut drawable_text).unwrap(); // drawable_text.draw(&mut draw, &mut draw_context).unwrap();
} }
} }

View file

@ -27,7 +27,6 @@ fn setup(
mut textures: ResMut<Assets<Texture>>, mut textures: ResMut<Assets<Texture>>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>, mut texture_atlases: ResMut<Assets<TextureAtlas>>,
) { ) {
env_logger::init();
let texture_handle = asset_server let texture_handle = asset_server
.load_sync( .load_sync(
&mut textures, &mut textures,