Bind group layout entries (#10224)
# Objective
- Follow up to #9694
## Solution
- Same api as #9694 but adapted for `BindGroupLayoutEntry`
- Use the same `ShaderStages` visibilty for all entries by default
- Add `BindingType` helper function that mirror the wgsl equivalent and
that make writing layouts much simpler.
Before:
```rust
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some("post_process_bind_group_layout"),
entries: &[
BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
sample_type: TextureSampleType::Float { filterable: true },
view_dimension: TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
BindGroupLayoutEntry {
binding: 1,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Filtering),
count: None,
},
BindGroupLayoutEntry {
binding: 2,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Buffer {
ty: bevy::render::render_resource::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: Some(PostProcessSettings::min_size()),
},
count: None,
},
],
});
```
After:
```rust
let layout = render_device.create_bind_group_layout(
"post_process_bind_group_layout"),
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d_f32(),
sampler(SamplerBindingType::Filtering),
uniform_buffer(false, Some(PostProcessSettings::min_size())),
),
),
);
```
Here's a more extreme example in bevy_solari:
86dab7f5da
---
## Changelog
- Added `BindGroupLayoutEntries` and all `BindingType` helper functions.
## Migration Guide
`RenderDevice::create_bind_group_layout()` doesn't take a
`BindGroupLayoutDescriptor` anymore. You need to provide the parameters
separately
```rust
// 0.12
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some("post_process_bind_group_layout"),
entries: &[
BindGroupLayoutEntry {
// ...
},
],
});
// 0.13
let layout = render_device.create_bind_group_layout(
"post_process_bind_group_layout",
&[
BindGroupLayoutEntry {
// ...
},
],
);
```
## TODO
- [x] implement a `Dynamic` variant
- [x] update the `RenderDevice::create_bind_group_layout()` api to match
the one from `RenderDevice::creat_bind_group()`
- [x] docs
This commit is contained in:
parent
f0a8994f55
commit
6d0c11a28f
@ -1,7 +1,14 @@
|
|||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{load_internal_asset, Handle};
|
use bevy_asset::{load_internal_asset, Handle};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_render::{render_resource::*, renderer::RenderDevice, RenderApp};
|
use bevy_render::{
|
||||||
|
render_resource::{
|
||||||
|
binding_types::{sampler, texture_2d},
|
||||||
|
*,
|
||||||
|
},
|
||||||
|
renderer::RenderDevice,
|
||||||
|
RenderApp,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
|
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
|
||||||
|
|
||||||
@ -36,28 +43,16 @@ impl FromWorld for BlitPipeline {
|
|||||||
fn from_world(render_world: &mut World) -> Self {
|
fn from_world(render_world: &mut World) -> Self {
|
||||||
let render_device = render_world.resource::<RenderDevice>();
|
let render_device = render_world.resource::<RenderDevice>();
|
||||||
|
|
||||||
let texture_bind_group =
|
let texture_bind_group = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"blit_bind_group_layout",
|
||||||
label: Some("blit_bind_group_layout"),
|
&BindGroupLayoutEntries::sequential(
|
||||||
entries: &[
|
ShaderStages::FRAGMENT,
|
||||||
BindGroupLayoutEntry {
|
(
|
||||||
binding: 0,
|
texture_2d(TextureSampleType::Float { filterable: false }),
|
||||||
visibility: ShaderStages::FRAGMENT,
|
sampler(SamplerBindingType::NonFiltering),
|
||||||
ty: BindingType::Texture {
|
),
|
||||||
sample_type: TextureSampleType::Float { filterable: false },
|
),
|
||||||
view_dimension: TextureViewDimension::D2,
|
);
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::NonFiltering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
|
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,13 @@ use bevy_ecs::{
|
|||||||
world::{FromWorld, World},
|
world::{FromWorld, World},
|
||||||
};
|
};
|
||||||
use bevy_math::Vec4;
|
use bevy_math::Vec4;
|
||||||
use bevy_render::{render_resource::*, renderer::RenderDevice};
|
use bevy_render::{
|
||||||
|
render_resource::{
|
||||||
|
binding_types::{sampler, texture_2d, uniform_buffer},
|
||||||
|
*,
|
||||||
|
},
|
||||||
|
renderer::RenderDevice,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct BloomDownsamplingPipelineIds {
|
pub struct BloomDownsamplingPipelineIds {
|
||||||
@ -41,44 +47,21 @@ impl FromWorld for BloomDownsamplingPipeline {
|
|||||||
fn from_world(world: &mut World) -> Self {
|
fn from_world(world: &mut World) -> Self {
|
||||||
let render_device = world.resource::<RenderDevice>();
|
let render_device = world.resource::<RenderDevice>();
|
||||||
|
|
||||||
// Input texture binding
|
|
||||||
let texture = BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
count: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Sampler binding
|
|
||||||
let sampler = BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
count: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Downsampling settings binding
|
|
||||||
let settings = BindGroupLayoutEntry {
|
|
||||||
binding: 2,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(BloomUniforms::min_size()),
|
|
||||||
},
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
count: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Bind group layout
|
// Bind group layout
|
||||||
let bind_group_layout =
|
let bind_group_layout = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"bloom_downsampling_bind_group_layout_with_settings",
|
||||||
label: Some("bloom_downsampling_bind_group_layout_with_settings"),
|
&BindGroupLayoutEntries::sequential(
|
||||||
entries: &[texture, sampler, settings],
|
ShaderStages::FRAGMENT,
|
||||||
});
|
(
|
||||||
|
// Input texture binding
|
||||||
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
|
// Sampler binding
|
||||||
|
sampler(SamplerBindingType::Filtering),
|
||||||
|
// Downsampling settings binding
|
||||||
|
uniform_buffer::<BloomUniforms>(true),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// Sampler
|
// Sampler
|
||||||
let sampler = render_device.create_sampler(&SamplerDescriptor {
|
let sampler = render_device.create_sampler(&SamplerDescriptor {
|
||||||
|
|||||||
@ -8,7 +8,14 @@ use bevy_ecs::{
|
|||||||
system::{Commands, Query, Res, ResMut, Resource},
|
system::{Commands, Query, Res, ResMut, Resource},
|
||||||
world::{FromWorld, World},
|
world::{FromWorld, World},
|
||||||
};
|
};
|
||||||
use bevy_render::{render_resource::*, renderer::RenderDevice, view::ViewTarget};
|
use bevy_render::{
|
||||||
|
render_resource::{
|
||||||
|
binding_types::{sampler, texture_2d, uniform_buffer},
|
||||||
|
*,
|
||||||
|
},
|
||||||
|
renderer::RenderDevice,
|
||||||
|
view::ViewTarget,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct UpsamplingPipelineIds {
|
pub struct UpsamplingPipelineIds {
|
||||||
@ -31,41 +38,20 @@ impl FromWorld for BloomUpsamplingPipeline {
|
|||||||
fn from_world(world: &mut World) -> Self {
|
fn from_world(world: &mut World) -> Self {
|
||||||
let render_device = world.resource::<RenderDevice>();
|
let render_device = world.resource::<RenderDevice>();
|
||||||
|
|
||||||
let bind_group_layout =
|
let bind_group_layout = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"bloom_upsampling_bind_group_layout",
|
||||||
label: Some("bloom_upsampling_bind_group_layout"),
|
&BindGroupLayoutEntries::sequential(
|
||||||
entries: &[
|
ShaderStages::FRAGMENT,
|
||||||
|
(
|
||||||
// Input texture
|
// Input texture
|
||||||
BindGroupLayoutEntry {
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
binding: 0,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Sampler
|
// Sampler
|
||||||
BindGroupLayoutEntry {
|
sampler(SamplerBindingType::Filtering),
|
||||||
binding: 1,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// BloomUniforms
|
// BloomUniforms
|
||||||
BindGroupLayoutEntry {
|
uniform_buffer::<BloomUniforms>(true),
|
||||||
binding: 2,
|
),
|
||||||
ty: BindingType::Buffer {
|
),
|
||||||
ty: BufferBindingType::Uniform,
|
);
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(BloomUniforms::min_size()),
|
|
||||||
},
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
BloomUpsamplingPipeline { bind_group_layout }
|
BloomUpsamplingPipeline { bind_group_layout }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,10 @@ use bevy_render::{
|
|||||||
extract_component::{ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin},
|
extract_component::{ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin},
|
||||||
prelude::Camera,
|
prelude::Camera,
|
||||||
render_graph::RenderGraphApp,
|
render_graph::RenderGraphApp,
|
||||||
render_resource::*,
|
render_resource::{
|
||||||
|
binding_types::{sampler, texture_2d, uniform_buffer},
|
||||||
|
*,
|
||||||
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::BevyDefault,
|
texture::BevyDefault,
|
||||||
view::{ExtractedView, ViewTarget},
|
view::{ExtractedView, ViewTarget},
|
||||||
@ -169,39 +172,18 @@ pub struct CASPipeline {
|
|||||||
impl FromWorld for CASPipeline {
|
impl FromWorld for CASPipeline {
|
||||||
fn from_world(render_world: &mut World) -> Self {
|
fn from_world(render_world: &mut World) -> Self {
|
||||||
let render_device = render_world.resource::<RenderDevice>();
|
let render_device = render_world.resource::<RenderDevice>();
|
||||||
let texture_bind_group =
|
let texture_bind_group = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"sharpening_texture_bind_group_layout",
|
||||||
label: Some("sharpening_texture_bind_group_layout"),
|
&BindGroupLayoutEntries::sequential(
|
||||||
entries: &[
|
ShaderStages::FRAGMENT,
|
||||||
BindGroupLayoutEntry {
|
(
|
||||||
binding: 0,
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
visibility: ShaderStages::FRAGMENT,
|
sampler(SamplerBindingType::Filtering),
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// CAS Settings
|
// CAS Settings
|
||||||
BindGroupLayoutEntry {
|
uniform_buffer::<CASUniform>(true),
|
||||||
binding: 2,
|
),
|
||||||
ty: BindingType::Buffer {
|
),
|
||||||
ty: BufferBindingType::Uniform,
|
);
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(CASUniform::min_size()),
|
|
||||||
},
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
|
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use bevy_ecs::prelude::*;
|
|||||||
use bevy_math::UVec2;
|
use bevy_math::UVec2;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::ExtractedCamera,
|
camera::ExtractedCamera,
|
||||||
render_resource::*,
|
render_resource::{binding_types::texture_2d, *},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::{CachedTexture, TextureCache},
|
texture::{CachedTexture, TextureCache},
|
||||||
view::ViewTarget,
|
view::ViewTarget,
|
||||||
@ -128,19 +128,13 @@ impl FromWorld for CopyDeferredLightingIdPipeline {
|
|||||||
fn from_world(world: &mut World) -> Self {
|
fn from_world(world: &mut World) -> Self {
|
||||||
let render_device = world.resource::<RenderDevice>();
|
let render_device = world.resource::<RenderDevice>();
|
||||||
|
|
||||||
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let layout = render_device.create_bind_group_layout(
|
||||||
label: Some("copy_deferred_lighting_id_bind_group_layout"),
|
"copy_deferred_lighting_id_bind_group_layout",
|
||||||
entries: &[BindGroupLayoutEntry {
|
&BindGroupLayoutEntries::single(
|
||||||
binding: 0,
|
ShaderStages::FRAGMENT,
|
||||||
visibility: ShaderStages::FRAGMENT,
|
texture_2d(TextureSampleType::Uint),
|
||||||
ty: BindingType::Texture {
|
),
|
||||||
sample_type: TextureSampleType::Uint,
|
);
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
|
|
||||||
let pipeline_id =
|
let pipeline_id =
|
||||||
world
|
world
|
||||||
|
|||||||
@ -13,7 +13,10 @@ use bevy_render::{
|
|||||||
prelude::Camera,
|
prelude::Camera,
|
||||||
render_graph::RenderGraphApp,
|
render_graph::RenderGraphApp,
|
||||||
render_graph::ViewNodeRunner,
|
render_graph::ViewNodeRunner,
|
||||||
render_resource::*,
|
render_resource::{
|
||||||
|
binding_types::{sampler, texture_2d},
|
||||||
|
*,
|
||||||
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::BevyDefault,
|
texture::BevyDefault,
|
||||||
view::{ExtractedView, ViewTarget},
|
view::{ExtractedView, ViewTarget},
|
||||||
@ -131,27 +134,16 @@ impl FromWorld for FxaaPipeline {
|
|||||||
fn from_world(render_world: &mut World) -> Self {
|
fn from_world(render_world: &mut World) -> Self {
|
||||||
let texture_bind_group = render_world
|
let texture_bind_group = render_world
|
||||||
.resource::<RenderDevice>()
|
.resource::<RenderDevice>()
|
||||||
.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
.create_bind_group_layout(
|
||||||
label: Some("fxaa_texture_bind_group_layout"),
|
"fxaa_texture_bind_group_layout",
|
||||||
entries: &[
|
&BindGroupLayoutEntries::sequential(
|
||||||
BindGroupLayoutEntry {
|
ShaderStages::FRAGMENT,
|
||||||
binding: 0,
|
(
|
||||||
visibility: ShaderStages::FRAGMENT,
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
ty: BindingType::Texture {
|
sampler(SamplerBindingType::Filtering),
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
),
|
||||||
view_dimension: TextureViewDimension::D2,
|
),
|
||||||
multisampled: false,
|
);
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
FxaaPipeline { texture_bind_group }
|
FxaaPipeline { texture_bind_group }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,13 +10,13 @@ use bevy_render::{
|
|||||||
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor,
|
binding_types::{sampler, texture_cube, uniform_buffer},
|
||||||
BindGroupLayoutEntry, BindingType, BufferBindingType, CachedRenderPipelineId,
|
BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries,
|
||||||
ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState,
|
CachedRenderPipelineId, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState,
|
||||||
FragmentState, MultisampleState, PipelineCache, PrimitiveState, RenderPipelineDescriptor,
|
DepthStencilState, FragmentState, MultisampleState, PipelineCache, PrimitiveState,
|
||||||
SamplerBindingType, Shader, ShaderStages, ShaderType, SpecializedRenderPipeline,
|
RenderPipelineDescriptor, SamplerBindingType, Shader, ShaderStages,
|
||||||
SpecializedRenderPipelines, StencilFaceState, StencilState, TextureFormat,
|
SpecializedRenderPipeline, SpecializedRenderPipelines, StencilFaceState, StencilState,
|
||||||
TextureSampleType, TextureViewDimension, VertexState,
|
TextureFormat, TextureSampleType, VertexState,
|
||||||
},
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::{BevyDefault, Image},
|
texture::{BevyDefault, Image},
|
||||||
@ -80,41 +80,19 @@ struct SkyboxPipeline {
|
|||||||
|
|
||||||
impl SkyboxPipeline {
|
impl SkyboxPipeline {
|
||||||
fn new(render_device: &RenderDevice) -> Self {
|
fn new(render_device: &RenderDevice) -> Self {
|
||||||
let bind_group_layout_descriptor = BindGroupLayoutDescriptor {
|
|
||||||
label: Some("skybox_bind_group_layout"),
|
|
||||||
entries: &[
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::Cube,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 2,
|
|
||||||
visibility: ShaderStages::VERTEX_FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
bind_group_layout: render_device
|
bind_group_layout: render_device.create_bind_group_layout(
|
||||||
.create_bind_group_layout(&bind_group_layout_descriptor),
|
"skybox_bind_group_layout",
|
||||||
|
&BindGroupLayoutEntries::sequential(
|
||||||
|
ShaderStages::FRAGMENT,
|
||||||
|
(
|
||||||
|
texture_cube(TextureSampleType::Float { filterable: true }),
|
||||||
|
sampler(SamplerBindingType::Filtering),
|
||||||
|
uniform_buffer::<ViewUniform>(true)
|
||||||
|
.visibility(ShaderStages::VERTEX_FRAGMENT),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,13 +21,13 @@ use bevy_render::{
|
|||||||
prelude::{Camera, Projection},
|
prelude::{Camera, Projection},
|
||||||
render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner},
|
render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
|
binding_types::{sampler, texture_2d, texture_depth_2d},
|
||||||
BindingType, CachedRenderPipelineId, ColorTargetState, ColorWrites, Extent3d, FilterMode,
|
BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries, CachedRenderPipelineId,
|
||||||
FragmentState, MultisampleState, Operations, PipelineCache, PrimitiveState,
|
ColorTargetState, ColorWrites, Extent3d, FilterMode, FragmentState, MultisampleState,
|
||||||
RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineDescriptor, Sampler,
|
Operations, PipelineCache, PrimitiveState, RenderPassColorAttachment, RenderPassDescriptor,
|
||||||
SamplerBindingType, SamplerDescriptor, Shader, ShaderStages, SpecializedRenderPipeline,
|
RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor, Shader,
|
||||||
SpecializedRenderPipelines, TextureDescriptor, TextureDimension, TextureFormat,
|
ShaderStages, SpecializedRenderPipeline, SpecializedRenderPipelines, TextureDescriptor,
|
||||||
TextureSampleType, TextureUsages, TextureViewDimension,
|
TextureDimension, TextureFormat, TextureSampleType, TextureUsages,
|
||||||
},
|
},
|
||||||
renderer::{RenderContext, RenderDevice},
|
renderer::{RenderContext, RenderDevice},
|
||||||
texture::{BevyDefault, CachedTexture, TextureCache},
|
texture::{BevyDefault, CachedTexture, TextureCache},
|
||||||
@ -266,70 +266,26 @@ impl FromWorld for TaaPipeline {
|
|||||||
..SamplerDescriptor::default()
|
..SamplerDescriptor::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
let taa_bind_group_layout =
|
let taa_bind_group_layout = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"taa_bind_group_layout",
|
||||||
label: Some("taa_bind_group_layout"),
|
&BindGroupLayoutEntries::sequential(
|
||||||
entries: &[
|
ShaderStages::FRAGMENT,
|
||||||
|
(
|
||||||
// View target (read)
|
// View target (read)
|
||||||
BindGroupLayoutEntry {
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
binding: 0,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// TAA History (read)
|
// TAA History (read)
|
||||||
BindGroupLayoutEntry {
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Motion Vectors
|
// Motion Vectors
|
||||||
BindGroupLayoutEntry {
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
binding: 2,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Depth
|
// Depth
|
||||||
BindGroupLayoutEntry {
|
texture_depth_2d(),
|
||||||
binding: 3,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Depth,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Nearest sampler
|
// Nearest sampler
|
||||||
BindGroupLayoutEntry {
|
sampler(SamplerBindingType::NonFiltering),
|
||||||
binding: 4,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::NonFiltering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Linear sampler
|
// Linear sampler
|
||||||
BindGroupLayoutEntry {
|
sampler(SamplerBindingType::Filtering),
|
||||||
binding: 5,
|
),
|
||||||
visibility: ShaderStages::FRAGMENT,
|
),
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
);
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
TaaPipeline {
|
TaaPipeline {
|
||||||
taa_bind_group_layout,
|
taa_bind_group_layout,
|
||||||
|
|||||||
@ -7,6 +7,9 @@ use bevy_render::camera::Camera;
|
|||||||
use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin};
|
use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin};
|
||||||
use bevy_render::extract_resource::{ExtractResource, ExtractResourcePlugin};
|
use bevy_render::extract_resource::{ExtractResource, ExtractResourcePlugin};
|
||||||
use bevy_render::render_asset::RenderAssets;
|
use bevy_render::render_asset::RenderAssets;
|
||||||
|
use bevy_render::render_resource::binding_types::{
|
||||||
|
sampler, texture_2d, texture_3d, uniform_buffer,
|
||||||
|
};
|
||||||
use bevy_render::renderer::RenderDevice;
|
use bevy_render::renderer::RenderDevice;
|
||||||
use bevy_render::texture::{CompressedImageFormats, Image, ImageSampler, ImageType};
|
use bevy_render::texture::{CompressedImageFormats, Image, ImageSampler, ImageType};
|
||||||
use bevy_render::view::{ViewTarget, ViewUniform};
|
use bevy_render::view::{ViewTarget, ViewUniform};
|
||||||
@ -248,42 +251,24 @@ impl SpecializedRenderPipeline for TonemappingPipeline {
|
|||||||
|
|
||||||
impl FromWorld for TonemappingPipeline {
|
impl FromWorld for TonemappingPipeline {
|
||||||
fn from_world(render_world: &mut World) -> Self {
|
fn from_world(render_world: &mut World) -> Self {
|
||||||
let mut entries = vec![
|
let mut entries = DynamicBindGroupLayoutEntries::new_with_indices(
|
||||||
BindGroupLayoutEntry {
|
ShaderStages::FRAGMENT,
|
||||||
binding: 0,
|
(
|
||||||
visibility: ShaderStages::FRAGMENT,
|
(0, uniform_buffer::<ViewUniform>(true)),
|
||||||
ty: BindingType::Buffer {
|
(
|
||||||
ty: BufferBindingType::Uniform,
|
1,
|
||||||
has_dynamic_offset: true,
|
texture_2d(TextureSampleType::Float { filterable: false }),
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
),
|
||||||
},
|
(2, sampler(SamplerBindingType::NonFiltering)),
|
||||||
count: None,
|
),
|
||||||
},
|
);
|
||||||
BindGroupLayoutEntry {
|
let lut_layout_entries = get_lut_bind_group_layout_entries();
|
||||||
binding: 1,
|
entries =
|
||||||
visibility: ShaderStages::FRAGMENT,
|
entries.extend_with_indices(((3, lut_layout_entries[0]), (4, lut_layout_entries[1])));
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: false },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 2,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::NonFiltering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
entries.extend(get_lut_bind_group_layout_entries([3, 4]));
|
|
||||||
|
|
||||||
let tonemap_texture_bind_group = render_world
|
let tonemap_texture_bind_group = render_world
|
||||||
.resource::<RenderDevice>()
|
.resource::<RenderDevice>()
|
||||||
.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
.create_bind_group_layout("tonemapping_hdr_texture_bind_group_layout", &entries);
|
||||||
label: Some("tonemapping_hdr_texture_bind_group_layout"),
|
|
||||||
entries: &entries,
|
|
||||||
});
|
|
||||||
|
|
||||||
TonemappingPipeline {
|
TonemappingPipeline {
|
||||||
texture_bind_group: tonemap_texture_bind_group,
|
texture_bind_group: tonemap_texture_bind_group,
|
||||||
@ -345,24 +330,10 @@ pub fn get_lut_bindings<'a>(
|
|||||||
(&lut_image.texture_view, &lut_image.sampler)
|
(&lut_image.texture_view, &lut_image.sampler)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_lut_bind_group_layout_entries(bindings: [u32; 2]) -> [BindGroupLayoutEntry; 2] {
|
pub fn get_lut_bind_group_layout_entries() -> [BindGroupLayoutEntryBuilder; 2] {
|
||||||
[
|
[
|
||||||
BindGroupLayoutEntry {
|
texture_3d(TextureSampleType::Float { filterable: true }),
|
||||||
binding: bindings[0],
|
sampler(SamplerBindingType::Filtering),
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::D3,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: bindings[1],
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -54,10 +54,9 @@ use bevy_render::{
|
|||||||
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets},
|
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets},
|
||||||
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
|
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor,
|
binding_types::uniform_buffer, BindGroup, BindGroupEntries, BindGroupLayout,
|
||||||
BindGroupLayoutEntry, BindingType, Buffer, BufferBindingType, BufferInitDescriptor,
|
BindGroupLayoutEntries, Buffer, BufferInitDescriptor, BufferUsages, Shader, ShaderStages,
|
||||||
BufferUsages, Shader, ShaderStages, ShaderType, VertexAttribute, VertexBufferLayout,
|
ShaderType, VertexAttribute, VertexBufferLayout, VertexFormat, VertexStepMode,
|
||||||
VertexFormat, VertexStepMode,
|
|
||||||
},
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
view::RenderLayers,
|
view::RenderLayers,
|
||||||
@ -120,19 +119,13 @@ impl Plugin for GizmoPlugin {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let render_device = render_app.world.resource::<RenderDevice>();
|
let render_device = render_app.world.resource::<RenderDevice>();
|
||||||
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let layout = render_device.create_bind_group_layout(
|
||||||
entries: &[BindGroupLayoutEntry {
|
"LineGizmoUniform layout",
|
||||||
binding: 0,
|
&BindGroupLayoutEntries::single(
|
||||||
visibility: ShaderStages::VERTEX,
|
ShaderStages::VERTEX,
|
||||||
ty: BindingType::Buffer {
|
uniform_buffer::<LineGizmoUniform>(true),
|
||||||
ty: BufferBindingType::Uniform,
|
),
|
||||||
has_dynamic_offset: true,
|
);
|
||||||
min_binding_size: Some(LineGizmoUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
label: Some("LineGizmoUniform layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
render_app.insert_resource(LineGizmoUniformBindgroupLayout { layout });
|
render_app.insert_resource(LineGizmoUniformBindgroupLayout { layout });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,9 @@ use bevy_render::{
|
|||||||
},
|
},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_graph::{NodeRunError, RenderGraphContext, ViewNode, ViewNodeRunner},
|
render_graph::{NodeRunError, RenderGraphContext, ViewNode, ViewNodeRunner},
|
||||||
render_resource::{self, Operations, PipelineCache, RenderPassDescriptor},
|
render_resource::{
|
||||||
|
binding_types::uniform_buffer, Operations, PipelineCache, RenderPassDescriptor,
|
||||||
|
},
|
||||||
renderer::{RenderContext, RenderDevice},
|
renderer::{RenderContext, RenderDevice},
|
||||||
texture::Image,
|
texture::Image,
|
||||||
view::{ViewTarget, ViewUniformOffset},
|
view::{ViewTarget, ViewUniformOffset},
|
||||||
@ -376,19 +378,13 @@ impl SpecializedRenderPipeline for DeferredLightingLayout {
|
|||||||
impl FromWorld for DeferredLightingLayout {
|
impl FromWorld for DeferredLightingLayout {
|
||||||
fn from_world(world: &mut World) -> Self {
|
fn from_world(world: &mut World) -> Self {
|
||||||
let render_device = world.resource::<RenderDevice>();
|
let render_device = world.resource::<RenderDevice>();
|
||||||
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let layout = render_device.create_bind_group_layout(
|
||||||
label: Some("deferred_lighting_layout"),
|
"deferred_lighting_layout",
|
||||||
entries: &[BindGroupLayoutEntry {
|
&BindGroupLayoutEntries::single(
|
||||||
binding: 0,
|
ShaderStages::VERTEX_FRAGMENT,
|
||||||
visibility: ShaderStages::VERTEX_FRAGMENT,
|
uniform_buffer::<PbrDeferredLightingDepthId>(false),
|
||||||
ty: BindingType::Buffer {
|
),
|
||||||
ty: render_resource::BufferBindingType::Uniform,
|
);
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(PbrDeferredLightingDepthId::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
Self {
|
Self {
|
||||||
mesh_pipeline: world.resource::<MeshPipeline>().clone(),
|
mesh_pipeline: world.resource::<MeshPipeline>().clone(),
|
||||||
bind_group_layout_1: layout,
|
bind_group_layout_1: layout,
|
||||||
|
|||||||
@ -6,7 +6,10 @@ use bevy_reflect::Reflect;
|
|||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_resource::*,
|
render_resource::{
|
||||||
|
binding_types::{sampler, texture_cube},
|
||||||
|
*,
|
||||||
|
},
|
||||||
texture::{FallbackImageCubemap, Image},
|
texture::{FallbackImageCubemap, Image},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,33 +82,10 @@ pub fn get_bindings<'a>(
|
|||||||
(diffuse_map, specular_map, &fallback_image_cubemap.sampler)
|
(diffuse_map, specular_map, &fallback_image_cubemap.sampler)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bind_group_layout_entries(bindings: [u32; 3]) -> [BindGroupLayoutEntry; 3] {
|
pub fn get_bind_group_layout_entries() -> [BindGroupLayoutEntryBuilder; 3] {
|
||||||
[
|
[
|
||||||
BindGroupLayoutEntry {
|
texture_cube(TextureSampleType::Float { filterable: true }),
|
||||||
binding: bindings[0],
|
texture_cube(TextureSampleType::Float { filterable: true }),
|
||||||
visibility: ShaderStages::FRAGMENT,
|
sampler(SamplerBindingType::Filtering),
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::Cube,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: bindings[1],
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: TextureViewDimension::Cube,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: bindings[2],
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
mod prepass_bindings;
|
mod prepass_bindings;
|
||||||
|
|
||||||
|
use bevy_render::render_resource::binding_types::uniform_buffer;
|
||||||
pub use prepass_bindings::*;
|
pub use prepass_bindings::*;
|
||||||
|
|
||||||
use bevy_app::{Plugin, PreUpdate};
|
use bevy_app::{Plugin, PreUpdate};
|
||||||
@ -229,74 +230,33 @@ impl<M: Material> FromWorld for PrepassPipeline<M> {
|
|||||||
let render_device = world.resource::<RenderDevice>();
|
let render_device = world.resource::<RenderDevice>();
|
||||||
let asset_server = world.resource::<AssetServer>();
|
let asset_server = world.resource::<AssetServer>();
|
||||||
|
|
||||||
let view_layout_motion_vectors =
|
let view_layout_motion_vectors = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"prepass_view_layout_motion_vectors",
|
||||||
entries: &[
|
&BindGroupLayoutEntries::sequential(
|
||||||
|
ShaderStages::VERTEX_FRAGMENT,
|
||||||
|
(
|
||||||
// View
|
// View
|
||||||
BindGroupLayoutEntry {
|
uniform_buffer::<ViewUniform>(true),
|
||||||
binding: 0,
|
|
||||||
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Globals
|
// Globals
|
||||||
BindGroupLayoutEntry {
|
uniform_buffer::<GlobalsUniform>(false),
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::VERTEX_FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(GlobalsUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// PreviousViewProjection
|
// PreviousViewProjection
|
||||||
BindGroupLayoutEntry {
|
uniform_buffer::<PreviousViewProjection>(true),
|
||||||
binding: 2,
|
),
|
||||||
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
|
),
|
||||||
ty: BindingType::Buffer {
|
);
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(PreviousViewProjection::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("prepass_view_layout_motion_vectors"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let view_layout_no_motion_vectors =
|
let view_layout_no_motion_vectors = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"prepass_view_layout_no_motion_vectors",
|
||||||
entries: &[
|
&BindGroupLayoutEntries::sequential(
|
||||||
|
ShaderStages::VERTEX_FRAGMENT,
|
||||||
|
(
|
||||||
// View
|
// View
|
||||||
BindGroupLayoutEntry {
|
uniform_buffer::<ViewUniform>(true),
|
||||||
binding: 0,
|
|
||||||
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Globals
|
// Globals
|
||||||
BindGroupLayoutEntry {
|
uniform_buffer::<GlobalsUniform>(false),
|
||||||
binding: 1,
|
),
|
||||||
visibility: ShaderStages::VERTEX_FRAGMENT,
|
),
|
||||||
ty: BindingType::Buffer {
|
);
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(GlobalsUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("prepass_view_layout_no_motion_vectors"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let mesh_pipeline = world.resource::<MeshPipeline>();
|
let mesh_pipeline = world.resource::<MeshPipeline>();
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
use bevy_core_pipeline::prepass::ViewPrepassTextures;
|
use bevy_core_pipeline::prepass::ViewPrepassTextures;
|
||||||
use bevy_render::render_resource::{
|
use bevy_render::render_resource::{
|
||||||
BindGroupLayoutEntry, BindingType, ShaderStages, TextureAspect, TextureSampleType, TextureView,
|
binding_types::{
|
||||||
TextureViewDescriptor, TextureViewDimension,
|
texture_2d, texture_2d_multisampled, texture_depth_2d, texture_depth_2d_multisampled,
|
||||||
|
},
|
||||||
|
BindGroupLayoutEntryBuilder, TextureAspect, TextureSampleType, TextureView,
|
||||||
|
TextureViewDescriptor,
|
||||||
};
|
};
|
||||||
use bevy_utils::default;
|
use bevy_utils::default;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@ -9,25 +12,19 @@ use smallvec::SmallVec;
|
|||||||
use crate::MeshPipelineViewLayoutKey;
|
use crate::MeshPipelineViewLayoutKey;
|
||||||
|
|
||||||
pub fn get_bind_group_layout_entries(
|
pub fn get_bind_group_layout_entries(
|
||||||
bindings: [u32; 4],
|
|
||||||
layout_key: MeshPipelineViewLayoutKey,
|
layout_key: MeshPipelineViewLayoutKey,
|
||||||
) -> SmallVec<[BindGroupLayoutEntry; 4]> {
|
) -> SmallVec<[BindGroupLayoutEntryBuilder; 4]> {
|
||||||
let mut result = SmallVec::<[BindGroupLayoutEntry; 4]>::new();
|
let mut result = SmallVec::<[BindGroupLayoutEntryBuilder; 4]>::new();
|
||||||
|
|
||||||
let multisampled = layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED);
|
let multisampled = layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED);
|
||||||
|
|
||||||
if layout_key.contains(MeshPipelineViewLayoutKey::DEPTH_PREPASS) {
|
if layout_key.contains(MeshPipelineViewLayoutKey::DEPTH_PREPASS) {
|
||||||
result.push(
|
result.push(
|
||||||
// Depth texture
|
// Depth texture
|
||||||
BindGroupLayoutEntry {
|
if multisampled {
|
||||||
binding: bindings[0],
|
texture_depth_2d_multisampled()
|
||||||
visibility: ShaderStages::FRAGMENT,
|
} else {
|
||||||
ty: BindingType::Texture {
|
texture_depth_2d()
|
||||||
multisampled,
|
|
||||||
sample_type: TextureSampleType::Depth,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -35,15 +32,10 @@ pub fn get_bind_group_layout_entries(
|
|||||||
if layout_key.contains(MeshPipelineViewLayoutKey::NORMAL_PREPASS) {
|
if layout_key.contains(MeshPipelineViewLayoutKey::NORMAL_PREPASS) {
|
||||||
result.push(
|
result.push(
|
||||||
// Normal texture
|
// Normal texture
|
||||||
BindGroupLayoutEntry {
|
if multisampled {
|
||||||
binding: bindings[1],
|
texture_2d_multisampled(TextureSampleType::Float { filterable: false })
|
||||||
visibility: ShaderStages::FRAGMENT,
|
} else {
|
||||||
ty: BindingType::Texture {
|
texture_2d(TextureSampleType::Float { filterable: false })
|
||||||
multisampled,
|
|
||||||
sample_type: TextureSampleType::Float { filterable: false },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -51,15 +43,10 @@ pub fn get_bind_group_layout_entries(
|
|||||||
if layout_key.contains(MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS) {
|
if layout_key.contains(MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS) {
|
||||||
result.push(
|
result.push(
|
||||||
// Motion Vectors texture
|
// Motion Vectors texture
|
||||||
BindGroupLayoutEntry {
|
if multisampled {
|
||||||
binding: bindings[2],
|
texture_2d_multisampled(TextureSampleType::Float { filterable: false })
|
||||||
visibility: ShaderStages::FRAGMENT,
|
} else {
|
||||||
ty: BindingType::Texture {
|
texture_2d(TextureSampleType::Float { filterable: false })
|
||||||
multisampled,
|
|
||||||
sample_type: TextureSampleType::Float { filterable: false },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -67,16 +54,7 @@ pub fn get_bind_group_layout_entries(
|
|||||||
if layout_key.contains(MeshPipelineViewLayoutKey::DEFERRED_PREPASS) {
|
if layout_key.contains(MeshPipelineViewLayoutKey::DEFERRED_PREPASS) {
|
||||||
result.push(
|
result.push(
|
||||||
// Deferred texture
|
// Deferred texture
|
||||||
BindGroupLayoutEntry {
|
texture_2d(TextureSampleType::Uint),
|
||||||
binding: bindings[3],
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
multisampled: false,
|
|
||||||
sample_type: TextureSampleType::Uint,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,50 +17,28 @@ mod layout_entry {
|
|||||||
use crate::MeshUniform;
|
use crate::MeshUniform;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BindGroupLayoutEntry, BindingType, BufferBindingType, BufferSize, GpuArrayBuffer,
|
binding_types::{texture_3d, uniform_buffer_sized},
|
||||||
ShaderStages, TextureSampleType, TextureViewDimension,
|
BindGroupLayoutEntryBuilder, BufferSize, GpuArrayBuffer, ShaderStages,
|
||||||
|
TextureSampleType,
|
||||||
},
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn buffer(binding: u32, size: u64, visibility: ShaderStages) -> BindGroupLayoutEntry {
|
pub(super) fn model(render_device: &RenderDevice) -> BindGroupLayoutEntryBuilder {
|
||||||
BindGroupLayoutEntry {
|
GpuArrayBuffer::<MeshUniform>::binding_layout(render_device)
|
||||||
binding,
|
.visibility(ShaderStages::VERTEX_FRAGMENT)
|
||||||
visibility,
|
|
||||||
count: None,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: BufferSize::new(size),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub(super) fn model(render_device: &RenderDevice, binding: u32) -> BindGroupLayoutEntry {
|
pub(super) fn skinning() -> BindGroupLayoutEntryBuilder {
|
||||||
GpuArrayBuffer::<MeshUniform>::binding_layout(
|
uniform_buffer_sized(true, BufferSize::new(JOINT_BUFFER_SIZE as u64))
|
||||||
binding,
|
|
||||||
ShaderStages::VERTEX_FRAGMENT,
|
|
||||||
render_device,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
pub(super) fn skinning(binding: u32) -> BindGroupLayoutEntry {
|
pub(super) fn weights() -> BindGroupLayoutEntryBuilder {
|
||||||
buffer(binding, JOINT_BUFFER_SIZE as u64, ShaderStages::VERTEX)
|
uniform_buffer_sized(true, BufferSize::new(MORPH_BUFFER_SIZE as u64))
|
||||||
}
|
}
|
||||||
pub(super) fn weights(binding: u32) -> BindGroupLayoutEntry {
|
pub(super) fn targets() -> BindGroupLayoutEntryBuilder {
|
||||||
buffer(binding, MORPH_BUFFER_SIZE as u64, ShaderStages::VERTEX)
|
texture_3d(TextureSampleType::Float { filterable: false })
|
||||||
}
|
|
||||||
pub(super) fn targets(binding: u32) -> BindGroupLayoutEntry {
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding,
|
|
||||||
visibility: ShaderStages::VERTEX,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
view_dimension: TextureViewDimension::D3,
|
|
||||||
sample_type: TextureSampleType::Float { filterable: false },
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Individual [`BindGroupEntry`]
|
/// Individual [`BindGroupEntry`]
|
||||||
/// for bind groups.
|
/// for bind groups.
|
||||||
mod entry {
|
mod entry {
|
||||||
@ -133,40 +111,52 @@ impl MeshLayouts {
|
|||||||
// ---------- create individual BindGroupLayouts ----------
|
// ---------- create individual BindGroupLayouts ----------
|
||||||
|
|
||||||
fn model_only_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
fn model_only_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
render_device.create_bind_group_layout(
|
||||||
entries: &[layout_entry::model(render_device, 0)],
|
"mesh_layout",
|
||||||
label: Some("mesh_layout"),
|
&BindGroupLayoutEntries::single(
|
||||||
})
|
ShaderStages::empty(),
|
||||||
|
layout_entry::model(render_device),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
render_device.create_bind_group_layout(
|
||||||
entries: &[
|
"skinned_mesh_layout",
|
||||||
layout_entry::model(render_device, 0),
|
&BindGroupLayoutEntries::with_indices(
|
||||||
layout_entry::skinning(1),
|
ShaderStages::VERTEX,
|
||||||
],
|
(
|
||||||
label: Some("skinned_mesh_layout"),
|
(0, layout_entry::model(render_device)),
|
||||||
})
|
(1, layout_entry::skinning()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
render_device.create_bind_group_layout(
|
||||||
entries: &[
|
"morphed_mesh_layout",
|
||||||
layout_entry::model(render_device, 0),
|
&BindGroupLayoutEntries::with_indices(
|
||||||
layout_entry::weights(2),
|
ShaderStages::VERTEX,
|
||||||
layout_entry::targets(3),
|
(
|
||||||
],
|
(0, layout_entry::model(render_device)),
|
||||||
label: Some("morphed_mesh_layout"),
|
(2, layout_entry::weights()),
|
||||||
})
|
(3, layout_entry::targets()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
render_device.create_bind_group_layout(
|
||||||
entries: &[
|
"morphed_skinned_mesh_layout",
|
||||||
layout_entry::model(render_device, 0),
|
&BindGroupLayoutEntries::with_indices(
|
||||||
layout_entry::skinning(1),
|
ShaderStages::VERTEX,
|
||||||
layout_entry::weights(2),
|
(
|
||||||
layout_entry::targets(3),
|
(0, layout_entry::model(render_device)),
|
||||||
],
|
(1, layout_entry::skinning()),
|
||||||
label: Some("morphed_skinned_mesh_layout"),
|
(2, layout_entry::weights()),
|
||||||
})
|
(3, layout_entry::targets()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- BindGroup methods ----------
|
// ---------- BindGroup methods ----------
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::array;
|
use std::{array, num::NonZeroU64};
|
||||||
|
|
||||||
use bevy_core_pipeline::{
|
use bevy_core_pipeline::{
|
||||||
core_3d::ViewTransmissionTexture,
|
core_3d::ViewTransmissionTexture,
|
||||||
@ -16,15 +16,24 @@ use bevy_render::{
|
|||||||
globals::{GlobalsBuffer, GlobalsUniform},
|
globals::{GlobalsBuffer, GlobalsUniform},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BindGroup, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType,
|
binding_types::{
|
||||||
BufferBindingType, DynamicBindGroupEntries, SamplerBindingType, ShaderStages, ShaderType,
|
sampler, storage_buffer_read_only_sized, storage_buffer_sized, texture_2d,
|
||||||
TextureFormat, TextureSampleType, TextureViewDimension,
|
uniform_buffer, uniform_buffer_sized,
|
||||||
|
},
|
||||||
|
BindGroup, BindGroupLayout, BindGroupLayoutEntry, BindGroupLayoutEntryBuilder, BindingType,
|
||||||
|
BufferBindingType, DynamicBindGroupEntries, DynamicBindGroupLayoutEntries,
|
||||||
|
SamplerBindingType, ShaderStages, TextureFormat, TextureSampleType,
|
||||||
},
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::{BevyDefault, FallbackImageCubemap, FallbackImageMsaa, FallbackImageZero, Image},
|
texture::{BevyDefault, FallbackImageCubemap, FallbackImageMsaa, FallbackImageZero, Image},
|
||||||
view::{Msaa, ViewUniform, ViewUniforms},
|
view::{Msaa, ViewUniform, ViewUniforms},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "webgl", target_arch = "wasm32"))]
|
||||||
|
use bevy_render::render_resource::binding_types::texture_cube;
|
||||||
|
#[cfg(any(not(feature = "webgl"), not(target_arch = "wasm32")))]
|
||||||
|
use bevy_render::render_resource::binding_types::{texture_2d_array, texture_cube_array};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
environment_map, prepass, EnvironmentMapLight, FogMeta, GlobalLightMeta, GpuFog, GpuLights,
|
environment_map, prepass, EnvironmentMapLight, FogMeta, GlobalLightMeta, GpuFog, GpuLights,
|
||||||
GpuPointLights, LightMeta, MeshPipeline, MeshPipelineKey, ScreenSpaceAmbientOcclusionTextures,
|
GpuPointLights, LightMeta, MeshPipeline, MeshPipelineKey, ScreenSpaceAmbientOcclusionTextures,
|
||||||
@ -144,190 +153,141 @@ impl From<Option<&ViewPrepassTextures>> for MeshPipelineViewLayoutKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn buffer_layout(
|
||||||
|
buffer_binding_type: BufferBindingType,
|
||||||
|
has_dynamic_offset: bool,
|
||||||
|
min_binding_size: Option<NonZeroU64>,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
match buffer_binding_type {
|
||||||
|
BufferBindingType::Uniform => uniform_buffer_sized(has_dynamic_offset, min_binding_size),
|
||||||
|
BufferBindingType::Storage { read_only } => {
|
||||||
|
if read_only {
|
||||||
|
storage_buffer_read_only_sized(has_dynamic_offset, min_binding_size)
|
||||||
|
} else {
|
||||||
|
storage_buffer_sized(has_dynamic_offset, min_binding_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the appropriate bind group layout vec based on the parameters
|
/// Returns the appropriate bind group layout vec based on the parameters
|
||||||
fn layout_entries(
|
fn layout_entries(
|
||||||
clustered_forward_buffer_binding_type: BufferBindingType,
|
clustered_forward_buffer_binding_type: BufferBindingType,
|
||||||
layout_key: MeshPipelineViewLayoutKey,
|
layout_key: MeshPipelineViewLayoutKey,
|
||||||
) -> Vec<BindGroupLayoutEntry> {
|
) -> Vec<BindGroupLayoutEntry> {
|
||||||
let mut entries = vec![
|
let mut entries = DynamicBindGroupLayoutEntries::new_with_indices(
|
||||||
// View
|
ShaderStages::FRAGMENT,
|
||||||
BindGroupLayoutEntry {
|
(
|
||||||
binding: 0,
|
// View
|
||||||
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
|
(
|
||||||
ty: BindingType::Buffer {
|
0,
|
||||||
ty: BufferBindingType::Uniform,
|
uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),
|
||||||
has_dynamic_offset: true,
|
),
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
// Lights
|
||||||
},
|
(1, uniform_buffer::<GpuLights>(true)),
|
||||||
count: None,
|
// Point Shadow Texture Cube Array
|
||||||
},
|
(
|
||||||
// Lights
|
2,
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(GpuLights::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Point Shadow Texture Cube Array
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 2,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
multisampled: false,
|
|
||||||
sample_type: TextureSampleType::Depth,
|
|
||||||
#[cfg(any(not(feature = "webgl"), not(target_arch = "wasm32")))]
|
#[cfg(any(not(feature = "webgl"), not(target_arch = "wasm32")))]
|
||||||
view_dimension: TextureViewDimension::CubeArray,
|
texture_cube_array(TextureSampleType::Depth),
|
||||||
#[cfg(all(feature = "webgl", target_arch = "wasm32"))]
|
#[cfg(all(feature = "webgl", target_arch = "wasm32"))]
|
||||||
view_dimension: TextureViewDimension::Cube,
|
texture_cube(TextureSampleType::Depth),
|
||||||
},
|
),
|
||||||
count: None,
|
// Point Shadow Texture Array Sampler
|
||||||
},
|
(3, sampler(SamplerBindingType::Comparison)),
|
||||||
// Point Shadow Texture Array Sampler
|
// Directional Shadow Texture Array
|
||||||
BindGroupLayoutEntry {
|
(
|
||||||
binding: 3,
|
4,
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Comparison),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Directional Shadow Texture Array
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 4,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
multisampled: false,
|
|
||||||
sample_type: TextureSampleType::Depth,
|
|
||||||
#[cfg(any(not(feature = "webgl"), not(target_arch = "wasm32")))]
|
#[cfg(any(not(feature = "webgl"), not(target_arch = "wasm32")))]
|
||||||
view_dimension: TextureViewDimension::D2Array,
|
texture_2d_array(TextureSampleType::Depth),
|
||||||
#[cfg(all(feature = "webgl", target_arch = "wasm32"))]
|
#[cfg(all(feature = "webgl", target_arch = "wasm32"))]
|
||||||
view_dimension: TextureViewDimension::D2,
|
texture_2d(TextureSampleType::Depth),
|
||||||
},
|
),
|
||||||
count: None,
|
// Directional Shadow Texture Array Sampler
|
||||||
},
|
(5, sampler(SamplerBindingType::Comparison)),
|
||||||
// Directional Shadow Texture Array Sampler
|
// PointLights
|
||||||
BindGroupLayoutEntry {
|
(
|
||||||
binding: 5,
|
6,
|
||||||
visibility: ShaderStages::FRAGMENT,
|
buffer_layout(
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Comparison),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// PointLights
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 6,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: clustered_forward_buffer_binding_type,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(GpuPointLights::min_size(
|
|
||||||
clustered_forward_buffer_binding_type,
|
clustered_forward_buffer_binding_type,
|
||||||
)),
|
false,
|
||||||
},
|
Some(GpuPointLights::min_size(
|
||||||
count: None,
|
clustered_forward_buffer_binding_type,
|
||||||
},
|
)),
|
||||||
// ClusteredLightIndexLists
|
),
|
||||||
BindGroupLayoutEntry {
|
),
|
||||||
binding: 7,
|
// ClusteredLightIndexLists
|
||||||
visibility: ShaderStages::FRAGMENT,
|
(
|
||||||
ty: BindingType::Buffer {
|
7,
|
||||||
ty: clustered_forward_buffer_binding_type,
|
buffer_layout(
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(ViewClusterBindings::min_size_cluster_light_index_lists(
|
|
||||||
clustered_forward_buffer_binding_type,
|
clustered_forward_buffer_binding_type,
|
||||||
)),
|
false,
|
||||||
},
|
Some(ViewClusterBindings::min_size_cluster_light_index_lists(
|
||||||
count: None,
|
clustered_forward_buffer_binding_type,
|
||||||
},
|
)),
|
||||||
// ClusterOffsetsAndCounts
|
),
|
||||||
BindGroupLayoutEntry {
|
),
|
||||||
binding: 8,
|
// ClusterOffsetsAndCounts
|
||||||
visibility: ShaderStages::FRAGMENT,
|
(
|
||||||
ty: BindingType::Buffer {
|
8,
|
||||||
ty: clustered_forward_buffer_binding_type,
|
buffer_layout(
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(ViewClusterBindings::min_size_cluster_offsets_and_counts(
|
|
||||||
clustered_forward_buffer_binding_type,
|
clustered_forward_buffer_binding_type,
|
||||||
)),
|
false,
|
||||||
},
|
Some(ViewClusterBindings::min_size_cluster_offsets_and_counts(
|
||||||
count: None,
|
clustered_forward_buffer_binding_type,
|
||||||
},
|
)),
|
||||||
// Globals
|
),
|
||||||
BindGroupLayoutEntry {
|
),
|
||||||
binding: 9,
|
// Globals
|
||||||
visibility: ShaderStages::VERTEX_FRAGMENT,
|
(9, uniform_buffer::<GlobalsUniform>(false)),
|
||||||
ty: BindingType::Buffer {
|
// Fog
|
||||||
ty: BufferBindingType::Uniform,
|
(10, uniform_buffer::<GpuFog>(true)),
|
||||||
has_dynamic_offset: false,
|
// Screen space ambient occlusion texture
|
||||||
min_binding_size: Some(GlobalsUniform::min_size()),
|
(
|
||||||
},
|
11,
|
||||||
count: None,
|
texture_2d(TextureSampleType::Float { filterable: false }),
|
||||||
},
|
),
|
||||||
// Fog
|
),
|
||||||
BindGroupLayoutEntry {
|
);
|
||||||
binding: 10,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(GpuFog::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// Screen space ambient occlusion texture
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 11,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
multisampled: false,
|
|
||||||
sample_type: TextureSampleType::Float { filterable: false },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// EnvironmentMapLight
|
// EnvironmentMapLight
|
||||||
let environment_map_entries = environment_map::get_bind_group_layout_entries([12, 13, 14]);
|
let environment_map_entries = environment_map::get_bind_group_layout_entries();
|
||||||
entries.extend_from_slice(&environment_map_entries);
|
entries = entries.extend_with_indices((
|
||||||
|
(12, environment_map_entries[0]),
|
||||||
|
(13, environment_map_entries[1]),
|
||||||
|
(14, environment_map_entries[2]),
|
||||||
|
));
|
||||||
|
|
||||||
// Tonemapping
|
// Tonemapping
|
||||||
let tonemapping_lut_entries = get_lut_bind_group_layout_entries([15, 16]);
|
let tonemapping_lut_entries = get_lut_bind_group_layout_entries();
|
||||||
entries.extend_from_slice(&tonemapping_lut_entries);
|
entries = entries.extend_with_indices((
|
||||||
|
(15, tonemapping_lut_entries[0]),
|
||||||
|
(16, tonemapping_lut_entries[1]),
|
||||||
|
));
|
||||||
|
|
||||||
// Prepass
|
// Prepass
|
||||||
if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32")))
|
if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32")))
|
||||||
|| (cfg!(all(feature = "webgl", target_arch = "wasm32"))
|
|| (cfg!(all(feature = "webgl", target_arch = "wasm32"))
|
||||||
&& !layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED))
|
&& !layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED))
|
||||||
{
|
{
|
||||||
entries.extend_from_slice(&prepass::get_bind_group_layout_entries(
|
for (entry, binding) in prepass::get_bind_group_layout_entries(layout_key)
|
||||||
[17, 18, 19, 20],
|
.iter()
|
||||||
layout_key,
|
.zip([17, 18, 19, 20])
|
||||||
));
|
{
|
||||||
|
entries = entries.extend_with_indices(((binding as u32, *entry),));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// View Transmission Texture
|
// View Transmission Texture
|
||||||
entries.extend_from_slice(&[
|
entries = entries.extend_with_indices((
|
||||||
BindGroupLayoutEntry {
|
(
|
||||||
binding: 21,
|
21,
|
||||||
visibility: ShaderStages::FRAGMENT,
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
ty: BindingType::Texture {
|
),
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
(22, sampler(SamplerBindingType::Filtering)),
|
||||||
multisampled: false,
|
));
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 22,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
entries
|
entries.to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates all possible view layouts for the mesh pipeline, based on all combinations of
|
/// Generates all possible view layouts for the mesh pipeline, based on all combinations of
|
||||||
@ -347,10 +307,8 @@ pub fn generate_view_layouts(
|
|||||||
.count();
|
.count();
|
||||||
|
|
||||||
MeshPipelineViewLayout {
|
MeshPipelineViewLayout {
|
||||||
bind_group_layout: render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
bind_group_layout: render_device
|
||||||
label: Some(key.label().as_str()),
|
.create_bind_group_layout(key.label().as_str(), &entries),
|
||||||
entries: &entries,
|
|
||||||
}),
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
texture_count,
|
texture_count,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,12 @@ use bevy_render::{
|
|||||||
globals::{GlobalsBuffer, GlobalsUniform},
|
globals::{GlobalsBuffer, GlobalsUniform},
|
||||||
prelude::Camera,
|
prelude::Camera,
|
||||||
render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner},
|
render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner},
|
||||||
render_resource::*,
|
render_resource::{
|
||||||
|
binding_types::{
|
||||||
|
sampler, texture_2d, texture_depth_2d, texture_storage_2d, uniform_buffer,
|
||||||
|
},
|
||||||
|
*,
|
||||||
|
},
|
||||||
renderer::{RenderAdapter, RenderContext, RenderDevice, RenderQueue},
|
renderer::{RenderAdapter, RenderContext, RenderDevice, RenderQueue},
|
||||||
texture::{CachedTexture, TextureCache},
|
texture::{CachedTexture, TextureCache},
|
||||||
view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms},
|
view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms},
|
||||||
@ -345,176 +350,58 @@ impl FromWorld for SsaoPipelines {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
let common_bind_group_layout =
|
let common_bind_group_layout = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"ssao_common_bind_group_layout",
|
||||||
label: Some("ssao_common_bind_group_layout"),
|
&BindGroupLayoutEntries::sequential(
|
||||||
entries: &[
|
ShaderStages::COMPUTE,
|
||||||
BindGroupLayoutEntry {
|
(
|
||||||
binding: 0,
|
sampler(SamplerBindingType::NonFiltering),
|
||||||
visibility: ShaderStages::COMPUTE,
|
uniform_buffer::<ViewUniform>(true),
|
||||||
ty: BindingType::Sampler(SamplerBindingType::NonFiltering),
|
),
|
||||||
count: None,
|
),
|
||||||
},
|
);
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
let mip_texture_entry = BindGroupLayoutEntry {
|
let preprocess_depth_bind_group_layout = render_device.create_bind_group_layout(
|
||||||
binding: 1,
|
"ssao_preprocess_depth_bind_group_layout",
|
||||||
visibility: ShaderStages::COMPUTE,
|
&BindGroupLayoutEntries::sequential(
|
||||||
ty: BindingType::StorageTexture {
|
ShaderStages::COMPUTE,
|
||||||
access: StorageTextureAccess::WriteOnly,
|
(
|
||||||
format: TextureFormat::R16Float,
|
texture_depth_2d(),
|
||||||
view_dimension: TextureViewDimension::D2,
|
texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly),
|
||||||
},
|
texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly),
|
||||||
count: None,
|
texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly),
|
||||||
};
|
texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly),
|
||||||
let preprocess_depth_bind_group_layout =
|
texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly),
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
),
|
||||||
label: Some("ssao_preprocess_depth_bind_group_layout"),
|
),
|
||||||
entries: &[
|
);
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Depth,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
mip_texture_entry,
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 2,
|
|
||||||
..mip_texture_entry
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 3,
|
|
||||||
..mip_texture_entry
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 4,
|
|
||||||
..mip_texture_entry
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 5,
|
|
||||||
..mip_texture_entry
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
let gtao_bind_group_layout =
|
let gtao_bind_group_layout = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"ssao_gtao_bind_group_layout",
|
||||||
label: Some("ssao_gtao_bind_group_layout"),
|
&BindGroupLayoutEntries::sequential(
|
||||||
entries: &[
|
ShaderStages::COMPUTE,
|
||||||
BindGroupLayoutEntry {
|
(
|
||||||
binding: 0,
|
texture_2d(TextureSampleType::Float { filterable: false }),
|
||||||
visibility: ShaderStages::COMPUTE,
|
texture_2d(TextureSampleType::Float { filterable: false }),
|
||||||
ty: BindingType::Texture {
|
texture_2d(TextureSampleType::Uint),
|
||||||
sample_type: TextureSampleType::Float { filterable: false },
|
texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly),
|
||||||
view_dimension: TextureViewDimension::D2,
|
texture_storage_2d(TextureFormat::R32Uint, StorageTextureAccess::WriteOnly),
|
||||||
multisampled: false,
|
uniform_buffer::<GlobalsUniform>(false),
|
||||||
},
|
),
|
||||||
count: None,
|
),
|
||||||
},
|
);
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Float { filterable: false },
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 2,
|
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Uint,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 3,
|
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::StorageTexture {
|
|
||||||
access: StorageTextureAccess::WriteOnly,
|
|
||||||
format: TextureFormat::R16Float,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 4,
|
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::StorageTexture {
|
|
||||||
access: StorageTextureAccess::WriteOnly,
|
|
||||||
format: TextureFormat::R32Uint,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 5,
|
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(GlobalsUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
let spatial_denoise_bind_group_layout =
|
let spatial_denoise_bind_group_layout = render_device.create_bind_group_layout(
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
"ssao_spatial_denoise_bind_group_layout",
|
||||||
label: Some("ssao_spatial_denoise_bind_group_layout"),
|
&BindGroupLayoutEntries::sequential(
|
||||||
entries: &[
|
ShaderStages::COMPUTE,
|
||||||
BindGroupLayoutEntry {
|
(
|
||||||
binding: 0,
|
texture_2d(TextureSampleType::Float { filterable: false }),
|
||||||
visibility: ShaderStages::COMPUTE,
|
texture_2d(TextureSampleType::Uint),
|
||||||
ty: BindingType::Texture {
|
texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly),
|
||||||
sample_type: TextureSampleType::Float { filterable: false },
|
),
|
||||||
view_dimension: TextureViewDimension::D2,
|
),
|
||||||
multisampled: false,
|
);
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::Texture {
|
|
||||||
sample_type: TextureSampleType::Uint,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 2,
|
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::StorageTexture {
|
|
||||||
access: StorageTextureAccess::WriteOnly,
|
|
||||||
format: TextureFormat::R16Float,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
let preprocess_depth_pipeline =
|
let preprocess_depth_pipeline =
|
||||||
pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
|
pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ pub use bevy_render_macros::AsBindGroup;
|
|||||||
use bevy_utils::thiserror::Error;
|
use bevy_utils::thiserror::Error;
|
||||||
use encase::ShaderType;
|
use encase::ShaderType;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use wgpu::{BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource};
|
use wgpu::{BindGroupEntry, BindGroupLayoutEntry, BindingResource};
|
||||||
|
|
||||||
define_atomic_id!(BindGroupId);
|
define_atomic_id!(BindGroupId);
|
||||||
render_resource_wrapper!(ErasedBindGroup, wgpu::BindGroup);
|
render_resource_wrapper!(ErasedBindGroup, wgpu::BindGroup);
|
||||||
@ -313,10 +313,10 @@ pub trait AsBindGroup {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
render_device.create_bind_group_layout(
|
||||||
label: Self::label(),
|
Self::label(),
|
||||||
entries: &Self::bind_group_layout_entries(render_device),
|
&Self::bind_group_layout_entries(render_device),
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a vec of bind group layout entries
|
/// Returns a vec of bind group layout entries
|
||||||
|
|||||||
@ -0,0 +1,546 @@
|
|||||||
|
use bevy_utils::all_tuples_with_size;
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
use wgpu::{BindGroupLayoutEntry, BindingType, ShaderStages};
|
||||||
|
|
||||||
|
/// Helper for constructing bind group layouts.
|
||||||
|
///
|
||||||
|
/// Allows constructing the layout's entries as:
|
||||||
|
/// ```ignore
|
||||||
|
/// let layout = render_device.create_bind_group_layout(
|
||||||
|
/// "my_bind_group_layout",
|
||||||
|
/// &BindGroupLayoutEntries::with_indices(
|
||||||
|
/// // The layout entries will only be visible in the fragment stage
|
||||||
|
/// ShaderStages::FRAGMENT,
|
||||||
|
/// (
|
||||||
|
/// // Screen texture
|
||||||
|
/// (2, tepxture_2d(TextureSampleType::Float { filterable: true })),
|
||||||
|
/// // Sampler
|
||||||
|
/// (3, sampler(SamplerBindingType::Filtering)),
|
||||||
|
/// ),
|
||||||
|
/// ),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// instead of
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let layout = render_device.create_bind_group_layout(
|
||||||
|
/// "my_bind_group_layout",
|
||||||
|
/// &[
|
||||||
|
/// // Screen texture
|
||||||
|
/// BindGroupLayoutEntry {
|
||||||
|
/// binding: 2,
|
||||||
|
/// visibility: ShaderStages::FRAGMENT,
|
||||||
|
/// ty: BindingType::Texture {
|
||||||
|
/// sample_type: TextureSampleType::Float { filterable: true },
|
||||||
|
/// view_dimension: TextureViewDimension::D2,
|
||||||
|
/// multisampled: false,
|
||||||
|
/// },
|
||||||
|
/// count: None,
|
||||||
|
/// },
|
||||||
|
/// // Sampler
|
||||||
|
/// BindGroupLayoutEntry {
|
||||||
|
/// binding: 3,
|
||||||
|
/// visibility: ShaderStages::FRAGMENT,
|
||||||
|
/// ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
||||||
|
/// count: None,
|
||||||
|
/// },
|
||||||
|
/// ],
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// or
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// render_device.create_bind_group_layout(
|
||||||
|
/// "my_bind_group_layout",
|
||||||
|
/// &BindGroupLayoutEntries::sequential(
|
||||||
|
/// ShaderStages::FRAGMENT,
|
||||||
|
/// (
|
||||||
|
/// // Screen texture
|
||||||
|
/// texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
|
/// // Sampler
|
||||||
|
/// sampler(SamplerBindingType::Filtering),
|
||||||
|
/// ),
|
||||||
|
/// ),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// instead of
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let layout = render_device.create_bind_group_layout(
|
||||||
|
/// "my_bind_group_layout",
|
||||||
|
/// &[
|
||||||
|
/// // Screen texture
|
||||||
|
/// BindGroupLayoutEntry {
|
||||||
|
/// binding: 0,
|
||||||
|
/// visibility: ShaderStages::FRAGMENT,
|
||||||
|
/// ty: BindingType::Texture {
|
||||||
|
/// sample_type: TextureSampleType::Float { filterable: true },
|
||||||
|
/// view_dimension: TextureViewDimension::D2,
|
||||||
|
/// multisampled: false,
|
||||||
|
/// },
|
||||||
|
/// count: None,
|
||||||
|
/// },
|
||||||
|
/// // Sampler
|
||||||
|
/// BindGroupLayoutEntry {
|
||||||
|
/// binding: 1,
|
||||||
|
/// visibility: ShaderStages::FRAGMENT,
|
||||||
|
/// ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
||||||
|
/// count: None,
|
||||||
|
/// },
|
||||||
|
/// ],
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// or
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// render_device.create_bind_group_layout(
|
||||||
|
/// "my_bind_group_layout",
|
||||||
|
/// &BindGroupLayoutEntries::single(
|
||||||
|
/// ShaderStages::FRAGMENT,
|
||||||
|
/// texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
|
/// ),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// instead of
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let layout = render_device.create_bind_group_layout(
|
||||||
|
/// "my_bind_group_layout",
|
||||||
|
/// &[
|
||||||
|
/// BindGroupLayoutEntry {
|
||||||
|
/// binding: 0,
|
||||||
|
/// visibility: ShaderStages::FRAGMENT,
|
||||||
|
/// ty: BindingType::Texture {
|
||||||
|
/// sample_type: TextureSampleType::Float { filterable: true },
|
||||||
|
/// view_dimension: TextureViewDimension::D2,
|
||||||
|
/// multisampled: false,
|
||||||
|
/// },
|
||||||
|
/// count: None,
|
||||||
|
/// },
|
||||||
|
/// ],
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct BindGroupLayoutEntryBuilder {
|
||||||
|
ty: BindingType,
|
||||||
|
visibility: Option<ShaderStages>,
|
||||||
|
count: Option<NonZeroU32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BindGroupLayoutEntryBuilder {
|
||||||
|
pub fn visibility(mut self, visibility: ShaderStages) -> Self {
|
||||||
|
self.visibility = Some(visibility);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn count(mut self, count: NonZeroU32) -> Self {
|
||||||
|
self.count = Some(count);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(
|
||||||
|
&self,
|
||||||
|
binding: u32,
|
||||||
|
default_visibility: ShaderStages,
|
||||||
|
) -> wgpu::BindGroupLayoutEntry {
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding,
|
||||||
|
ty: self.ty,
|
||||||
|
visibility: self.visibility.unwrap_or(default_visibility),
|
||||||
|
count: self.count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BindGroupLayoutEntries<const N: usize> {
|
||||||
|
entries: [wgpu::BindGroupLayoutEntry; N],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> BindGroupLayoutEntries<N> {
|
||||||
|
#[inline]
|
||||||
|
pub fn sequential(
|
||||||
|
default_visibility: ShaderStages,
|
||||||
|
entries_ext: impl IntoBindGroupLayoutEntryBuilderArray<N>,
|
||||||
|
) -> Self {
|
||||||
|
let mut i = 0;
|
||||||
|
Self {
|
||||||
|
entries: entries_ext.into_array().map(|entry| {
|
||||||
|
let binding = i;
|
||||||
|
i += 1;
|
||||||
|
entry.build(binding, default_visibility)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_indices(
|
||||||
|
default_visibility: ShaderStages,
|
||||||
|
indexed_entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
entries: indexed_entries
|
||||||
|
.into_array()
|
||||||
|
.map(|(binding, entry)| entry.build(binding, default_visibility)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BindGroupLayoutEntries<1> {
|
||||||
|
pub fn single(
|
||||||
|
visibility: ShaderStages,
|
||||||
|
resource: impl IntoBindGroupLayoutEntryBuilder,
|
||||||
|
) -> [BindGroupLayoutEntry; 1] {
|
||||||
|
[resource
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
.build(0, visibility)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> std::ops::Deref for BindGroupLayoutEntries<N> {
|
||||||
|
type Target = [wgpu::BindGroupLayoutEntry];
|
||||||
|
fn deref(&self) -> &[wgpu::BindGroupLayoutEntry] {
|
||||||
|
&self.entries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoBindGroupLayoutEntryBuilder {
|
||||||
|
fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoBindGroupLayoutEntryBuilder for BindingType {
|
||||||
|
fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindGroupLayoutEntryBuilder {
|
||||||
|
ty: self,
|
||||||
|
visibility: None,
|
||||||
|
count: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoBindGroupLayoutEntryBuilder for wgpu::BindGroupLayoutEntry {
|
||||||
|
fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder {
|
||||||
|
if self.binding != u32::MAX {
|
||||||
|
bevy_log::warn!("The BindGroupLayoutEntries api ignores the binding index when converting a raw wgpu::BindGroupLayoutEntry. You can ignore this warning by setting it to u32::MAX.");
|
||||||
|
}
|
||||||
|
BindGroupLayoutEntryBuilder {
|
||||||
|
ty: self.ty,
|
||||||
|
visibility: Some(self.visibility),
|
||||||
|
count: self.count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoBindGroupLayoutEntryBuilder for BindGroupLayoutEntryBuilder {
|
||||||
|
fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoBindGroupLayoutEntryBuilderArray<const N: usize> {
|
||||||
|
fn into_array(self) -> [BindGroupLayoutEntryBuilder; N];
|
||||||
|
}
|
||||||
|
macro_rules! impl_to_binding_type_slice {
|
||||||
|
($N: expr, $(($T: ident, $I: ident)),*) => {
|
||||||
|
impl<$($T: IntoBindGroupLayoutEntryBuilder),*> IntoBindGroupLayoutEntryBuilderArray<$N> for ($($T,)*) {
|
||||||
|
#[inline]
|
||||||
|
fn into_array(self) -> [BindGroupLayoutEntryBuilder; $N] {
|
||||||
|
let ($($I,)*) = self;
|
||||||
|
[$($I.into_bind_group_layout_entry_builder(), )*]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all_tuples_with_size!(impl_to_binding_type_slice, 1, 32, T, s);
|
||||||
|
|
||||||
|
pub trait IntoIndexedBindGroupLayoutEntryBuilderArray<const N: usize> {
|
||||||
|
fn into_array(self) -> [(u32, BindGroupLayoutEntryBuilder); N];
|
||||||
|
}
|
||||||
|
macro_rules! impl_to_indexed_binding_type_slice {
|
||||||
|
($N: expr, $(($T: ident, $S: ident, $I: ident)),*) => {
|
||||||
|
impl<$($T: IntoBindGroupLayoutEntryBuilder),*> IntoIndexedBindGroupLayoutEntryBuilderArray<$N> for ($((u32, $T),)*) {
|
||||||
|
#[inline]
|
||||||
|
fn into_array(self) -> [(u32, BindGroupLayoutEntryBuilder); $N] {
|
||||||
|
let ($(($S, $I),)*) = self;
|
||||||
|
[$(($S, $I.into_bind_group_layout_entry_builder())), *]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all_tuples_with_size!(impl_to_indexed_binding_type_slice, 1, 32, T, n, s);
|
||||||
|
|
||||||
|
impl<const N: usize> IntoBindGroupLayoutEntryBuilderArray<N> for [BindGroupLayoutEntry; N] {
|
||||||
|
fn into_array(self) -> [BindGroupLayoutEntryBuilder; N] {
|
||||||
|
self.map(|x| x.into_bind_group_layout_entry_builder())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DynamicBindGroupLayoutEntries {
|
||||||
|
default_visibility: ShaderStages,
|
||||||
|
entries: Vec<BindGroupLayoutEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynamicBindGroupLayoutEntries {
|
||||||
|
pub fn sequential<const N: usize>(
|
||||||
|
default_visibility: ShaderStages,
|
||||||
|
entries: impl IntoBindGroupLayoutEntryBuilderArray<N>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
default_visibility,
|
||||||
|
entries: entries
|
||||||
|
.into_array()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(ix, resource)| resource.build(ix as u32, default_visibility))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend_sequential<const N: usize>(
|
||||||
|
mut self,
|
||||||
|
entries: impl IntoBindGroupLayoutEntryBuilderArray<N>,
|
||||||
|
) -> Self {
|
||||||
|
let start = self.entries.last().unwrap().binding + 1;
|
||||||
|
self.entries.extend(
|
||||||
|
entries
|
||||||
|
.into_array()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(ix, resource)| resource.build(start + ix as u32, self.default_visibility)),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_indices<const N: usize>(
|
||||||
|
default_visibility: ShaderStages,
|
||||||
|
entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
default_visibility,
|
||||||
|
entries: entries
|
||||||
|
.into_array()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(binding, resource)| resource.build(binding, default_visibility))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend_with_indices<const N: usize>(
|
||||||
|
mut self,
|
||||||
|
entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,
|
||||||
|
) -> Self {
|
||||||
|
self.entries.extend(
|
||||||
|
entries
|
||||||
|
.into_array()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(binding, resource)| resource.build(binding, self.default_visibility)),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for DynamicBindGroupLayoutEntries {
|
||||||
|
type Target = [BindGroupLayoutEntry];
|
||||||
|
|
||||||
|
fn deref(&self) -> &[BindGroupLayoutEntry] {
|
||||||
|
&self.entries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod binding_types {
|
||||||
|
use crate::render_resource::{
|
||||||
|
BufferBindingType, SamplerBindingType, TextureSampleType, TextureViewDimension,
|
||||||
|
};
|
||||||
|
use encase::ShaderType;
|
||||||
|
use std::num::NonZeroU64;
|
||||||
|
use wgpu::{BindingType, StorageTextureAccess, TextureFormat};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub fn storage_buffer<T: ShaderType>(has_dynamic_offset: bool) -> BindGroupLayoutEntryBuilder {
|
||||||
|
storage_buffer_sized(has_dynamic_offset, Some(T::min_size()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn storage_buffer_sized(
|
||||||
|
has_dynamic_offset: bool,
|
||||||
|
min_binding_size: Option<NonZeroU64>,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Buffer {
|
||||||
|
ty: BufferBindingType::Storage { read_only: false },
|
||||||
|
has_dynamic_offset,
|
||||||
|
min_binding_size,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn storage_buffer_read_only<T: ShaderType>(
|
||||||
|
has_dynamic_offset: bool,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
storage_buffer_read_only_sized(has_dynamic_offset, Some(T::min_size()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn storage_buffer_read_only_sized(
|
||||||
|
has_dynamic_offset: bool,
|
||||||
|
min_binding_size: Option<NonZeroU64>,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Buffer {
|
||||||
|
ty: BufferBindingType::Storage { read_only: true },
|
||||||
|
has_dynamic_offset,
|
||||||
|
min_binding_size,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uniform_buffer<T: ShaderType>(has_dynamic_offset: bool) -> BindGroupLayoutEntryBuilder {
|
||||||
|
uniform_buffer_sized(has_dynamic_offset, Some(T::min_size()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uniform_buffer_sized(
|
||||||
|
has_dynamic_offset: bool,
|
||||||
|
min_binding_size: Option<NonZeroU64>,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Buffer {
|
||||||
|
ty: BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset,
|
||||||
|
min_binding_size,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_2d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::D2,
|
||||||
|
multisampled: false,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_2d_multisampled(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::D2,
|
||||||
|
multisampled: true,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_2d_array(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::D2Array,
|
||||||
|
multisampled: false,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_2d_array_multisampled(
|
||||||
|
sample_type: TextureSampleType,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::D2Array,
|
||||||
|
multisampled: true,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_depth_2d() -> BindGroupLayoutEntryBuilder {
|
||||||
|
texture_2d(TextureSampleType::Depth).into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_depth_2d_multisampled() -> BindGroupLayoutEntryBuilder {
|
||||||
|
texture_2d_multisampled(TextureSampleType::Depth).into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_cube(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::Cube,
|
||||||
|
multisampled: false,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_cube_multisampled(
|
||||||
|
sample_type: TextureSampleType,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::Cube,
|
||||||
|
multisampled: true,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_cube_array(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::CubeArray,
|
||||||
|
multisampled: false,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_cube_array_multisampled(
|
||||||
|
sample_type: TextureSampleType,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::CubeArray,
|
||||||
|
multisampled: true,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_3d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::D3,
|
||||||
|
multisampled: false,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_3d_multisampled(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Texture {
|
||||||
|
sample_type,
|
||||||
|
view_dimension: TextureViewDimension::D3,
|
||||||
|
multisampled: true,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sampler(sampler_binding_type: SamplerBindingType) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::Sampler(sampler_binding_type).into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_storage_2d(
|
||||||
|
format: TextureFormat,
|
||||||
|
access: StorageTextureAccess,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::StorageTexture {
|
||||||
|
access,
|
||||||
|
format,
|
||||||
|
view_dimension: TextureViewDimension::D2,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_storage_2d_array(
|
||||||
|
format: TextureFormat,
|
||||||
|
access: StorageTextureAccess,
|
||||||
|
) -> BindGroupLayoutEntryBuilder {
|
||||||
|
BindingType::StorageTexture {
|
||||||
|
access,
|
||||||
|
format,
|
||||||
|
view_dimension: TextureViewDimension::D2Array,
|
||||||
|
}
|
||||||
|
.into_bind_group_layout_entry_builder()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,7 @@
|
|||||||
use super::StorageBuffer;
|
use super::{
|
||||||
|
binding_types::{storage_buffer_read_only, uniform_buffer_sized},
|
||||||
|
BindGroupLayoutEntryBuilder, StorageBuffer,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
render_resource::batched_uniform_buffer::BatchedUniformBuffer,
|
render_resource::batched_uniform_buffer::BatchedUniformBuffer,
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
@ -7,7 +10,7 @@ use bevy_ecs::{prelude::Component, system::Resource};
|
|||||||
use bevy_utils::nonmax::NonMaxU32;
|
use bevy_utils::nonmax::NonMaxU32;
|
||||||
use encase::{private::WriteInto, ShaderSize, ShaderType};
|
use encase::{private::WriteInto, ShaderSize, ShaderType};
|
||||||
use std::{marker::PhantomData, mem};
|
use std::{marker::PhantomData, mem};
|
||||||
use wgpu::{BindGroupLayoutEntry, BindingResource, BindingType, BufferBindingType, ShaderStages};
|
use wgpu::BindingResource;
|
||||||
|
|
||||||
/// Trait for types able to go in a [`GpuArrayBuffer`].
|
/// Trait for types able to go in a [`GpuArrayBuffer`].
|
||||||
pub trait GpuArrayBufferable: ShaderType + ShaderSize + WriteInto + Clone {}
|
pub trait GpuArrayBufferable: ShaderType + ShaderSize + WriteInto + Clone {}
|
||||||
@ -74,30 +77,16 @@ impl<T: GpuArrayBufferable> GpuArrayBuffer<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binding_layout(
|
pub fn binding_layout(device: &RenderDevice) -> BindGroupLayoutEntryBuilder {
|
||||||
binding: u32,
|
if device.limits().max_storage_buffers_per_shader_stage == 0 {
|
||||||
visibility: ShaderStages,
|
uniform_buffer_sized(
|
||||||
device: &RenderDevice,
|
true,
|
||||||
) -> BindGroupLayoutEntry {
|
// BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use
|
||||||
BindGroupLayoutEntry {
|
// None here and let wgpu figure out the size.
|
||||||
binding,
|
None,
|
||||||
visibility,
|
)
|
||||||
ty: if device.limits().max_storage_buffers_per_shader_stage == 0 {
|
} else {
|
||||||
BindingType::Buffer {
|
storage_buffer_read_only::<T>(false)
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
// BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use
|
|
||||||
// None here and let wgpu figure out the size.
|
|
||||||
min_binding_size: None,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Storage { read_only: true },
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(T::min_size()),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ mod batched_uniform_buffer;
|
|||||||
mod bind_group;
|
mod bind_group;
|
||||||
mod bind_group_entries;
|
mod bind_group_entries;
|
||||||
mod bind_group_layout;
|
mod bind_group_layout;
|
||||||
|
mod bind_group_layout_entries;
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod buffer_vec;
|
mod buffer_vec;
|
||||||
mod gpu_array_buffer;
|
mod gpu_array_buffer;
|
||||||
@ -17,6 +18,7 @@ mod uniform_buffer;
|
|||||||
pub use bind_group::*;
|
pub use bind_group::*;
|
||||||
pub use bind_group_entries::*;
|
pub use bind_group_entries::*;
|
||||||
pub use bind_group_layout::*;
|
pub use bind_group_layout::*;
|
||||||
|
pub use bind_group_layout_entries::*;
|
||||||
pub use buffer::*;
|
pub use buffer::*;
|
||||||
pub use buffer_vec::*;
|
pub use buffer_vec::*;
|
||||||
pub use gpu_array_buffer::*;
|
pub use gpu_array_buffer::*;
|
||||||
|
|||||||
@ -4,7 +4,8 @@ use crate::render_resource::{
|
|||||||
};
|
};
|
||||||
use bevy_ecs::system::Resource;
|
use bevy_ecs::system::Resource;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BufferAsyncError, BufferBindingType,
|
util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor,
|
||||||
|
BindGroupLayoutEntry, BufferAsyncError, BufferBindingType,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::RenderQueue;
|
use super::RenderQueue;
|
||||||
@ -100,11 +101,18 @@ impl RenderDevice {
|
|||||||
|
|
||||||
/// Creates a [`BindGroupLayout`](wgpu::BindGroupLayout).
|
/// Creates a [`BindGroupLayout`](wgpu::BindGroupLayout).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn create_bind_group_layout(
|
pub fn create_bind_group_layout<'a>(
|
||||||
&self,
|
&self,
|
||||||
desc: &wgpu::BindGroupLayoutDescriptor,
|
label: impl Into<wgpu::Label<'a>>,
|
||||||
|
entries: &'a [BindGroupLayoutEntry],
|
||||||
) -> BindGroupLayout {
|
) -> BindGroupLayout {
|
||||||
BindGroupLayout::from(self.device.create_bind_group_layout(desc))
|
BindGroupLayout::from(
|
||||||
|
self.device
|
||||||
|
.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||||
|
label: label.into(),
|
||||||
|
entries,
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`PipelineLayout`](wgpu::PipelineLayout).
|
/// Creates a [`PipelineLayout`](wgpu::PipelineLayout).
|
||||||
|
|||||||
@ -15,9 +15,9 @@ use wgpu::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
prelude::{Image, Shader},
|
prelude::{Image, Shader},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BindGroup, BindGroupLayout, Buffer, CachedRenderPipelineId, FragmentState, PipelineCache,
|
binding_types::texture_2d, BindGroup, BindGroupLayout, BindGroupLayoutEntries, Buffer,
|
||||||
RenderPipelineDescriptor, SpecializedRenderPipeline, SpecializedRenderPipelines, Texture,
|
CachedRenderPipelineId, FragmentState, PipelineCache, RenderPipelineDescriptor,
|
||||||
VertexState,
|
SpecializedRenderPipeline, SpecializedRenderPipelines, Texture, VertexState,
|
||||||
},
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::TextureFormatPixelInfo,
|
texture::TextureFormatPixelInfo,
|
||||||
@ -201,19 +201,13 @@ impl FromWorld for ScreenshotToScreenPipeline {
|
|||||||
fn from_world(render_world: &mut World) -> Self {
|
fn from_world(render_world: &mut World) -> Self {
|
||||||
let device = render_world.resource::<RenderDevice>();
|
let device = render_world.resource::<RenderDevice>();
|
||||||
|
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let bind_group_layout = device.create_bind_group_layout(
|
||||||
label: Some("screenshot-to-screen-bgl"),
|
"screenshot-to-screen-bgl",
|
||||||
entries: &[wgpu::BindGroupLayoutEntry {
|
&BindGroupLayoutEntries::single(
|
||||||
binding: 0,
|
wgpu::ShaderStages::FRAGMENT,
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
texture_2d(wgpu::TextureSampleType::Float { filterable: false }),
|
||||||
ty: wgpu::BindingType::Texture {
|
),
|
||||||
sample_type: wgpu::TextureSampleType::Float { filterable: false },
|
);
|
||||||
view_dimension: wgpu::TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
|
|
||||||
Self { bind_group_layout }
|
Self { bind_group_layout }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,7 @@ use bevy_render::{
|
|||||||
mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout},
|
mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
|
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||||
render_resource::*,
|
render_resource::{binding_types::uniform_buffer, *},
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
texture::{
|
texture::{
|
||||||
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
||||||
@ -256,41 +256,25 @@ impl FromWorld for Mesh2dPipeline {
|
|||||||
)> = SystemState::new(world);
|
)> = SystemState::new(world);
|
||||||
let (render_device, render_queue, default_sampler) = system_state.get_mut(world);
|
let (render_device, render_queue, default_sampler) = system_state.get_mut(world);
|
||||||
let render_device = render_device.into_inner();
|
let render_device = render_device.into_inner();
|
||||||
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let view_layout = render_device.create_bind_group_layout(
|
||||||
entries: &[
|
"mesh2d_view_layout",
|
||||||
// View
|
&BindGroupLayoutEntries::sequential(
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: true,
|
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::VERTEX_FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(GlobalsUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("mesh2d_view_layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let mesh_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
|
||||||
entries: &[GpuArrayBuffer::<Mesh2dUniform>::binding_layout(
|
|
||||||
0,
|
|
||||||
ShaderStages::VERTEX_FRAGMENT,
|
ShaderStages::VERTEX_FRAGMENT,
|
||||||
render_device,
|
(
|
||||||
)],
|
// View
|
||||||
label: Some("mesh2d_layout"),
|
uniform_buffer::<ViewUniform>(true),
|
||||||
});
|
uniform_buffer::<GlobalsUniform>(false),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mesh_layout = render_device.create_bind_group_layout(
|
||||||
|
"mesh2d_layout",
|
||||||
|
&BindGroupLayoutEntries::single(
|
||||||
|
ShaderStages::VERTEX_FRAGMENT,
|
||||||
|
GpuArrayBuffer::<Mesh2dUniform>::binding_layout(render_device),
|
||||||
|
),
|
||||||
|
);
|
||||||
// A 1x1x1 'all 1.0' texture to use as a dummy texture to use in place of optional StandardMaterial textures
|
// A 1x1x1 'all 1.0' texture to use as a dummy texture to use in place of optional StandardMaterial textures
|
||||||
let dummy_white_gpu_image = {
|
let dummy_white_gpu_image = {
|
||||||
let image = Image::default();
|
let image = Image::default();
|
||||||
|
|||||||
@ -21,7 +21,10 @@ use bevy_render::{
|
|||||||
DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, SetItemPipeline,
|
DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, SetItemPipeline,
|
||||||
TrackedRenderPass,
|
TrackedRenderPass,
|
||||||
},
|
},
|
||||||
render_resource::{BindGroupEntries, *},
|
render_resource::{
|
||||||
|
binding_types::{sampler, texture_2d, uniform_buffer},
|
||||||
|
BindGroupEntries, *,
|
||||||
|
},
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
texture::{
|
texture::{
|
||||||
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
||||||
@ -53,41 +56,24 @@ impl FromWorld for SpritePipeline {
|
|||||||
)> = SystemState::new(world);
|
)> = SystemState::new(world);
|
||||||
let (render_device, default_sampler, render_queue) = system_state.get_mut(world);
|
let (render_device, default_sampler, render_queue) = system_state.get_mut(world);
|
||||||
|
|
||||||
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let view_layout = render_device.create_bind_group_layout(
|
||||||
entries: &[BindGroupLayoutEntry {
|
"sprite_view_layout",
|
||||||
binding: 0,
|
&BindGroupLayoutEntries::single(
|
||||||
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
|
ShaderStages::VERTEX_FRAGMENT,
|
||||||
ty: BindingType::Buffer {
|
uniform_buffer::<ViewUniform>(true),
|
||||||
ty: BufferBindingType::Uniform,
|
),
|
||||||
has_dynamic_offset: true,
|
);
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
label: Some("sprite_view_layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let material_layout = render_device.create_bind_group_layout(
|
||||||
entries: &[
|
"sprite_material_layout",
|
||||||
BindGroupLayoutEntry {
|
&BindGroupLayoutEntries::sequential(
|
||||||
binding: 0,
|
ShaderStages::FRAGMENT,
|
||||||
visibility: ShaderStages::FRAGMENT,
|
(
|
||||||
ty: BindingType::Texture {
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
multisampled: false,
|
sampler(SamplerBindingType::Filtering),
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
),
|
||||||
view_dimension: TextureViewDimension::D2,
|
),
|
||||||
},
|
);
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("sprite_material_layout"),
|
|
||||||
});
|
|
||||||
let dummy_white_gpu_image = {
|
let dummy_white_gpu_image = {
|
||||||
let image = Image::default();
|
let image = Image::default();
|
||||||
let texture = render_device.create_texture(&image.texture_descriptor);
|
let texture = render_device.create_texture(&image.texture_descriptor);
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
render_resource::*,
|
render_resource::{
|
||||||
|
binding_types::{sampler, texture_2d, uniform_buffer},
|
||||||
|
*,
|
||||||
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::BevyDefault,
|
texture::BevyDefault,
|
||||||
view::{ViewTarget, ViewUniform},
|
view::{ViewTarget, ViewUniform},
|
||||||
@ -16,41 +19,24 @@ impl FromWorld for UiPipeline {
|
|||||||
fn from_world(world: &mut World) -> Self {
|
fn from_world(world: &mut World) -> Self {
|
||||||
let render_device = world.resource::<RenderDevice>();
|
let render_device = world.resource::<RenderDevice>();
|
||||||
|
|
||||||
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let view_layout = render_device.create_bind_group_layout(
|
||||||
entries: &[BindGroupLayoutEntry {
|
"ui_view_layout",
|
||||||
binding: 0,
|
&BindGroupLayoutEntries::single(
|
||||||
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
|
ShaderStages::VERTEX_FRAGMENT,
|
||||||
ty: BindingType::Buffer {
|
uniform_buffer::<ViewUniform>(true),
|
||||||
ty: BufferBindingType::Uniform,
|
),
|
||||||
has_dynamic_offset: true,
|
);
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
label: Some("ui_view_layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let image_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let image_layout = render_device.create_bind_group_layout(
|
||||||
entries: &[
|
"ui_image_layout",
|
||||||
BindGroupLayoutEntry {
|
&BindGroupLayoutEntries::sequential(
|
||||||
binding: 0,
|
ShaderStages::FRAGMENT,
|
||||||
visibility: ShaderStages::FRAGMENT,
|
(
|
||||||
ty: BindingType::Texture {
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
multisampled: false,
|
sampler(SamplerBindingType::Filtering),
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
),
|
||||||
view_dimension: TextureViewDimension::D2,
|
),
|
||||||
},
|
);
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("ui_image_layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
UiPipeline {
|
UiPipeline {
|
||||||
view_layout,
|
view_layout,
|
||||||
|
|||||||
@ -17,7 +17,7 @@ use bevy_render::{
|
|||||||
extract_component::ExtractComponentPlugin,
|
extract_component::ExtractComponentPlugin,
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_phase::*,
|
render_phase::*,
|
||||||
render_resource::*,
|
render_resource::{binding_types::uniform_buffer, *},
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
texture::{BevyDefault, FallbackImage, Image},
|
texture::{BevyDefault, FallbackImage, Image},
|
||||||
view::*,
|
view::*,
|
||||||
@ -223,19 +223,13 @@ impl<M: UiMaterial> FromWorld for UiMaterialPipeline<M> {
|
|||||||
let render_device = world.resource::<RenderDevice>();
|
let render_device = world.resource::<RenderDevice>();
|
||||||
let ui_layout = M::bind_group_layout(render_device);
|
let ui_layout = M::bind_group_layout(render_device);
|
||||||
|
|
||||||
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let view_layout = render_device.create_bind_group_layout(
|
||||||
entries: &[BindGroupLayoutEntry {
|
"ui_view_layout",
|
||||||
binding: 0,
|
&BindGroupLayoutEntries::single(
|
||||||
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
|
ShaderStages::VERTEX_FRAGMENT,
|
||||||
ty: BindingType::Buffer {
|
uniform_buffer::<ViewUniform>(true),
|
||||||
ty: BufferBindingType::Uniform,
|
),
|
||||||
has_dynamic_offset: true,
|
);
|
||||||
min_binding_size: Some(ViewUniform::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
label: Some("ui_view_layout"),
|
|
||||||
});
|
|
||||||
UiMaterialPipeline {
|
UiMaterialPipeline {
|
||||||
ui_layout,
|
ui_layout,
|
||||||
view_layout,
|
view_layout,
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use bevy::{
|
|||||||
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_graph::{self, RenderGraph},
|
render_graph::{self, RenderGraph},
|
||||||
render_resource::*,
|
render_resource::{binding_types::texture_storage_2d, *},
|
||||||
renderer::{RenderContext, RenderDevice},
|
renderer::{RenderContext, RenderDevice},
|
||||||
Render, RenderApp, RenderSet,
|
Render, RenderApp, RenderSet,
|
||||||
},
|
},
|
||||||
@ -124,22 +124,13 @@ pub struct GameOfLifePipeline {
|
|||||||
|
|
||||||
impl FromWorld for GameOfLifePipeline {
|
impl FromWorld for GameOfLifePipeline {
|
||||||
fn from_world(world: &mut World) -> Self {
|
fn from_world(world: &mut World) -> Self {
|
||||||
let texture_bind_group_layout =
|
let texture_bind_group_layout = world.resource::<RenderDevice>().create_bind_group_layout(
|
||||||
world
|
None,
|
||||||
.resource::<RenderDevice>()
|
&BindGroupLayoutEntries::single(
|
||||||
.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
ShaderStages::COMPUTE,
|
||||||
label: None,
|
texture_storage_2d(TextureFormat::Rgba8Unorm, StorageTextureAccess::ReadWrite),
|
||||||
entries: &[BindGroupLayoutEntry {
|
),
|
||||||
binding: 0,
|
);
|
||||||
visibility: ShaderStages::COMPUTE,
|
|
||||||
ty: BindingType::StorageTexture {
|
|
||||||
access: StorageTextureAccess::ReadWrite,
|
|
||||||
format: TextureFormat::Rgba8Unorm,
|
|
||||||
view_dimension: TextureViewDimension::D2,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
let shader = world
|
let shader = world
|
||||||
.resource::<AssetServer>()
|
.resource::<AssetServer>()
|
||||||
.load("shaders/game_of_life.wgsl");
|
.load("shaders/game_of_life.wgsl");
|
||||||
|
|||||||
@ -17,12 +17,8 @@ use bevy::{
|
|||||||
NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner,
|
NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner,
|
||||||
},
|
},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
|
binding_types::{sampler, texture_2d, uniform_buffer},
|
||||||
BindingType, CachedRenderPipelineId, ColorTargetState, ColorWrites, FragmentState,
|
*,
|
||||||
MultisampleState, Operations, PipelineCache, PrimitiveState, RenderPassColorAttachment,
|
|
||||||
RenderPassDescriptor, RenderPipelineDescriptor, Sampler, SamplerBindingType,
|
|
||||||
SamplerDescriptor, ShaderStages, ShaderType, TextureFormat, TextureSampleType,
|
|
||||||
TextureViewDimension,
|
|
||||||
},
|
},
|
||||||
renderer::{RenderContext, RenderDevice},
|
renderer::{RenderContext, RenderDevice},
|
||||||
texture::BevyDefault,
|
texture::BevyDefault,
|
||||||
@ -227,40 +223,21 @@ impl FromWorld for PostProcessPipeline {
|
|||||||
let render_device = world.resource::<RenderDevice>();
|
let render_device = world.resource::<RenderDevice>();
|
||||||
|
|
||||||
// We need to define the bind group layout used for our pipeline
|
// We need to define the bind group layout used for our pipeline
|
||||||
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
let layout = render_device.create_bind_group_layout(
|
||||||
label: Some("post_process_bind_group_layout"),
|
"post_process_bind_group_layout",
|
||||||
entries: &[
|
&BindGroupLayoutEntries::sequential(
|
||||||
// The screen texture
|
// The layout entries will only be visible in the fragment stage
|
||||||
BindGroupLayoutEntry {
|
ShaderStages::FRAGMENT,
|
||||||
binding: 0,
|
(
|
||||||
visibility: ShaderStages::FRAGMENT,
|
// The screen texture
|
||||||
ty: BindingType::Texture {
|
texture_2d(TextureSampleType::Float { filterable: true }),
|
||||||
sample_type: TextureSampleType::Float { filterable: true },
|
// The sampler that will be used to sample the screen texture
|
||||||
view_dimension: TextureViewDimension::D2,
|
sampler(SamplerBindingType::Filtering),
|
||||||
multisampled: false,
|
// The settings uniform that will control the effect
|
||||||
},
|
uniform_buffer::<PostProcessSettings>(false),
|
||||||
count: None,
|
),
|
||||||
},
|
),
|
||||||
// The sampler that will be used to sample the screen texture
|
);
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// The settings uniform that will control the effect
|
|
||||||
BindGroupLayoutEntry {
|
|
||||||
binding: 2,
|
|
||||||
visibility: ShaderStages::FRAGMENT,
|
|
||||||
ty: BindingType::Buffer {
|
|
||||||
ty: bevy::render::render_resource::BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: Some(PostProcessSettings::min_size()),
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
// We can create the sampler here since it won't change at runtime and doesn't depend on the view
|
// We can create the sampler here since it won't change at runtime and doesn't depend on the view
|
||||||
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
|
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user