mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 06:00:20 +00:00
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:
parent
085cda8bc6
commit
4246d47fec
11 changed files with 334 additions and 363 deletions
|
@ -33,7 +33,7 @@ impl<'a, T: 'a> Clone for Res<'a, T> {
|
|||
|
||||
impl<'a, T: 'a> Res<'a, T> {
|
||||
#[inline(always)]
|
||||
fn new(resource: *const T) -> Self {
|
||||
pub fn new(resource: *const T) -> Self {
|
||||
Self {
|
||||
value: resource,
|
||||
_marker: PhantomData::default(),
|
||||
|
@ -120,7 +120,7 @@ impl<'a, T: 'a> Clone for ResMut<'a, T> {
|
|||
|
||||
impl<'a, T: 'a> ResMut<'a, T> {
|
||||
#[inline(always)]
|
||||
fn new(resource: *mut T) -> Self {
|
||||
pub fn new(resource: *mut T) -> Self {
|
||||
Self {
|
||||
value: resource,
|
||||
_marker: PhantomData::default(),
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
use crate::{
|
||||
pipeline::{PipelineDescriptor, PipelineLayout},
|
||||
pipeline::{
|
||||
PipelineCompiler, PipelineDescriptor, PipelineLayout, PipelineSpecialization,
|
||||
VertexBufferDescriptors,
|
||||
},
|
||||
render_resource::{
|
||||
AssetRenderResourceBindings, BindGroup, BindGroupId, BufferId, BufferUsage, RenderResource,
|
||||
RenderResourceBinding, RenderResourceBindings, SharedBuffers,
|
||||
},
|
||||
renderer::RenderResourceContext,
|
||||
shader::Shader,
|
||||
};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_property::Properties;
|
||||
use legion::{
|
||||
prelude::{ComMut, Res},
|
||||
storage::Component,
|
||||
prelude::{ComMut, Res, ResourceSet},
|
||||
systems::{resource::ResourceTypeId, ResMut},
|
||||
};
|
||||
use std::{
|
||||
ops::{Deref, DerefMut, Range},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{ops::Range, sync::Arc};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
@ -58,84 +65,12 @@ impl Default for 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) {
|
||||
self.render_commands.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DrawError {
|
||||
#[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_pipeline(&mut self, pipeline: Handle<PipelineDescriptor>) {
|
||||
self.render_command(RenderCommand::SetPipeline { pipeline });
|
||||
}
|
||||
|
||||
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> {
|
||||
self.current_pipeline
|
||||
.and_then(|handle| self.pipelines.get(&handle))
|
||||
.ok_or_else(|| DrawError::NoPipelineSet)
|
||||
}
|
||||
|
||||
|
@ -180,57 +246,82 @@ impl<'a> DrawContext<'a> {
|
|||
}
|
||||
|
||||
pub fn set_bind_groups_from_bindings(
|
||||
&mut self,
|
||||
render_resource_bindings: &RenderResourceBindings,
|
||||
&self,
|
||||
draw: &mut Draw,
|
||||
render_resource_bindings: &mut [&mut RenderResourceBindings],
|
||||
) -> Result<(), DrawError> {
|
||||
let pipeline = self
|
||||
.current_pipeline
|
||||
.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()
|
||||
.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() {
|
||||
if let Some(local_bind_group) =
|
||||
render_resource_bindings.get_descriptor_bind_group(bind_group_descriptor.id)
|
||||
for bindings in render_resource_bindings.iter_mut() {
|
||||
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(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn render_command(&mut self, render_command: RenderCommand) {
|
||||
self.draw.render_commands.push(render_command);
|
||||
pub fn set_vertex_buffers_from_bindings(
|
||||
&self,
|
||||
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> {
|
||||
drawable.draw(self)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(indices)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Drawable {
|
||||
fn draw(&mut self, draw: &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();
|
||||
fn draw(&mut self, draw: &mut Draw, context: &mut DrawContext) -> Result<(), DrawError>;
|
||||
}
|
||||
|
||||
pub fn clear_draw_system(mut draw: ComMut<Draw>) {
|
||||
|
|
|
@ -35,12 +35,12 @@ use base_render_graph::{BaseRenderGraphBuilder, BaseRenderGraphConfig};
|
|||
use bevy_app::{AppBuilder, AppPlugin};
|
||||
use bevy_asset::AddAsset;
|
||||
use bevy_type_registry::RegisterType;
|
||||
use draw::{clear_draw_system, draw_system, Draw};
|
||||
use draw::{clear_draw_system, Draw};
|
||||
use legion::prelude::IntoSystem;
|
||||
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_resource::{bind_groups_system, AssetRenderResourceBindings};
|
||||
use render_resource::AssetRenderResourceBindings;
|
||||
use std::ops::Range;
|
||||
use texture::{PngTextureLoader, TextureResourceSystemState};
|
||||
|
||||
|
@ -112,12 +112,7 @@ impl AppPlugin for RenderPlugin {
|
|||
stage::RENDER_GRAPH_SYSTEMS,
|
||||
render_graph_schedule_executor_system,
|
||||
)
|
||||
.add_system_to_stage(
|
||||
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());
|
||||
.add_system_to_stage(stage::DRAW, draw_render_pipelines_system.system());
|
||||
|
||||
if let Some(ref config) = self.base_render_graph_config {
|
||||
let resources = app.resources();
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
use super::{
|
||||
state_descriptors::PrimitiveTopology, PipelineDescriptor, RenderPipelines,
|
||||
VertexBufferDescriptors,
|
||||
};
|
||||
use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors};
|
||||
use crate::{
|
||||
renderer::RenderResourceContext,
|
||||
shader::{Shader, ShaderSource},
|
||||
};
|
||||
use bevy_asset::{Assets, Handle, AssetEvent};
|
||||
use legion::prelude::*;
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use bevy_app::Events;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Default)]
|
||||
pub struct PipelineSpecialization {
|
||||
|
@ -18,6 +14,14 @@ pub struct PipelineSpecialization {
|
|||
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)]
|
||||
pub struct ShaderSpecialization {
|
||||
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| {
|
||||
¤t_specialized_pipeline.specialization == specialization
|
||||
})
|
||||
})
|
||||
.map(|specialized_pipeline| specialized_pipeline.pipeline)
|
||||
}
|
||||
|
||||
pub fn compile_pipeline(
|
||||
&mut self,
|
||||
render_resource_context: &dyn RenderResourceContext,
|
||||
pipelines: &mut Assets<PipelineDescriptor>,
|
||||
|
@ -152,48 +173,16 @@ impl PipelineCompiler {
|
|||
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(
|
||||
&self,
|
||||
pipeline_handle: Handle<PipelineDescriptor>,
|
||||
) -> Option<impl Iterator<Item = &Handle<PipelineDescriptor>>> {
|
||||
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 {
|
||||
None
|
||||
}
|
||||
|
@ -210,65 +199,3 @@ impl PipelineCompiler {
|
|||
.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
use super::{PipelineDescriptor, PipelineSpecialization};
|
||||
use crate::{
|
||||
draw::{DrawContext, DrawError, Drawable},
|
||||
draw::{Draw, DrawContext, DrawError, Drawable},
|
||||
render_resource::RenderResourceBindings,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
use bevy_property::Properties;
|
||||
use legion::{prelude::ComMut, systems::ResMut};
|
||||
#[derive(Properties, Default, Clone)]
|
||||
pub struct RenderPipeline {
|
||||
pub pipeline: Handle<PipelineDescriptor>,
|
||||
#[property(ignore)]
|
||||
pub specialized_pipeline: Option<Handle<PipelineDescriptor>>,
|
||||
#[property(ignore)]
|
||||
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 {
|
||||
pipeline,
|
||||
specialization,
|
||||
|
@ -68,55 +70,46 @@ impl Default for RenderPipelines {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drawable for RenderPipelines {
|
||||
fn draw(&mut self, draw: &mut DrawContext) -> Result<(), DrawError> {
|
||||
for render_pipeline in self.pipelines.iter() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct DrawableRenderPipelines<'a> {
|
||||
pub render_pipelines: &'a mut RenderPipelines,
|
||||
pub render_resource_bindings: &'a mut RenderResourceBindings,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ mod buffer;
|
|||
mod render_resource;
|
||||
mod render_resource_bindings;
|
||||
mod shared_buffers;
|
||||
mod systems;
|
||||
mod texture;
|
||||
|
||||
pub use bind_group::*;
|
||||
|
@ -11,5 +10,4 @@ pub use buffer::*;
|
|||
pub use render_resource::*;
|
||||
pub use render_resource_bindings::*;
|
||||
pub use shared_buffers::*;
|
||||
pub use systems::*;
|
||||
pub use texture::*;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
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 std::{
|
||||
collections::{HashMap, HashSet},
|
||||
|
@ -82,10 +85,8 @@ pub struct RenderResourceBindings {
|
|||
// TODO: remove this
|
||||
vertex_buffers: HashMap<String, (BufferId, Option<BufferId>)>,
|
||||
bind_groups: HashMap<BindGroupId, BindGroup>,
|
||||
bind_group_descriptors: HashMap<BindGroupDescriptorId, BindGroupId>,
|
||||
bind_group_descriptors: HashMap<BindGroupDescriptorId, Option<BindGroupId>>,
|
||||
dirty_bind_groups: HashSet<BindGroupId>,
|
||||
// TODO: remove this
|
||||
// pub pipeline_specialization: PipelineSpecialization,
|
||||
}
|
||||
|
||||
impl RenderResourceBindings {
|
||||
|
@ -139,7 +140,7 @@ impl RenderResourceBindings {
|
|||
if let Some(bind_group) = bind_group {
|
||||
let id = bind_group.id;
|
||||
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)
|
||||
} else {
|
||||
BindGroupStatus::NoMatch
|
||||
|
@ -151,18 +152,26 @@ impl RenderResourceBindings {
|
|||
bind_group_descriptor: &BindGroupDescriptor,
|
||||
) -> BindGroupStatus {
|
||||
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) {
|
||||
self.dirty_bind_groups.remove(id);
|
||||
self.create_bind_group(bind_group_descriptor)
|
||||
} else {
|
||||
BindGroupStatus::Unchanged(*id)
|
||||
}
|
||||
} else {
|
||||
BindGroupStatus::NoMatch
|
||||
}
|
||||
} else {
|
||||
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();
|
||||
for bind_group_descriptor in layout.bind_groups.iter() {
|
||||
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> {
|
||||
self.bind_group_descriptors
|
||||
.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> {
|
||||
|
@ -228,6 +243,10 @@ impl AssetRenderResourceBindings {
|
|||
.entry(HandleUntyped::from(handle))
|
||||
.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)]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
use crate::{Font, FontAtlasSet};
|
||||
use bevy_asset::Assets;
|
||||
use bevy_render::{
|
||||
draw::{DrawContext, DrawError, Drawable},
|
||||
draw::{DrawContext, DrawError, Drawable, Draw},
|
||||
mesh,
|
||||
render_resource::{BindGroup, BufferUsage, RenderResourceId},
|
||||
Color,
|
||||
Color, pipeline::PipelineSpecialization,
|
||||
};
|
||||
use bevy_sprite::{TextureAtlas, TextureAtlasSprite};
|
||||
use glam::{Vec2, Vec3};
|
||||
|
@ -45,10 +45,9 @@ impl<'a> DrawableText<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Drawable for DrawableText<'a> {
|
||||
fn draw(&mut self, draw: &mut DrawContext) -> Result<(), DrawError> {
|
||||
draw.set_pipeline(bevy_sprite::SPRITE_SHEET_PIPELINE_HANDLE)?;
|
||||
let render_resource_context = draw.render_resource_context;
|
||||
// TODO: add draw.set_mesh(slot)
|
||||
fn draw(&mut self, draw: &mut Draw, context: &mut DrawContext) -> Result<(), DrawError> {
|
||||
context.set_pipeline(draw, bevy_sprite::SPRITE_SHEET_PIPELINE_HANDLE, PipelineSpecialization::empty())?;
|
||||
let render_resource_context = &**context.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)
|
||||
{
|
||||
|
@ -59,8 +58,7 @@ impl<'a> Drawable for DrawableText<'a> {
|
|||
.get_asset_resource(bevy_sprite::QUAD_HANDLE, mesh::INDEX_BUFFER_ASSET_INDEX)
|
||||
{
|
||||
draw.set_index_buffer(quad_index_buffer, 0);
|
||||
if let Some(buffer_info) = draw
|
||||
.render_resource_context
|
||||
if let Some(buffer_info) = render_resource_context
|
||||
.get_buffer_info(quad_index_buffer)
|
||||
{
|
||||
indices = 0..(buffer_info.size / 2) as u32;
|
||||
|
@ -70,7 +68,7 @@ impl<'a> Drawable for DrawableText<'a> {
|
|||
}
|
||||
|
||||
// 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
|
||||
for character in self.text.chars() {
|
||||
|
@ -78,17 +76,17 @@ impl<'a> Drawable for DrawableText<'a> {
|
|||
.font_atlas_set
|
||||
.get_glyph_atlas_info(self.style.font_size, character)
|
||||
{
|
||||
let atlas_render_resource_bindings = draw
|
||||
.asset_render_resource_bindings
|
||||
.get(glyph_atlas_info.texture_atlas)
|
||||
.unwrap();
|
||||
draw.set_bind_groups_from_bindings(&atlas_render_resource_bindings)?;
|
||||
// let atlas_render_resource_bindings = context
|
||||
// .asset_render_resource_bindings
|
||||
// .get_mut(glyph_atlas_info.texture_atlas)
|
||||
// .unwrap();
|
||||
// context.set_bind_groups_from_bindings(draw, &mut[atlas_render_resource_bindings])?;
|
||||
let sprite_buffer = TextureAtlasSprite {
|
||||
index: glyph_atlas_info.char_index,
|
||||
position: Vec3::new(300.0, 300.0, 0.0),
|
||||
scale: 5.0,
|
||||
};
|
||||
let sprite_buffer = draw
|
||||
let sprite_buffer = context
|
||||
.shared_buffers
|
||||
.get_buffer(&sprite_buffer, BufferUsage::UNIFORM)
|
||||
.unwrap();
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_render::{
|
||||
draw::Draw,
|
||||
pipeline::PipelineDescriptor,
|
||||
render_resource::{AssetRenderResourceBindings, RenderResourceBindings, SharedBuffers},
|
||||
renderer::RenderResourceContext,
|
||||
texture::Texture,
|
||||
Color,
|
||||
};
|
||||
use bevy_render::{draw::{DrawContext, Draw}, texture::Texture, Color};
|
||||
use bevy_sprite::{ColorMaterial, ComMut, Quad, TextureAtlas};
|
||||
use bevy_text::{Font, FontAtlasSet, TextStyle};
|
||||
use legion::prelude::{Com, Res, ResMut};
|
||||
|
@ -78,11 +71,7 @@ impl Label {
|
|||
}
|
||||
|
||||
pub fn draw_label_system(
|
||||
_pipelines: Res<Assets<PipelineDescriptor>>,
|
||||
_render_resource_bindings: Res<RenderResourceBindings>,
|
||||
_asset_render_resource_bindings: Res<AssetRenderResourceBindings>,
|
||||
_render_resource_context: Res<Box<dyn RenderResourceContext>>,
|
||||
_shared_buffers: Res<SharedBuffers>,
|
||||
mut _draw_context: DrawContext,
|
||||
_fonts: Res<Assets<Font>>,
|
||||
_font_atlas_sets: Res<Assets<FontAtlasSet>>,
|
||||
_texture_atlases: Res<Assets<TextureAtlas>>,
|
||||
|
@ -90,23 +79,16 @@ impl Label {
|
|||
_label: Com<Label>,
|
||||
_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(
|
||||
// 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,
|
||||
// quad.position,
|
||||
// &label.style,
|
||||
// &label.text,
|
||||
// );
|
||||
// draw_context.draw(&mut drawable_text).unwrap();
|
||||
// drawable_text.draw(&mut draw, &mut draw_context).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ fn setup(
|
|||
mut textures: ResMut<Assets<Texture>>,
|
||||
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
|
||||
) {
|
||||
env_logger::init();
|
||||
let texture_handle = asset_server
|
||||
.load_sync(
|
||||
&mut textures,
|
||||
|
|
Loading…
Reference in a new issue