textures work!

This commit is contained in:
Carter Anderson 2020-03-01 17:48:37 -08:00
parent 8d3026899d
commit 5154320f70
12 changed files with 137 additions and 136 deletions

View file

@ -13,6 +13,12 @@ Here is the current list of planned features. All items are sorted in approximat
* Add runtime type safety to uniform bindings (and maybe compile time)
* Inject layout set/bindings into shader source so they don't need to be defined in-shader. Specify set / binding indices in resource providers?
* Pull as much logic as possible from wgpu_renderer into a "render orchestrator" struct/trait
* Docs
* Add doc comments to code
* Add tutorials
* Add feature docs
* Add "template" projects
* Add ```#![deny(warnings, missing_docs)]``` to ensure future contributions meet style/doc standards
* Error Handling
* Custom error type?
* Remove as many panics / unwraps as possible

View file

@ -42,7 +42,7 @@ fn main() {
mat4 Model;
};
void main() {
v_Position = Model * vec4(a_Pos);
v_Position = Model * a_Pos;
gl_Position = ViewProj * v_Position;
}
"#,

View file

@ -97,6 +97,15 @@ impl Hash for BindGroup {
}
}
impl PartialEq for BindGroup {
fn eq(&self, other: &BindGroup) -> bool {
self.index == other.index &&
self.bindings == other.bindings
}
}
impl Eq for BindGroup {}
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Binding {
pub name: String,

View file

@ -24,10 +24,10 @@ layout(set = 0, binding = 1) uniform Lights {
};
# ifdef STANDARD_MATERIAL_ALBEDO_TEXTURE
layout(set = 1, binding = 1) uniform texture2D StandardMaterial_albedo_texture;
layout(set = 1, binding = 2) uniform sampler StandardMaterial_albedo_sampler;
layout(set = 2, binding = 1) uniform texture2D StandardMaterial_albedo_texture;
layout(set = 2, binding = 2) uniform sampler StandardMaterial_albedo_sampler;
# else
layout(set = 1, binding = 1) uniform StandardMaterial_albedo {
layout(set = 2, binding = 1) uniform StandardMaterial_albedo {
vec4 Albedo;
};
# endif

View file

@ -18,7 +18,7 @@ layout(set = 1, binding = 0) uniform Object {
void main() {
v_Normal = mat3(Model) * vec3(a_Normal.xyz);
v_Position = Model * vec4(a_Pos);
v_Position = Model * a_Pos;
v_Uv = a_Uv;
gl_Position = ViewProj * v_Position;
}

View file

@ -15,7 +15,5 @@ layout(set = 1, binding = 1) uniform StandardMaterial_albedo {
};
void main() {
// multiply the light by material color
o_Target = vec4(1.0, 0.0, 0.0, 1.0);
o_Target = Albedo;
}

View file

@ -22,8 +22,6 @@ layout(set = 1, binding = 1) uniform StandardMaterial_albedo {
void main() {
v_Normal = mat3(Model) * vec3(a_Normal.xyz);
v_Position = Model * vec4(a_Pos);
// v_Normal = vec3(a_Normal.xyz);
// v_Position = vec4(a_Pos);
v_Position = Model * a_Pos;
gl_Position = ViewProj * v_Position;
}

View file

@ -81,7 +81,7 @@ pub trait Renderer {
fn get_render_resources(&self) -> &RenderResources;
fn get_render_resources_mut(&mut self) -> &mut RenderResources;
fn set_entity_uniform_resource(&mut self, entity: Entity, uniform_name: &str, resource: RenderResource);
fn get_entity_uniform_resource(&mut self, entity: Entity, uniform_name: &str) -> Option<RenderResource>;
fn get_entity_uniform_resource(&self, entity: Entity, uniform_name: &str) -> Option<RenderResource>;
}
pub trait RenderPass {

View file

@ -316,13 +316,13 @@ impl WgpuRenderer {
let resource = match self.render_resources.get_named_resource(&binding.name) {
resource @ Some(_) => resource,
None => {
match binding.bind_type {
BindType::Uniform { .. } => {
println!(
"Warning: creating new empty buffer for binding {} {:?}",
"Warning: creating new empty buffer for uniform binding {} {:?}",
binding.name, binding
);
unset_uniforms.push(binding.name.to_string());
match binding.bind_type {
BindType::Uniform { .. } => {
let size = binding.bind_type.get_uniform_size().unwrap();
let resource = self.create_buffer(
size,
@ -430,23 +430,13 @@ impl WgpuRenderer {
pub fn create_entity_bind_group(&mut self, bind_group: &BindGroup, entity: Entity) {
let bind_group_id = bind_group.get_hash().unwrap();
let mut binding_resources = Vec::new();
for binding in bind_group.bindings.iter() {
let bindings = bind_group.bindings.iter().map(|binding| {
if let Some(resource) = self.get_entity_uniform_resource(entity, &binding.name) {
let resource_info = self.resource_info.get(&resource).unwrap();
match binding.bind_type {
BindType::SampledTexture { .. } => {
},
BindType::Sampler => {
},
_ => panic!("Attempted to create an unsupported BindType for BindGroup. Binding: {:?}, BindGroup: {:?}, Entity: {:?}", binding, bind_group, entity),
}
wgpu::Binding {
binding: binding.index,
resource: match &binding.bind_type {
BindType::SampledTexture {
} => {
BindType::SampledTexture { .. } => {
if let ResourceInfo::Texture = resource_info {
let texture = self.textures.get(&resource).unwrap();
wgpu::BindingResource::TextureView(texture)
@ -454,92 +444,22 @@ impl WgpuRenderer {
panic!("expected a Texture resource");
}
},
BindType::Sampler => {
if let ResourceInfo::Sampler = resource_info {
let sampler = self.samplers.get(&resource).unwrap();
wgpu::BindingResource::Sampler(sampler)
} else {
panic!("expected a Sampler resource");
}
}
_ => panic!("unsupported bind type"),
},
}
}
else {
panic!("No resource assigned to uniform {} for entity {}", binding.name, entity),
panic!("No resource assigned to uniform \"{}\" for entity {}", binding.name, entity);
}
}
}
fn setup_bind_group(&mut self, bind_group: &BindGroup) {
let bind_group_id = bind_group.get_hash().unwrap();
if let None = self.bind_groups.get(&bind_group_id) {
let mut unset_uniforms = Vec::new();
let mut binding_resources = Vec::new();
// if a uniform resource buffer doesn't exist, create a new empty one
for binding in bind_group.bindings.iter() {
let resource = match self.render_resources.get_named_resource(&binding.name) {
resource @ Some(_) => resource,
None => {
println!(
"Warning: creating new empty buffer for binding {} {:?}",
binding.name, binding
);
unset_uniforms.push(binding.name.to_string());
match binding.bind_type {
BindType::Uniform { .. } => {
let size = binding.bind_type.get_uniform_size().unwrap();
let resource = self.create_buffer(
size,
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
);
self.render_resources
.set_named_resource(&binding.name, resource);
Some(resource)
},
BindType::Sampler | BindType::SampledTexture { .. } => {
// textures and samplers are handled per-entity
return;
},
_ => panic!("unsupported bind type: {:?}", binding),
}
}
};
if let Some(resource) = resource {
binding_resources.push(resource);
}
}
// create wgpu Bindings
let bindings = bind_group
.bindings
.iter()
.zip(binding_resources)
.map(|(binding, resource)| {
let resource_info = self.resource_info.get(&resource).unwrap();
wgpu::Binding {
binding: binding.index,
resource: match &binding.bind_type {
BindType::Uniform {
dynamic: _,
properties: _,
} => {
if let ResourceInfo::Buffer {
size,
buffer_usage: _,
} = resource_info
{
let buffer = self.buffers.get(&resource).unwrap();
wgpu::BindingResource::Buffer {
buffer,
range: 0..*size,
}
} else {
panic!("expected a Buffer resource");
}
}
_ => panic!("unsupported bind type"),
},
}
})
.collect::<Vec<wgpu::Binding>>();
}).collect::<Vec<wgpu::Binding>>();
let bind_group_layout = self.bind_group_layouts.get(&bind_group_id).unwrap();
let bind_group_descriptor = wgpu::BindGroupDescriptor {
layout: bind_group_layout,
@ -547,14 +467,11 @@ impl WgpuRenderer {
};
let bind_group = self.device.create_bind_group(&bind_group_descriptor);
self.bind_groups.insert(
bind_group_id,
BindGroupInfo {
// TODO: storing a large number entity bind groups might actually be really bad. make sure this is ok
self.entity_bind_groups.insert((entity, bind_group_id), BindGroupInfo {
bind_group,
unset_uniforms,
},
);
}
unset_uniforms: Vec::new(),
});
}
}
@ -857,11 +774,10 @@ impl Renderer for WgpuRenderer {
let sampler = self.device.create_sampler(&descriptor);
let resource = self.render_resources.get_next_resource();
self.samplers.insert(resource, sampler);
self.add_resource_info(resource, ResourceInfo::Texture);
self.add_resource_info(resource, ResourceInfo::Sampler);
resource
}
fn create_texture(
&mut self,
texture_descriptor: &TextureDescriptor,
@ -918,7 +834,7 @@ impl Renderer for WgpuRenderer {
fn set_entity_uniform_resource(&mut self, entity: Entity, uniform_name: &str, resource: RenderResource) {
self.entity_uniform_resources.insert((Cow::Owned(entity), Cow::Owned(uniform_name.to_string())), resource);
}
fn get_entity_uniform_resource(&mut self, entity: Entity, uniform_name: &str) -> Option<RenderResource> {
fn get_entity_uniform_resource(&self, entity: Entity, uniform_name: &str) -> Option<RenderResource> {
self.entity_uniform_resources.get(&(Cow::Owned(entity), Cow::Borrowed(uniform_name))).cloned()
}
}
@ -964,7 +880,9 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
for bind_group in pipeline_layout.bind_groups.iter() {
let bind_group_id = bind_group.get_hash().unwrap();
let bind_group_info = match self.renderer.bind_groups.get(&bind_group_id) {
// if there is a "global" bind group, use that
Some(bind_group_info) => bind_group_info,
// otherwise try to get an entity-specific bind group
None => {
if let Some(entity) = entity {
if let None = self.renderer.get_entity_bind_group(*entity, bind_group_id) {

View file

@ -16,4 +16,5 @@ pub enum ResourceInfo {
// pub layout: Option<
},
Texture,
Sampler,
}

View file

@ -86,7 +86,7 @@ where
}
};
renderer.assign_entity_uniform_resource(*entity, uniform_info.name, resource);
renderer.set_entity_uniform_resource(entity, uniform_info.name, resource);
}
BindType::Sampler { .. } => {
let texture_handle =
@ -104,7 +104,7 @@ where
}
};
renderer.assign_entity_uniform_resource(*entity, uniform_info.name, resource);
renderer.set_entity_uniform_resource(entity, uniform_info.name, resource);
}
_ => panic!(
"encountered unsupported bind_type {:?}",

View file

@ -23,7 +23,7 @@ use zerocopy::AsBytes;
// println!("{:?}", structured.types);
// }
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ShaderLayout {
pub bind_groups: Vec<BindGroup>,
pub entry_point: String,
@ -70,23 +70,23 @@ fn reflect_dimension(type_description: &ReflectTypeDescription) -> TextureViewDi
fn reflect_binding(binding: &ReflectDescriptorBinding) -> Binding {
let type_description = binding.type_description.as_ref().unwrap();
let bind_type = match binding.descriptor_type {
ReflectDescriptorType::UniformBuffer => BindType::Uniform {
let (name, bind_type) = match binding.descriptor_type {
ReflectDescriptorType::UniformBuffer => (&type_description.type_name, BindType::Uniform {
dynamic: false,
properties: vec![reflect_uniform(type_description)],
},
ReflectDescriptorType::SampledImage => BindType::SampledTexture {
}),
ReflectDescriptorType::SampledImage => (&binding.name, BindType::SampledTexture {
dimension: reflect_dimension(type_description),
multisampled: false,
},
ReflectDescriptorType::Sampler => BindType::Sampler,
}),
ReflectDescriptorType::Sampler => (&binding.name, BindType::Sampler),
_ => panic!("unsupported bind type {:?}", binding.descriptor_type),
};
Binding {
index: binding.binding,
bind_type,
name: type_description.type_name.to_string(),
name: name.to_string(),
}
}
@ -170,3 +170,74 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::render::{
render_graph::{BindGroup, BindType, Binding, UniformProperty, UniformPropertyType},
Shader, ShaderStage,
};
#[test]
fn test_reflection() {
let vertex_shader = Shader::from_glsl(
ShaderStage::Vertex,
r#"
#version 450
layout(location = 0) in vec4 a_Pos;
layout(location = 0) out vec4 v_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform texture2D Texture;
void main() {
v_Position = a_Pos;
gl_Position = ViewProj * v_Position;
}
"#,
)
.get_spirv_shader(None);
let layout = vertex_shader.reflect_layout().unwrap();
assert_eq!(
layout,
ShaderLayout {
entry_point: "main".to_string(),
bind_groups: vec![
BindGroup::new(
0,
vec![Binding {
index: 0,
name: "Camera".to_string(),
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![UniformProperty {
name: "Camera".to_string(),
property_type: UniformPropertyType::Struct(vec![
UniformProperty {
name: "".to_string(),
property_type: UniformPropertyType::Mat4,
}
]),
}],
},
}]
),
BindGroup::new(
1,
vec![Binding {
index: 0,
name: "Texture".to_string(),
bind_type: BindType::SampledTexture {
multisampled: false,
dimension: TextureViewDimension::D2,
},
}]
),
]
}
);
}
}