Make PipelineDescriptor an Asset that references Handle<Shader>

This commit is contained in:
Carter Anderson 2020-02-15 16:28:17 -08:00
parent 478d475219
commit 4de039eb71
17 changed files with 275 additions and 255 deletions

View file

@ -16,7 +16,7 @@ use crate::{
};
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
use render_graph_2::CompiledShaderMap;
use render_graph_2::{CompiledShaderMap, PipelineDescriptor};
use std::collections::HashMap;
pub struct AppBuilder {
@ -166,6 +166,7 @@ impl AppBuilder {
resources.insert(AssetStorage::<Mesh>::new());
resources.insert(AssetStorage::<Texture>::new());
resources.insert(AssetStorage::<Shader>::new());
resources.insert(AssetStorage::<PipelineDescriptor>::new());
resources.insert(ShaderAssignments::new());
resources.insert(CompiledShaderMap::new());
self
@ -181,6 +182,17 @@ impl AppBuilder {
}
pub fn add_render_graph_defaults(mut self) -> Self {
{
let mut pipeline_storage = self
.world
.resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let mut shader_storage = self
.world
.resources
.get_mut::<AssetStorage<Shader>>()
.unwrap();
self.render_graph_builder = self
.render_graph_builder
.add_resource_provider(Box::new(CameraResourceProvider))
@ -190,8 +202,9 @@ impl AppBuilder {
.add_resource_provider(Box::new(UniformResourceProvider::<StandardMaterial>::new()))
.add_resource_provider(Box::new(UniformResourceProvider::<LocalToWorld>::new()))
.add_forward_pass()
.add_forward_pipeline()
.add_ui_pipeline();
.add_forward_pipeline(&mut pipeline_storage, &mut shader_storage)
.add_ui_pipeline(&mut pipeline_storage, &mut shader_storage);
}
self
}

View file

@ -3,17 +3,31 @@ mod mesh;
mod texture;
pub use self::gltf::load_gltf;
use std::hash::{Hash, Hasher};
pub use mesh::*;
pub use texture::*;
use std::{collections::HashMap, marker::PhantomData};
#[derive(Hash, Eq, PartialEq)]
pub struct Handle<T> {
pub id: usize,
marker: PhantomData<T>,
}
impl<T> Hash for Handle<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl<T> PartialEq for Handle<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<T> Eq for Handle<T> {}
// TODO: somehow handle this gracefully in asset managers. or alternatively remove Default
impl<T> Default for Handle<T> {
fn default() -> Self {
@ -75,11 +89,19 @@ impl<T> AssetStorage<T> {
handle
}
pub fn get_id(&mut self, id: usize) -> Option<&mut T> {
pub fn get_id(&self, id: usize) -> Option<&T> {
self.assets.get(&id)
}
pub fn get_id_mut(&mut self, id: usize) -> Option<&mut T> {
self.assets.get_mut(&id)
}
pub fn get(&mut self, handle: &Handle<T>) -> Option<&mut T> {
pub fn get(&self, handle: &Handle<T>) -> Option<&T> {
self.assets.get(&handle.id)
}
pub fn get_mut(&mut self, handle: &Handle<T>) -> Option<&mut T> {
self.assets.get_mut(&handle.id)
}
}

View file

@ -157,7 +157,7 @@ impl Pipeline for ForwardPipeline {
}
if should_load_mesh {
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
if let Some(mesh_asset) = mesh_storage.get_id_mut(mesh.id) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);

View file

@ -285,7 +285,7 @@ impl Pipeline for ForwardInstancedPipeline {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
for instance_buffer_info in self.instance_buffer_infos.as_ref().unwrap().iter() {
if let Some(mesh_asset) = mesh_storage.get_id(instance_buffer_info.mesh_id) {
if let Some(mesh_asset) = mesh_storage.get_id_mut(instance_buffer_info.mesh_id) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);

View file

@ -176,7 +176,7 @@ impl Pipeline for ForwardShadowPassNew {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
for (material, mesh) in mesh_query.iter(world) {
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
if let Some(mesh_asset) = mesh_storage.get_id_mut(mesh.id) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);

View file

@ -166,7 +166,7 @@ impl Pipeline for ShadowPipeline {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
for (material, mesh) in mesh_query.iter(world) {
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
if let Some(mesh_asset) = mesh_storage.get_id_mut(mesh.id) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);

View file

@ -242,7 +242,7 @@ impl Pipeline for UiPipeline {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
for instance_buffer_info in instance_buffer_infos.as_ref().unwrap().iter() {
if let Some(mesh_asset) = mesh_storage.get_id(instance_buffer_info.mesh_id) {
if let Some(mesh_asset) = mesh_storage.get_id_mut(instance_buffer_info.mesh_id) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);

View file

@ -10,7 +10,7 @@ use crate::{
use zerocopy::AsBytes;
pub fn mesh_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut current_mesh_id = None;
let mut current_mesh_index_length = 0;
let mesh_query = <(Read<ShaderUniforms>, Read<Handle<Mesh>>, Read<Renderable>)>::query()

View file

@ -7,7 +7,7 @@ use crate::{
use zerocopy::AsBytes;
pub fn ui_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
// NOTE: this is ugly and borrowing is stupid
let result = {
let renderer = render_pass.get_renderer();

View file

@ -1,7 +1,7 @@
use crate::render::{
use crate::{asset::{AssetStorage, Handle}, render::{
render_graph_2::{BindGroup, DrawTarget, PipelineLayout},
shader::{Shader, ShaderStages},
};
}};
pub struct VertexBufferDescriptor {
pub stride: wgpu::BufferAddress,
@ -55,7 +55,7 @@ pub struct PipelineDescriptor {
}
impl PipelineDescriptor {
fn new(vertex_shader: Shader) -> Self {
fn new(vertex_shader: Handle<Shader>) -> Self {
PipelineDescriptor {
pipeline_layout: PipelineLayout::new(),
color_states: Vec::new(),
@ -80,19 +80,22 @@ impl PipelineDescriptor {
}
impl PipelineDescriptor {
pub fn build(vertex_shader: Shader) -> PipelineBuilder {
PipelineBuilder::new(vertex_shader)
pub fn build(shader_storage: &mut AssetStorage<Shader>, vertex_shader: Shader) -> PipelineBuilder {
PipelineBuilder::new(shader_storage, vertex_shader)
}
}
pub struct PipelineBuilder {
pub struct PipelineBuilder<'a> {
pipeline: PipelineDescriptor,
shader_storage: &'a mut AssetStorage<Shader>,
}
impl PipelineBuilder {
pub fn new(vertex_shader: Shader) -> Self {
impl<'a> PipelineBuilder<'a> {
pub fn new(shader_storage: &'a mut AssetStorage<Shader>, vertex_shader: Shader) -> Self {
let vertex_shader_handle = shader_storage.add(vertex_shader);
PipelineBuilder {
pipeline: PipelineDescriptor::new(vertex_shader),
pipeline: PipelineDescriptor::new(vertex_shader_handle),
shader_storage,
}
}
@ -101,7 +104,8 @@ impl PipelineBuilder {
}
pub fn with_fragment_shader(mut self, fragment_shader: Shader) -> Self {
self.pipeline.shader_stages.fragment = Some(fragment_shader);
let fragment_shader_handle = self.shader_storage.add(fragment_shader);
self.pipeline.shader_stages.fragment = Some(fragment_shader_handle);
self
}

View file

@ -1,22 +1,22 @@
use crate::render::{
use crate::{asset::AssetStorage, render::{
render_graph_2::{
draw_targets::mesh_draw_target, pipeline_layout::*, PipelineDescriptor, RenderGraphBuilder,
},
shader::{Shader, ShaderStage},
Vertex,
};
}};
pub trait ForwardPipelineBuilder {
fn add_forward_pipeline(self) -> Self;
fn add_forward_pipeline(self, pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, shader_storage: &mut AssetStorage<Shader>) -> Self;
}
impl ForwardPipelineBuilder for RenderGraphBuilder {
fn add_forward_pipeline(self) -> Self {
fn add_forward_pipeline(self, pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, shader_storage: &mut AssetStorage<Shader>) -> Self {
self.add_pipeline(
"forward",
PipelineDescriptor::build(Shader::from_glsl(
include_str!("forward.vert"),
ShaderStage::Vertex,
))
pipeline_descriptor_storage,
PipelineDescriptor::build(
shader_storage,
Shader::from_glsl(include_str!("forward.vert"), ShaderStage::Vertex),
)
.with_fragment_shader(Shader::from_glsl(
include_str!("forward.frag"),
ShaderStage::Fragment,

View file

@ -1,22 +1,35 @@
use crate::render::{
use crate::{
asset::AssetStorage,
render::{
render_graph_2::{
draw_targets::mesh_draw_target, pipeline_layout::*, PipelineDescriptor, RenderGraphBuilder,
draw_targets::mesh_draw_target, pipeline_layout::*, PipelineDescriptor,
RenderGraphBuilder,
},
shader::{Shader, ShaderStage},
Vertex,
},
};
pub trait ForwardFlatPipelineBuilder {
fn add_forward_flat_pipeline(self) -> Self;
fn add_forward_flat_pipeline(
self,
pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>,
shader_storage: &mut AssetStorage<Shader>,
) -> Self;
}
impl ForwardFlatPipelineBuilder for RenderGraphBuilder {
fn add_forward_flat_pipeline(self) -> Self {
fn add_forward_flat_pipeline(
self,
pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>,
shader_storage: &mut AssetStorage<Shader>,
) -> Self {
self.add_pipeline(
"forward_flat",
PipelineDescriptor::build(Shader::from_glsl(
include_str!("forward_flat.vert"),
ShaderStage::Vertex,
))
pipeline_descriptor_storage,
PipelineDescriptor::build(
shader_storage,
Shader::from_glsl(include_str!("forward_flat.vert"), ShaderStage::Vertex),
)
.with_fragment_shader(Shader::from_glsl(
include_str!("forward_flat.frag"),
ShaderStage::Fragment,

View file

@ -1,23 +1,34 @@
use crate::render::{
use crate::{
asset::AssetStorage,
render::{
render_graph_2::{
draw_targets::ui_draw_target, pipeline_layout::*, resource_providers::RectData,
PipelineDescriptor, RenderGraphBuilder, VertexBufferDescriptor,
},
shader::{Shader, ShaderStage},
Vertex,
},
};
pub trait UiPipelineBuilder {
fn add_ui_pipeline(self) -> Self;
fn add_ui_pipeline(
self,
pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>,
shader_storage: &mut AssetStorage<Shader>,
) -> Self;
}
impl UiPipelineBuilder for RenderGraphBuilder {
fn add_ui_pipeline(self) -> Self {
fn add_ui_pipeline(
self,
pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>,
shader_storage: &mut AssetStorage<Shader>,
) -> Self {
self.add_pipeline(
"ui",
PipelineDescriptor::build(Shader::from_glsl(
include_str!("ui.vert"),
ShaderStage::Vertex,
))
pipeline_descriptor_storage,
PipelineDescriptor::build(
shader_storage,
Shader::from_glsl(include_str!("ui.vert"), ShaderStage::Vertex),
)
.with_fragment_shader(Shader::from_glsl(
include_str!("ui.frag"),
ShaderStage::Fragment,

View file

@ -1,13 +1,16 @@
use crate::render::render_graph_2::{
PassDescriptor, PipelineDescriptor, ResourceProvider, TextureDescriptor,
use crate::{
asset::{AssetStorage, Handle},
render::{
render_graph_2::{PassDescriptor, PipelineDescriptor, ResourceProvider, TextureDescriptor},
},
};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
pub struct RenderGraph {
pub pipeline_descriptors: HashMap<String, PipelineDescriptor>,
pub pipeline_descriptors: HashSet<Handle<PipelineDescriptor>>,
// TODO: make this ordered
pub pass_descriptors: HashMap<String, PassDescriptor>,
pub pass_pipelines: HashMap<String, Vec<String>>,
pub pass_pipelines: HashMap<String, Vec<Handle<PipelineDescriptor>>>,
pub resource_providers: Vec<Box<dyn ResourceProvider>>,
pub queued_textures: Vec<(String, TextureDescriptor)>,
}
@ -15,7 +18,7 @@ pub struct RenderGraph {
impl Default for RenderGraph {
fn default() -> Self {
RenderGraph {
pipeline_descriptors: HashMap::new(),
pipeline_descriptors: HashSet::new(),
pass_descriptors: HashMap::new(),
pass_pipelines: HashMap::new(),
resource_providers: Vec::new(),
@ -24,9 +27,23 @@ impl Default for RenderGraph {
}
}
impl RenderGraph {
pub fn add_pipeline(&mut self, pass: &str, pipeline: Handle<PipelineDescriptor>) {
self.pipeline_descriptors.insert(pipeline.clone());
if let None = self.pass_pipelines.get(pass) {
self.pass_pipelines.insert(pass.to_string(), Vec::new());
}
let pass_pipelines = self.pass_pipelines.get_mut(pass).unwrap();
pass_pipelines.push(pipeline);
}
}
pub struct RenderGraphBuilder {
render_graph: RenderGraph,
current_pass: Option<String>,
}
impl RenderGraphBuilder {
@ -45,24 +62,10 @@ impl RenderGraphBuilder {
self
}
pub fn add_pipeline(mut self, name: &str, pipeline: PipelineDescriptor) -> Self {
self.render_graph
.pipeline_descriptors
.insert(name.to_string(), pipeline);
if let Some(current_pass) = self.current_pass.as_ref() {
if let None = self.render_graph.pass_pipelines.get(current_pass) {
self.render_graph
.pass_pipelines
.insert(current_pass.to_string(), Vec::new());
}
let pass_pipelines = self
.render_graph
.pass_pipelines
.get_mut(current_pass)
.unwrap();
pass_pipelines.push(name.to_string());
pub fn add_pipeline(mut self, pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, pipeline: PipelineDescriptor) -> Self {
if let Some(ref pass) = self.current_pass {
let pipeline_descriptor_handle = pipeline_descriptor_storage.add(pipeline);
self.render_graph.add_pipeline(&pass, pipeline_descriptor_handle);
}
self

View file

@ -1,13 +1,14 @@
use crate::{
asset::{AssetStorage, Handle},
render::{render_graph_2::RenderGraph, Shader},
render::{render_graph_2::RenderGraph, Shader, ShaderStages},
};
use legion::prelude::*;
use std::collections::{HashMap, HashSet};
use super::PipelineDescriptor;
pub struct Renderable {
pub is_visible: bool,
pub shaders: Vec<Handle<Shader>>,
pub pipelines: Vec<Handle<PipelineDescriptor>>,
pub shader_defs: HashSet<String>,
}
@ -15,7 +16,7 @@ impl Default for Renderable {
fn default() -> Self {
Renderable {
is_visible: true,
shaders: Vec::new(),
pipelines: Vec::new(),
shader_defs: HashSet::new(),
}
}
@ -53,20 +54,23 @@ pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGra
let shader_assignments = world.resources.get_mut::<ShaderAssignments>().unwrap();
let mut compiled_shader_map = world.resources.get_mut::<CompiledShaderMap>().unwrap();
let mut shader_storage = world.resources.get_mut::<AssetStorage<Shader>>().unwrap();
let pipeline_descriptor_storage = world.resources.get_mut::<AssetStorage<PipelineDescriptor>>().unwrap();
for (entity, renderable) in <Read<Renderable>>::query().iter_entities(world) {
for shader in renderable.shaders.iter() {
if let None = compiled_shader_map.source_to_compiled.get(shader) {
for pipeline_handle in renderable.pipelines.iter() {
let pipeline_descriptor = pipeline_descriptor_storage.get(pipeline_handle).unwrap();
for shader_handle in pipeline_descriptor.shader_stages.iter() {
if let None = compiled_shader_map.source_to_compiled.get(shader_handle) {
compiled_shader_map
.source_to_compiled
.insert(shader.clone(), Vec::new());
.insert(shader_handle.clone(), Vec::new());
}
let compiled_shaders = compiled_shader_map.source_to_compiled.get_mut(shader).unwrap();
let compiled_shaders = compiled_shader_map.source_to_compiled.get_mut(shader_handle).unwrap();
if let None = compiled_shaders.iter().find(|(shader_defs, _shader)| *shader_defs == renderable.shader_defs) {
let shader_resource = shader_storage.get(shader).unwrap();
let shader_resource = shader_storage.get(shader_handle).unwrap();
let shader_def_vec = renderable.shader_defs.iter().cloned().collect::<Vec<String>>();
let compiled_shader = shader_resource.get_spirv_shader(Some(&shader_def_vec));
compiled_shaders.push((renderable.shader_defs.clone(), shader.clone()));
compiled_shaders.push((renderable.shader_defs.clone(), shader_handle.clone()));
let compiled_shader_handle = shader_storage.add(compiled_shader);
// TODO: collecting assigments in a map means they won't be removed when the macro changes
// TODO: need to somehow grab base shader's pipeline, then copy it
@ -75,6 +79,7 @@ pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGra
}
}
}
}
// cleanup entity shader_defs so next frame they can be refreshed
for mut renderable in <Write<Renderable>>::query().iter_mut(world) {

View file

@ -1,11 +1,15 @@
use crate::{
asset::{AssetStorage, Handle},
legion::prelude::*,
render::{Shader, render_graph_2::{
resource_name, update_shader_assignments, BindGroup, BindType, DynamicUniformBufferInfo,
PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass,
RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor, Renderer,
ResourceInfo, ShaderUniforms, TextureDescriptor,
}},
render::{
render_graph_2::{
resource_name, update_shader_assignments, BindGroup, BindType,
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass,
RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor,
Renderer, ResourceInfo, TextureDescriptor,
},
Shader,
},
};
use std::{collections::HashMap, ops::Deref};
@ -15,7 +19,7 @@ pub struct WgpuRenderer {
pub surface: Option<wgpu::Surface>,
pub encoder: Option<wgpu::CommandEncoder>,
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub buffers: HashMap<String, wgpu::Buffer>,
pub textures: HashMap<String, wgpu::TextureView>,
pub resource_info: HashMap<String, ResourceInfo>,
@ -69,12 +73,14 @@ impl WgpuRenderer {
pipeline_descriptor: &mut PipelineDescriptor,
bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>,
device: &wgpu::Device,
vertex_shader: &Shader,
fragment_shader: Option<&Shader>,
) -> wgpu::RenderPipeline {
let vertex_shader_module = Self::create_shader_module(device, &pipeline_descriptor
.shader_stages
.vertex, None);
let fragment_shader_module = match pipeline_descriptor.shader_stages.fragment {
Some(ref fragment_shader) => Some(Self::create_shader_module(device, fragment_shader, None)),
let vertex_shader_module = Self::create_shader_module(device, vertex_shader, None);
let fragment_shader_module = match fragment_shader {
Some(fragment_shader) => {
Some(Self::create_shader_module(device, fragment_shader, None))
}
None => None,
};
@ -121,10 +127,10 @@ impl WgpuRenderer {
layout: &pipeline_layout,
vertex_stage: wgpu::ProgrammableStageDescriptor {
module: &vertex_shader_module,
entry_point: &pipeline_descriptor.shader_stages.vertex.entry_point,
entry_point: &vertex_shader.entry_point,
},
fragment_stage: match pipeline_descriptor.shader_stages.fragment {
Some(ref fragment_shader) => Some(wgpu::ProgrammableStageDescriptor {
fragment_stage: match fragment_shader {
Some(fragment_shader) => Some(wgpu::ProgrammableStageDescriptor {
entry_point: &fragment_shader.entry_point,
module: fragment_shader_module.as_ref().unwrap(),
}),
@ -303,115 +309,11 @@ impl WgpuRenderer {
bind_group_id
}
// TODO: remove me
#[allow(dead_code)]
fn setup_dynamic_entity_shader_uniforms(
&mut self,
world: &World,
render_graph: &RenderGraph,
encoder: &mut wgpu::CommandEncoder,
) {
// retrieve all uniforms buffers that aren't aleady set. these are "dynamic" uniforms, which are set by the user in ShaderUniforms
// TODO: this breaks down in multiple ways:
// (1) resource_info will be set after the first run so this won't update.
// (2) if we create new buffers, the old bind groups will be invalid
for pipeline in render_graph.pipeline_descriptors.values() {
for bind_group in pipeline.pipeline_layout.bind_groups.iter() {
for binding in bind_group.bindings.iter() {
// if let None = self.resource_info.get(&binding.name) {
if let BindType::Uniform { dynamic: true, .. } = &binding.bind_type {
if self.dynamic_uniform_buffer_info.contains_key(&binding.name) {
continue;
}
self.dynamic_uniform_buffer_info.insert(
binding.name.to_string(),
DynamicUniformBufferInfo {
capacity: 0,
count: 0,
size: binding.bind_type.get_uniform_size().unwrap(),
indices: HashMap::new(),
offsets: HashMap::new(),
},
);
}
// }
}
}
}
// count the number of entities providing each uniform
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
info.count = 0;
for (entity, shader_uniforms) in <Read<ShaderUniforms>>::query().iter_entities(world) {
if let Some(_) = shader_uniforms.get_uniform_info(world, entity, name) {
info.count += 1;
}
}
}
// allocate uniform buffers
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
if self.buffers.contains_key(name) && info.count < info.capacity {
continue;
}
if info.count >= info.capacity && info.capacity != 0 {
panic!("resizing dynamic uniform buffers isn't supported yet. we still need to support updating bind groups");
}
// allocate enough space for twice as many entities as there are currently;
info.capacity = info.count * 2;
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity;
// TODO: remove this code duplication in favor of self.create_buffer(). this will likely require a refactor
// the following is a flattening of the content in self.create_buffer(), which can't be called because
// of rust's ownership rules. sometimes rust makes me unhappy
let buffer_usage = wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM;
let buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
size,
usage: buffer_usage,
});
self.resource_info.insert(
name.to_string(),
ResourceInfo::Buffer { buffer_usage, size },
);
self.buffers.insert(name.to_string(), buffer);
}
// copy entity uniform data to buffers
for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() {
let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count;
let mapped = self
.device
.create_buffer_mapped(size as usize, wgpu::BufferUsage::COPY_SRC);
let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize;
let mut offset = 0usize;
for (i, (entity, shader_uniforms)) in <Read<ShaderUniforms>>::query()
.iter_entities(world)
.enumerate()
{
// TODO: check if index has changed. if it has, then entity should be updated
// TODO: only mem-map entities if their data has changed
info.offsets.insert(entity, offset as u64);
info.indices.insert(i, entity);
if let Some(bytes) = shader_uniforms.get_uniform_bytes(world, entity, name) {
mapped.data[offset..(offset + bytes.len())].copy_from_slice(bytes.as_slice());
offset += alignment;
}
}
let temp_buffer = mapped.finish();
let uniform_buffer = self.buffers.get(name);
encoder.copy_buffer_to_buffer(&temp_buffer, 0, uniform_buffer.unwrap(), 0, size);
}
}
pub fn create_shader_module(device: &wgpu::Device, shader: &Shader, macros: Option<&[String]>) -> wgpu::ShaderModule {
pub fn create_shader_module(
device: &wgpu::Device,
shader: &Shader,
macros: Option<&[String]>,
) -> wgpu::ShaderModule {
device.create_shader_module(&shader.get_spirv(macros))
}
}
@ -489,16 +391,38 @@ impl Renderer for WgpuRenderer {
// self.setup_dynamic_entity_shader_uniforms(world, render_graph, &mut encoder);
// setup, pipelines, bind groups, and resources
for (pipeline_name, pipeline_descriptor) in render_graph.pipeline_descriptors.iter_mut() {
let mut pipeline_storage = world
.resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let shader_storage = world.resources.get::<AssetStorage<Shader>>().unwrap();
for pipeline_descriptor_handle in render_graph.pipeline_descriptors.iter() {
let pipeline_descriptor = pipeline_storage
.get_mut(pipeline_descriptor_handle)
.unwrap();
// create pipelines
if let None = self.render_pipelines.get(pipeline_name) {
if !self
.render_pipelines
.contains_key(pipeline_descriptor_handle)
{
let vertex_shader = shader_storage
.get(&pipeline_descriptor.shader_stages.vertex)
.unwrap();
let fragment_shader = pipeline_descriptor
.shader_stages
.fragment
.as_ref()
.map(|handle| &*shader_storage.get(&handle).unwrap());
let render_pipeline = WgpuRenderer::create_render_pipeline(
pipeline_descriptor,
&mut self.bind_group_layouts,
&self.device,
vertex_shader,
fragment_shader,
);
self.render_pipelines
.insert(pipeline_name.to_string(), render_pipeline);
.insert(pipeline_descriptor_handle.clone(), render_pipeline);
}
// create bind groups
@ -512,9 +436,7 @@ impl Renderer for WgpuRenderer {
let mut render_pass = self.create_render_pass(pass_descriptor, &mut encoder, &frame);
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
for pass_pipeline in pass_pipelines.iter() {
if let Some(pipeline_descriptor) =
render_graph.pipeline_descriptors.get(pass_pipeline)
{
let pipeline_descriptor = pipeline_storage.get(pass_pipeline).unwrap();
let render_pipeline = self.render_pipelines.get(pass_pipeline).unwrap();
render_pass.set_pipeline(render_pipeline);
@ -530,7 +452,6 @@ impl Renderer for WgpuRenderer {
}
}
}
}
let command_buffer = encoder.finish();
self.queue.submit(&[command_buffer]);

View file

@ -1,3 +1,4 @@
use crate::asset::Handle;
use std::marker::Copy;
#[derive(Hash, Eq, PartialEq, Copy, Clone)]
@ -69,9 +70,7 @@ impl Shader {
pub fn get_spirv(&self, macros: Option<&[String]>) -> Vec<u32> {
match self.source {
ShaderSource::Spirv(ref bytes) => bytes.clone(),
ShaderSource::Glsl(ref source) => {
glsl_to_spirv(&source, self.stage, macros)
}
ShaderSource::Glsl(ref source) => glsl_to_spirv(&source, self.stage, macros),
}
}
@ -85,15 +84,44 @@ impl Shader {
}
pub struct ShaderStages {
pub vertex: Shader,
pub fragment: Option<Shader>,
pub vertex: Handle<Shader>,
pub fragment: Option<Handle<Shader>>,
}
impl ShaderStages {
pub fn new(vertex_shader: Shader) -> Self {
pub fn new(vertex_shader: Handle<Shader>) -> Self {
ShaderStages {
vertex: vertex_shader,
fragment: None,
}
}
pub fn iter(&self) -> ShaderStagesIter {
ShaderStagesIter {
shader_stages: self,
index: 0,
}
}
}
pub struct ShaderStagesIter<'a> {
pub shader_stages: &'a ShaderStages,
pub index: usize,
}
impl<'a> Iterator for ShaderStagesIter<'a> {
type Item = &'a Handle<Shader>;
fn next(&mut self) -> Option<&'a Handle<Shader>> {
match self.index {
0 => Some(&self.shader_stages.vertex),
1 => {
if let Some(ref fragment) = self.shader_stages.fragment {
Some(fragment)
} else {
None
}
}
_ => None,
}
}
}