more texture work

This commit is contained in:
Carter Anderson 2020-02-23 23:41:48 -08:00
parent 79c900bc2d
commit 1a4bd98434
10 changed files with 171 additions and 42 deletions

View file

@ -119,13 +119,20 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}).collect::<Vec<String>>();
let mut uniform_name_strings = Vec::new();
let field_uniform_names = active_uniform_field_name_strings.iter().map(|f| {
let uniform = format!("{}_{}", struct_name, f);
let mut texture_and_sampler_name_strings = Vec::new();
let mut texture_and_sampler_name_idents = Vec::new();
let field_uniform_names = active_uniform_fields.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap().to_string();
let uniform = format!("{}_{}", struct_name, field_name);
let texture = format!("{}_texture", uniform);
let sampler = format!("{}_sampler", uniform);
uniform_name_strings.push(uniform.clone());
texture_and_sampler_name_strings.push(texture.clone());
texture_and_sampler_name_strings.push(sampler.clone());
texture_and_sampler_name_idents.push(f.ident.clone());
texture_and_sampler_name_idents.push(f.ident.clone());
quote!(bevy::render::render_graph::FieldUniformName {
field: #f,
field: #field_name,
uniform: #uniform,
texture: #texture,
sampler: #sampler,
@ -160,6 +167,14 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}
}
fn get_uniform_texture(&self, name: &str) -> Option<bevy::asset::Handle<bevy::asset::Texture>> {
use bevy::render::render_graph::GetTexture;
match name {
#(#texture_and_sampler_name_strings => self.#texture_and_sampler_name_idents.get_texture(),)*
_ => None,
}
}
// TODO: this will be very allocation heavy. find a way to either make this allocation free
// or alternatively only run it when the shader_defs have changed
fn get_shader_defs(&self) -> Option<Vec<String>> {

View file

@ -12,7 +12,7 @@ fn setup(world: &mut World) {
let texture_handle = {
let mut texture_storage = world.resources.get_mut::<AssetStorage<Texture>>().unwrap();
let texture = Texture::load(TextureType::Data(asset::create_texels(256)));
let texture = Texture::load(TextureType::Data(asset::create_texels(256), 256, 256));
texture_storage.add(texture)
};

View file

@ -1,23 +1,44 @@
use crate::asset::Asset;
use crate::{render::render_graph::{TextureDimension, TextureDescriptor}, asset::Asset};
pub enum TextureType {
Data(Vec<u8>),
Data(Vec<u8>, usize, usize),
}
pub struct Texture {
pub data: Vec<u8>,
pub width: usize,
pub height: usize,
}
impl Asset<TextureType> for Texture {
fn load(descriptor: TextureType) -> Self {
let data = match descriptor {
TextureType::Data(data) => data.clone(),
let (data, width, height) = match descriptor {
TextureType::Data(data, width, height) => (data.clone(), width, height),
};
Texture { data }
Texture { data, width, height }
}
}
impl From<&Texture> for TextureDescriptor {
fn from(texture: &Texture) -> Self {
TextureDescriptor {
size: wgpu::Extent3d {
height: texture.height as u32,
width: texture.width as u32,
depth: 1,
},
array_layer_count: 1,
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
}
}
}
pub fn create_texels(size: usize) -> Vec<u8> {
use std::iter;

View file

@ -241,3 +241,32 @@ impl From<TextureDescriptor> for wgpu::TextureDescriptor {
}
}
}
#[derive(Copy, Clone)]
pub struct SamplerDescriptor {
pub address_mode_u: wgpu::AddressMode,
pub address_mode_v: wgpu::AddressMode,
pub address_mode_w: wgpu::AddressMode,
pub mag_filter: wgpu::FilterMode,
pub min_filter: wgpu::FilterMode,
pub mipmap_filter: wgpu::FilterMode,
pub lod_min_clamp: f32,
pub lod_max_clamp: f32,
pub compare_function: wgpu::CompareFunction,
}
impl From<SamplerDescriptor> for wgpu::SamplerDescriptor {
fn from(sampler_descriptor: SamplerDescriptor) -> Self {
wgpu::SamplerDescriptor {
address_mode_u: sampler_descriptor.address_mode_u,
address_mode_v: sampler_descriptor.address_mode_v,
address_mode_w: sampler_descriptor.address_mode_w,
mag_filter: sampler_descriptor.mag_filter,
min_filter: sampler_descriptor.min_filter,
mipmap_filter: sampler_descriptor.mipmap_filter,
lod_min_clamp: sampler_descriptor.lod_min_clamp,
lod_max_clamp: sampler_descriptor.lod_max_clamp,
compare_function: sampler_descriptor.compare_function,
}
}
}

View file

@ -2,8 +2,8 @@ use crate::{
legion::prelude::*,
render::render_graph::{
render_resource::RenderResource, DynamicUniformBufferInfo, PipelineDescriptor, RenderGraph,
ResourceInfo, TextureDescriptor,
},
ResourceInfo, TextureDescriptor, SamplerDescriptor
}, asset::{Handle, Texture},
};
use std::ops::Range;
@ -23,8 +23,8 @@ pub trait Renderer {
data: &[u8],
buffer_usage: wgpu::BufferUsage,
) -> RenderResource;
fn create_texture(&mut self, texture_descriptor: &TextureDescriptor) -> RenderResource;
fn create_texture_with_data(
fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource;
fn create_texture(
&mut self,
texture_descriptor: &TextureDescriptor,
bytes: Option<&[u8]>,
@ -67,6 +67,7 @@ pub trait Renderer {
) -> RenderResource;
fn remove_buffer(&mut self, resource: RenderResource);
fn remove_texture(&mut self, resource: RenderResource);
fn remove_sampler(&mut self, resource: RenderResource);
fn get_resource_info(&self, resource: RenderResource) -> Option<&ResourceInfo>;
fn copy_buffer_to_buffer(
&mut self,
@ -78,6 +79,8 @@ pub trait Renderer {
);
fn get_named_resource(&self, name: &str) -> Option<RenderResource>;
fn set_named_resource(&mut self, name: &str, resource: RenderResource);
fn get_texture_resource(&self, texture: Handle<Texture>) -> Option<RenderResource>;
fn set_texture_resource(&mut self, texture: Handle<Texture>, resource: RenderResource);
}
pub trait RenderPass {

View file

@ -1,5 +1,5 @@
use crate::{
asset::{AssetStorage, Handle},
asset::{AssetStorage, Handle, Texture},
legion::prelude::*,
render::{
render_graph::{
@ -7,7 +7,7 @@ use crate::{
DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, PipelineLayout,
PipelineLayoutType, RenderGraph, RenderPass, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, RenderResource, RenderResources, Renderer,
ResourceInfo, TextureDescriptor,
ResourceInfo, SamplerDescriptor, TextureDescriptor,
},
Shader,
},
@ -23,6 +23,7 @@ pub struct WgpuRenderer {
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub buffers: HashMap<RenderResource, wgpu::Buffer>,
pub textures: HashMap<RenderResource, wgpu::TextureView>,
pub samplers: HashMap<RenderResource, wgpu::Sampler>,
pub resource_info: HashMap<RenderResource, ResourceInfo>,
pub bind_groups: HashMap<u64, BindGroupInfo>,
pub bind_group_layouts: HashMap<u64, wgpu::BindGroupLayout>,
@ -64,6 +65,7 @@ impl WgpuRenderer {
render_pipelines: HashMap::new(),
buffers: HashMap::new(),
textures: HashMap::new(),
samplers: HashMap::new(),
resource_info: HashMap::new(),
bind_groups: HashMap::new(),
bind_group_layouts: HashMap::new(),
@ -304,11 +306,11 @@ impl WgpuRenderer {
if let None = self.bind_groups.get(&bind_group_id) {
let mut unset_uniforms = Vec::new();
let mut binding_resources = Vec::with_capacity(bind_group.bindings.len());
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) {
Some(resource) => resource,
resource @ Some(_) => resource,
None => {
println!(
"Warning: creating new empty buffer for binding {} {:?}",
@ -325,14 +327,20 @@ impl WgpuRenderer {
self.render_resources
.set_named_resource(&binding.name, resource);
resource
}
Some(resource)
},
BindType::Sampler | BindType::SampledTexture { .. } => {
// textures and samplers are handled per-entity
None
},
_ => panic!("unsupported bind type: {:?}", binding),
}
}
};
binding_resources.push(resource);
if let Some(resource) = resource {
binding_resources.push(resource);
}
}
// create wgpu Bindings
@ -474,7 +482,7 @@ impl Renderer for WgpuRenderer {
update_shader_assignments(world, render_graph);
for (name, texture_descriptor) in render_graph.queued_textures.drain(..) {
let resource = self.create_texture(&texture_descriptor);
let resource = self.create_texture(&texture_descriptor, None);
self.render_resources.set_named_resource(&name, resource);
}
@ -709,16 +717,17 @@ impl Renderer for WgpuRenderer {
self.dynamic_uniform_buffer_info.insert(resource, info);
}
fn create_texture(&mut self, texture_descriptor: &TextureDescriptor) -> RenderResource {
let descriptor: wgpu::TextureDescriptor = (*texture_descriptor).into();
let texture = self.device.create_texture(&descriptor);
fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource {
let descriptor: wgpu::SamplerDescriptor = (*sampler_descriptor).into();
let sampler = self.device.create_sampler(&descriptor);
let resource = self.render_resources.get_next_resource();
self.textures
.insert(resource, texture.create_default_view());
self.samplers.insert(resource, sampler);
self.add_resource_info(resource, ResourceInfo::Texture);
resource
}
fn create_texture_with_data(
fn create_texture(
&mut self,
texture_descriptor: &TextureDescriptor,
bytes: Option<&[u8]>,
@ -749,6 +758,7 @@ impl Renderer for WgpuRenderer {
let resource = self.render_resources.get_next_resource();
self.add_resource_info(resource, ResourceInfo::Texture);
self.textures.insert(resource, texture_view);
resource
}
@ -764,6 +774,19 @@ impl Renderer for WgpuRenderer {
self.textures.remove(&resource);
self.resource_info.remove(&resource);
}
fn remove_sampler(&mut self, resource: RenderResource) {
self.samplers.remove(&resource);
self.resource_info.remove(&resource);
}
fn get_texture_resource(&self, texture: Handle<Texture>) -> Option<RenderResource> {
self.render_resources.get_texture_resource(texture)
}
fn set_texture_resource(&mut self, texture: Handle<Texture>, resource: RenderResource) {
self.render_resources.set_texture_resource(texture, resource);
}
}
pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {

View file

@ -26,7 +26,7 @@ impl FrameTextureResourceProvider {
renderer.remove_texture(old_resource);
}
let texture_resource = renderer.create_texture(&self.descriptor);
let texture_resource = renderer.create_texture(&self.descriptor, None);
renderer.set_named_resource(&self.name, texture_resource);
}
}

View file

@ -1,6 +1,9 @@
use crate::render::render_graph::{
render_resource::RenderResource, AsUniforms, BindType, DynamicUniformBufferInfo, Renderable,
Renderer, ResourceProvider, UniformInfoIter,
use crate::{
asset::{AssetStorage, Texture},
render::render_graph::{
render_resource::RenderResource, AsUniforms, BindType, DynamicUniformBufferInfo,
Renderable, Renderer, ResourceProvider, TextureDescriptor, UniformInfoIter,
},
};
use legion::prelude::*;
use std::{marker::PhantomData, ops::Deref};
@ -68,11 +71,18 @@ where
uniform_index += 1;
}
BindType::SampledTexture { .. } => {
// TODO: look up Handle and load
}
BindType::Sampler { .. } => {
// TODO: look up Handle and load
let texture_handle =
uniforms.get_uniform_texture(&uniform_info.name).unwrap();
let storage = world.resources.get::<AssetStorage<Texture>>().unwrap();
let texture = storage.get(&texture_handle).unwrap();
if let None = renderer.get_texture_resource(texture_handle.clone()) {
let descriptor: TextureDescriptor = texture.into();
let resource =
renderer.create_texture(&descriptor, Some(&texture.data));
renderer.set_texture_resource(texture_handle, resource);
}
}
BindType::Sampler { .. } => {}
_ => panic!(
"encountered unsupported bind_type {:?}",
uniform_info.bind_type

View file

@ -1,6 +1,6 @@
use crate::{
asset::{Handle, Texture},
core::GetBytes,
math::Vec4,
render::{
color::ColorSource,
render_graph::{BindType, TextureViewDimension},
@ -13,6 +13,7 @@ use std::collections::HashMap;
pub trait AsUniforms {
fn get_field_uniform_names(&self) -> &[FieldUniformName];
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>>;
fn get_uniform_texture(&self, name: &str) -> Option<Handle<Texture>>;
fn get_shader_defs(&self) -> Option<Vec<String>>;
fn get_field_bind_type(&self, name: &str) -> Option<FieldBindType>;
// TODO: support zero-copy uniforms
@ -125,18 +126,42 @@ impl AsFieldBindType for ColorSource {
}
}
default impl<T> AsFieldBindType for T
impl<T> AsFieldBindType for T
where
T: GetBytes,
{
fn get_field_bind_type(&self) -> FieldBindType {
default fn get_field_bind_type(&self) -> FieldBindType {
FieldBindType::Uniform
}
}
impl AsFieldBindType for Vec4 {
fn get_field_bind_type(&self) -> FieldBindType {
FieldBindType::Uniform
pub trait GetTexture {
fn get_texture(&self) -> Option<Handle<Texture>> {
None
}
}
impl<T> GetTexture for T
where
T: GetBytes,
{
default fn get_texture(&self) -> Option<Handle<Texture>> {
None
}
}
impl GetTexture for Handle<Texture> {
fn get_texture(&self) -> Option<Handle<Texture>> {
Some(self.clone())
}
}
impl GetTexture for ColorSource {
fn get_texture(&self) -> Option<Handle<Texture>> {
match self {
ColorSource::Color(_) => None,
ColorSource::Texture(texture) => Some(texture.clone()),
}
}
}

View file

@ -1,4 +1,4 @@
use crate::render::render_graph::{uniform::AsUniforms, FieldBindType, FieldUniformName};
use crate::{asset::{Handle, Texture}, render::render_graph::{uniform::AsUniforms, FieldBindType, FieldUniformName}};
use zerocopy::AsBytes;
@ -30,4 +30,7 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld {
_ => None,
}
}
fn get_uniform_texture(&self, _name: &str) -> Option<Handle<Texture>> {
None
}
}