mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
textures work!
This commit is contained in:
parent
8d3026899d
commit
5154320f70
12 changed files with 137 additions and 136 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
"#,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -316,13 +316,13 @@ impl WgpuRenderer {
|
|||
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 { .. } => {
|
||||
println!(
|
||||
"Warning: creating new empty buffer for uniform binding {} {:?}",
|
||||
binding.name, binding
|
||||
);
|
||||
unset_uniforms.push(binding.name.to_string());
|
||||
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,107 +444,34 @@ 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();
|
||||
}).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,
|
||||
bindings: bindings.as_slice(),
|
||||
};
|
||||
|
||||
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>>();
|
||||
|
||||
let bind_group_layout = self.bind_group_layouts.get(&bind_group_id).unwrap();
|
||||
let bind_group_descriptor = wgpu::BindGroupDescriptor {
|
||||
layout: bind_group_layout,
|
||||
bindings: bindings.as_slice(),
|
||||
};
|
||||
|
||||
let bind_group = self.device.create_bind_group(&bind_group_descriptor);
|
||||
self.bind_groups.insert(
|
||||
bind_group_id,
|
||||
BindGroupInfo {
|
||||
bind_group,
|
||||
unset_uniforms,
|
||||
},
|
||||
);
|
||||
}
|
||||
let bind_group = self.device.create_bind_group(&bind_group_descriptor);
|
||||
// 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: 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) {
|
||||
|
|
|
@ -16,4 +16,5 @@ pub enum ResourceInfo {
|
|||
// pub layout: Option<
|
||||
},
|
||||
Texture,
|
||||
Sampler,
|
||||
}
|
||||
|
|
|
@ -85,8 +85,8 @@ where
|
|||
resource
|
||||
}
|
||||
};
|
||||
|
||||
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 {:?}",
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}]
|
||||
),
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue