render graph bind groups
This commit is contained in:
parent
bcd7dae0ec
commit
a2d0d937e0
@ -40,7 +40,7 @@ pub fn mesh_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mesh_asset) = mesh_storage.get(mesh.id) {
|
if let Some(mesh_asset) = mesh_storage.get(mesh.id) {
|
||||||
// pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);
|
render_pass.setup_bind_groups();
|
||||||
render_pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1);
|
render_pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,16 +10,19 @@ impl PipelineLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Hash)]
|
||||||
pub struct BindGroup {
|
pub struct BindGroup {
|
||||||
pub bindings: Vec<Binding>
|
pub bindings: Vec<Binding>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Hash)]
|
||||||
pub struct Binding {
|
pub struct Binding {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub bind_type: BindType,
|
pub bind_type: BindType,
|
||||||
// TODO: ADD SHADER STAGE VISIBILITY
|
// TODO: ADD SHADER STAGE VISIBILITY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Hash)]
|
||||||
pub enum BindType {
|
pub enum BindType {
|
||||||
Uniform {
|
Uniform {
|
||||||
dynamic: bool,
|
dynamic: bool,
|
||||||
@ -39,11 +42,13 @@ pub enum BindType {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Hash)]
|
||||||
pub struct UniformProperty {
|
pub struct UniformProperty {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub property_type: UniformPropertyType,
|
pub property_type: UniformPropertyType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Hash)]
|
||||||
pub enum UniformPropertyType {
|
pub enum UniformPropertyType {
|
||||||
// TODO: Add all types here
|
// TODO: Add all types here
|
||||||
Int,
|
Int,
|
||||||
@ -56,7 +61,7 @@ pub enum UniformPropertyType {
|
|||||||
Array(Box<UniformPropertyType>, usize),
|
Array(Box<UniformPropertyType>, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Hash)]
|
||||||
pub enum TextureDimension {
|
pub enum TextureDimension {
|
||||||
D1,
|
D1,
|
||||||
D2,
|
D2,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, BufferInfo, PipelineDescriptor}};
|
use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, ResourceInfo, PipelineDescriptor, BindGroup}};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
pub trait Renderer {
|
pub trait Renderer {
|
||||||
@ -7,8 +7,9 @@ pub trait Renderer {
|
|||||||
fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World);
|
fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World);
|
||||||
// TODO: swap out wgpu::BufferUsage for custom type
|
// TODO: swap out wgpu::BufferUsage for custom type
|
||||||
fn create_buffer_with_data(&mut self, name: &str, data: &[u8], buffer_usage: wgpu::BufferUsage);
|
fn create_buffer_with_data(&mut self, name: &str, data: &[u8], buffer_usage: wgpu::BufferUsage);
|
||||||
|
fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64;
|
||||||
fn remove_buffer(&mut self, name: &str);
|
fn remove_buffer(&mut self, name: &str);
|
||||||
fn get_buffer_info(&self, name: &str) -> Option<&BufferInfo>;
|
fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RenderPass {
|
pub trait RenderPass {
|
||||||
@ -17,4 +18,5 @@ pub trait RenderPass {
|
|||||||
fn set_index_buffer(&mut self, name: &str, offset: u64);
|
fn set_index_buffer(&mut self, name: &str, offset: u64);
|
||||||
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64);
|
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64);
|
||||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
||||||
|
fn setup_bind_groups(&mut self);
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
// pub type ResourceId = u64;
|
pub enum ResourceInfo {
|
||||||
|
Buffer {
|
||||||
pub struct BufferInfo {
|
size: u64,
|
||||||
pub size: u64,
|
buffer_usage: wgpu::BufferUsage,
|
||||||
pub buffer_usage: wgpu::BufferUsage,
|
// pub layout: Option<
|
||||||
// pub layout: Option<
|
},
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ use legion::prelude::*;
|
|||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
|
|
||||||
pub trait ResourceProvider {
|
pub trait ResourceProvider {
|
||||||
|
fn initialize(&self, renderer: &mut dyn Renderer, world: &mut World);
|
||||||
fn update(&self, renderer: &mut dyn Renderer, world: &mut World);
|
fn update(&self, renderer: &mut dyn Renderer, world: &mut World);
|
||||||
fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32);
|
fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32);
|
||||||
}
|
}
|
||||||
@ -14,6 +15,10 @@ pub trait ResourceProvider {
|
|||||||
pub struct CameraResourceProvider;
|
pub struct CameraResourceProvider;
|
||||||
|
|
||||||
impl ResourceProvider for CameraResourceProvider {
|
impl ResourceProvider for CameraResourceProvider {
|
||||||
|
fn initialize(&self, renderer: &mut dyn Renderer, world: &mut World) {
|
||||||
|
// TODO: create real buffer here
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&self, _renderer: &mut dyn Renderer, _world: &mut World) {}
|
fn update(&self, _renderer: &mut dyn Renderer, _world: &mut World) {}
|
||||||
fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) {
|
fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) {
|
||||||
for (mut camera, local_to_world, _) in
|
for (mut camera, local_to_world, _) in
|
||||||
@ -22,7 +27,7 @@ impl ResourceProvider for CameraResourceProvider {
|
|||||||
camera.update(width, height);
|
camera.update(width, height);
|
||||||
let camera_matrix: [[f32; 4]; 4] =
|
let camera_matrix: [[f32; 4]; 4] =
|
||||||
(camera.view_matrix * local_to_world.0).to_cols_array_2d();
|
(camera.view_matrix * local_to_world.0).to_cols_array_2d();
|
||||||
// TODO: use staging buffer?
|
// TODO: use staging buffer here
|
||||||
renderer.create_buffer_with_data(
|
renderer.create_buffer_with_data(
|
||||||
resource_name::uniform::CAMERA,
|
resource_name::uniform::CAMERA,
|
||||||
camera_matrix.as_bytes(),
|
camera_matrix.as_bytes(),
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
legion::prelude::*,
|
legion::prelude::*,
|
||||||
render::render_graph_2::{
|
render::render_graph_2::{
|
||||||
resource_name, BindType, BufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph,
|
resource_name, BindGroup, BindType, PassDescriptor, PipelineDescriptor, RenderGraph,
|
||||||
RenderPass, RenderPassColorAttachmentDescriptor,
|
RenderPass, RenderPassColorAttachmentDescriptor,
|
||||||
RenderPassDepthStencilAttachmentDescriptor, Renderer, TextureDimension,
|
RenderPassDepthStencilAttachmentDescriptor, Renderer, ResourceInfo, TextureDimension,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, ops::Deref};
|
use std::{
|
||||||
|
collections::{hash_map::DefaultHasher, HashMap},
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
ops::Deref,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct WgpuRenderer {
|
pub struct WgpuRenderer {
|
||||||
pub device: wgpu::Device,
|
pub device: wgpu::Device,
|
||||||
@ -14,8 +18,11 @@ pub struct WgpuRenderer {
|
|||||||
pub surface: Option<wgpu::Surface>,
|
pub surface: Option<wgpu::Surface>,
|
||||||
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
|
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
|
||||||
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
|
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
|
||||||
pub buffers: HashMap<String, Buffer<wgpu::Buffer>>,
|
pub buffers: HashMap<String, wgpu::Buffer>,
|
||||||
pub textures: HashMap<String, wgpu::TextureView>,
|
pub textures: HashMap<String, wgpu::TextureView>,
|
||||||
|
pub resource_info: HashMap<String, ResourceInfo>,
|
||||||
|
pub bind_groups: HashMap<u64, wgpu::BindGroup>,
|
||||||
|
pub bind_group_layouts: HashMap<u64, wgpu::BindGroupLayout>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WgpuRenderer {
|
impl WgpuRenderer {
|
||||||
@ -51,11 +58,15 @@ impl WgpuRenderer {
|
|||||||
render_pipelines: HashMap::new(),
|
render_pipelines: HashMap::new(),
|
||||||
buffers: HashMap::new(),
|
buffers: HashMap::new(),
|
||||||
textures: HashMap::new(),
|
textures: HashMap::new(),
|
||||||
|
resource_info: HashMap::new(),
|
||||||
|
bind_groups: HashMap::new(),
|
||||||
|
bind_group_layouts: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_render_pipeline(
|
pub fn create_render_pipeline(
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
pipeline_descriptor: &PipelineDescriptor,
|
||||||
|
bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>,
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
) -> wgpu::RenderPipeline {
|
) -> wgpu::RenderPipeline {
|
||||||
let vertex_shader_module = pipeline_descriptor
|
let vertex_shader_module = pipeline_descriptor
|
||||||
@ -67,11 +78,12 @@ impl WgpuRenderer {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let bind_group_layouts = pipeline_descriptor
|
// setup new bind group layouts
|
||||||
.pipeline_layout
|
for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter() {
|
||||||
.bind_groups
|
let mut hasher = DefaultHasher::new();
|
||||||
.iter()
|
bind_group.hash(&mut hasher);
|
||||||
.map(|bind_group| {
|
let bind_group_id = hasher.finish();
|
||||||
|
if let None = bind_group_layouts.get(&bind_group_id) {
|
||||||
let bind_group_layout_binding = bind_group
|
let bind_group_layout_binding = bind_group
|
||||||
.bindings
|
.bindings
|
||||||
.iter()
|
.iter()
|
||||||
@ -82,17 +94,32 @@ impl WgpuRenderer {
|
|||||||
ty: (&binding.bind_type).into(),
|
ty: (&binding.bind_type).into(),
|
||||||
})
|
})
|
||||||
.collect::<Vec<wgpu::BindGroupLayoutBinding>>();
|
.collect::<Vec<wgpu::BindGroupLayoutBinding>>();
|
||||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let bind_group_layout =
|
||||||
bindings: bind_group_layout_binding.as_slice(),
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
})
|
bindings: bind_group_layout_binding.as_slice(),
|
||||||
|
});
|
||||||
|
|
||||||
|
bind_group_layouts.insert(bind_group_id, bind_group_layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect bind group layout references
|
||||||
|
let bind_group_layouts = pipeline_descriptor
|
||||||
|
.pipeline_layout
|
||||||
|
.bind_groups
|
||||||
|
.iter()
|
||||||
|
.map(|bind_group| {
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
bind_group.hash(&mut hasher);
|
||||||
|
let bind_group_id = hasher.finish();
|
||||||
|
|
||||||
|
bind_group_layouts.get(&bind_group_id).unwrap()
|
||||||
})
|
})
|
||||||
.collect::<Vec<wgpu::BindGroupLayout>>();
|
.collect::<Vec<&wgpu::BindGroupLayout>>();
|
||||||
|
|
||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
bind_group_layouts: bind_group_layouts
|
bind_group_layouts: bind_group_layouts.as_slice()
|
||||||
.iter()
|
|
||||||
.collect::<Vec<&wgpu::BindGroupLayout>>()
|
|
||||||
.as_slice(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
||||||
@ -198,6 +225,10 @@ impl WgpuRenderer {
|
|||||||
stencil_store_op: depth_stencil_attachment_descriptor.stencil_store_op,
|
stencil_store_op: depth_stencil_attachment_descriptor.stencil_store_op,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_resource_info(&mut self, name: &str, resource_info: ResourceInfo) {
|
||||||
|
self.resource_info.insert(name.to_string(), resource_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for WgpuRenderer {
|
impl Renderer for WgpuRenderer {
|
||||||
@ -244,6 +275,7 @@ impl Renderer for WgpuRenderer {
|
|||||||
if let None = self.render_pipelines.get(pass_pipeline) {
|
if let None = self.render_pipelines.get(pass_pipeline) {
|
||||||
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
||||||
pipeline_descriptor,
|
pipeline_descriptor,
|
||||||
|
&mut self.bind_group_layouts,
|
||||||
&self.device,
|
&self.device,
|
||||||
);
|
);
|
||||||
self.render_pipelines
|
self.render_pipelines
|
||||||
@ -275,25 +307,74 @@ impl Renderer for WgpuRenderer {
|
|||||||
buffer_usage: wgpu::BufferUsage,
|
buffer_usage: wgpu::BufferUsage,
|
||||||
) {
|
) {
|
||||||
let buffer = self.device.create_buffer_with_data(data, buffer_usage);
|
let buffer = self.device.create_buffer_with_data(data, buffer_usage);
|
||||||
self.buffers.insert(
|
self.add_resource_info(
|
||||||
name.to_string(),
|
name,
|
||||||
Buffer {
|
ResourceInfo::Buffer {
|
||||||
buffer,
|
buffer_usage,
|
||||||
buffer_info: BufferInfo {
|
size: data.len() as u64,
|
||||||
buffer_usage,
|
|
||||||
size: data.len() as u64,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.buffers.insert(name.to_string(), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_buffer_info(&self, name: &str) -> Option<&BufferInfo> {
|
fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo> {
|
||||||
self.buffers.get(name).map(|b| &b.buffer_info)
|
self.resource_info.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_buffer(&mut self, name: &str) {
|
fn remove_buffer(&mut self, name: &str) {
|
||||||
self.buffers.remove(name);
|
self.buffers.remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64 {
|
||||||
|
// TODO: cache hash result in bind_group?
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
bind_group.hash(&mut hasher);
|
||||||
|
let bind_group_id = hasher.finish();
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: setup bind group layout
|
||||||
|
if let None = self.bind_groups.get(&bind_group_id) {
|
||||||
|
let bindings = bind_group
|
||||||
|
.bindings
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, b)| wgpu::Binding {
|
||||||
|
binding: i as u32,
|
||||||
|
resource: match &b.bind_type {
|
||||||
|
BindType::Uniform {
|
||||||
|
dynamic,
|
||||||
|
properties,
|
||||||
|
} => {
|
||||||
|
let resource_info = self.resource_info.get(&b.name).unwrap();
|
||||||
|
if let ResourceInfo::Buffer { size, buffer_usage } = resource_info {
|
||||||
|
let buffer = self.buffers.get(&b.name).unwrap();
|
||||||
|
wgpu::BindingResource::Buffer {
|
||||||
|
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);
|
||||||
|
// let bind
|
||||||
|
self.bind_groups.insert(bind_group_id, bind_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
bind_group_id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {
|
pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {
|
||||||
@ -302,7 +383,7 @@ pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {
|
|||||||
pub renderer: &'d mut WgpuRenderer,
|
pub renderer: &'d mut WgpuRenderer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c,'d> {
|
impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
|
||||||
fn get_renderer(&mut self) -> &mut dyn Renderer {
|
fn get_renderer(&mut self) -> &mut dyn Renderer {
|
||||||
self.renderer
|
self.renderer
|
||||||
}
|
}
|
||||||
@ -313,16 +394,41 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c,'d> {
|
|||||||
|
|
||||||
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64) {
|
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64) {
|
||||||
let buffer = self.renderer.buffers.get(name).unwrap();
|
let buffer = self.renderer.buffers.get(name).unwrap();
|
||||||
self.render_pass.set_vertex_buffers(start_slot, &[(&buffer.buffer, offset)]);
|
self.render_pass
|
||||||
|
.set_vertex_buffers(start_slot, &[(&buffer, offset)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_index_buffer(&mut self, name: &str, offset: u64) {
|
fn set_index_buffer(&mut self, name: &str, offset: u64) {
|
||||||
let buffer = self.renderer.buffers.get(name).unwrap();
|
let buffer = self.renderer.buffers.get(name).unwrap();
|
||||||
self.render_pass.set_index_buffer(&buffer.buffer, offset);
|
self.render_pass.set_index_buffer(&buffer, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_indexed(&mut self, indices: core::ops::Range<u32>, base_vertex: i32, instances: core::ops::Range<u32>) {
|
fn draw_indexed(
|
||||||
self.render_pass.draw_indexed(indices, base_vertex, instances);
|
&mut self,
|
||||||
|
indices: core::ops::Range<u32>,
|
||||||
|
base_vertex: i32,
|
||||||
|
instances: core::ops::Range<u32>,
|
||||||
|
) {
|
||||||
|
self.render_pass
|
||||||
|
.draw_indexed(indices, base_vertex, instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: maybe move setup to renderer.setup_bind_groups(&pipeline_desc);
|
||||||
|
fn setup_bind_groups(&mut self) {
|
||||||
|
for (i, bind_group) in self
|
||||||
|
.pipeline_descriptor
|
||||||
|
.pipeline_layout
|
||||||
|
.bind_groups
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
let id = self.renderer.setup_bind_group(bind_group);
|
||||||
|
self.render_pass.set_bind_group(
|
||||||
|
i as u32,
|
||||||
|
self.renderer.bind_groups.get(&id).unwrap(),
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,8 +470,3 @@ impl From<&BindType> for wgpu::BindingType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Buffer<T> {
|
|
||||||
pub buffer: T,
|
|
||||||
pub buffer_info: BufferInfo,
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user