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> {
#[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(),

View file

@ -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>) {

View file

@ -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();

View file

@ -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| {
&current_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();
}
}
}

View file

@ -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();
}

View file

@ -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::*;

View file

@ -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)]

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 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();

View file

@ -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();
}
}

View file

@ -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,