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:
IceSentry 2023-11-27 23:00:49 -05:00 committed by GitHub
parent f0a8994f55
commit 6d0c11a28f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1142 additions and 1106 deletions

View File

@ -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());

View File

@ -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 {

View File

@ -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 }
} }

View File

@ -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());

View File

@ -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

View File

@ -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 }
} }

View File

@ -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),
),
),
),
} }
} }
} }

View File

@ -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,

View File

@ -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,
},
] ]
} }

View File

@ -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 });
} }

View File

@ -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,

View File

@ -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,
},
] ]
} }

View File

@ -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>();

View File

@ -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,
},
); );
} }

View File

@ -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 skinning() -> BindGroupLayoutEntryBuilder {
uniform_buffer_sized(true, BufferSize::new(JOINT_BUFFER_SIZE as u64))
} }
pub(super) fn model(render_device: &RenderDevice, binding: u32) -> BindGroupLayoutEntry { pub(super) fn weights() -> BindGroupLayoutEntryBuilder {
GpuArrayBuffer::<MeshUniform>::binding_layout( uniform_buffer_sized(true, BufferSize::new(MORPH_BUFFER_SIZE as u64))
binding,
ShaderStages::VERTEX_FRAGMENT,
render_device,
)
}
pub(super) fn skinning(binding: u32) -> BindGroupLayoutEntry {
buffer(binding, JOINT_BUFFER_SIZE as u64, ShaderStages::VERTEX)
}
pub(super) fn weights(binding: u32) -> BindGroupLayoutEntry {
buffer(binding, MORPH_BUFFER_SIZE as u64, ShaderStages::VERTEX)
}
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,
} }
pub(super) fn targets() -> BindGroupLayoutEntryBuilder {
texture_3d(TextureSampleType::Float { filterable: false })
} }
} }
/// 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 ----------

View File

@ -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(
ShaderStages::FRAGMENT,
(
// View // View
BindGroupLayoutEntry { (
binding: 0, 0,
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),
ty: BindingType::Buffer { ),
ty: BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: Some(ViewUniform::min_size()),
},
count: None,
},
// Lights // Lights
BindGroupLayoutEntry { (1, uniform_buffer::<GpuLights>(true)),
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 // Point Shadow Texture Cube Array
BindGroupLayoutEntry { (
binding: 2, 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 // Point Shadow Texture Array Sampler
BindGroupLayoutEntry { (3, sampler(SamplerBindingType::Comparison)),
binding: 3,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Comparison),
count: None,
},
// Directional Shadow Texture Array // Directional Shadow Texture Array
BindGroupLayoutEntry { (
binding: 4, 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 // Directional Shadow Texture Array Sampler
BindGroupLayoutEntry { (5, sampler(SamplerBindingType::Comparison)),
binding: 5,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Comparison),
count: None,
},
// PointLights // PointLights
BindGroupLayoutEntry { (
binding: 6, 6,
visibility: ShaderStages::FRAGMENT, buffer_layout(
ty: BindingType::Buffer { clustered_forward_buffer_binding_type,
ty: clustered_forward_buffer_binding_type, false,
has_dynamic_offset: false, Some(GpuPointLights::min_size(
min_binding_size: Some(GpuPointLights::min_size(
clustered_forward_buffer_binding_type, clustered_forward_buffer_binding_type,
)), )),
}, ),
count: None, ),
},
// ClusteredLightIndexLists // ClusteredLightIndexLists
BindGroupLayoutEntry { (
binding: 7, 7,
visibility: ShaderStages::FRAGMENT, buffer_layout(
ty: BindingType::Buffer { clustered_forward_buffer_binding_type,
ty: clustered_forward_buffer_binding_type, false,
has_dynamic_offset: false, Some(ViewClusterBindings::min_size_cluster_light_index_lists(
min_binding_size: Some(ViewClusterBindings::min_size_cluster_light_index_lists(
clustered_forward_buffer_binding_type, clustered_forward_buffer_binding_type,
)), )),
}, ),
count: None, ),
},
// ClusterOffsetsAndCounts // ClusterOffsetsAndCounts
BindGroupLayoutEntry { (
binding: 8, 8,
visibility: ShaderStages::FRAGMENT, buffer_layout(
ty: BindingType::Buffer { clustered_forward_buffer_binding_type,
ty: clustered_forward_buffer_binding_type, false,
has_dynamic_offset: false, Some(ViewClusterBindings::min_size_cluster_offsets_and_counts(
min_binding_size: Some(ViewClusterBindings::min_size_cluster_offsets_and_counts(
clustered_forward_buffer_binding_type, clustered_forward_buffer_binding_type,
)), )),
}, ),
count: None, ),
},
// Globals // Globals
BindGroupLayoutEntry { (9, uniform_buffer::<GlobalsUniform>(false)),
binding: 9,
visibility: ShaderStages::VERTEX_FRAGMENT,
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: Some(GlobalsUniform::min_size()),
},
count: None,
},
// Fog // Fog
BindGroupLayoutEntry { (10, uniform_buffer::<GpuFog>(true)),
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 // Screen space ambient occlusion texture
BindGroupLayoutEntry { (
binding: 11, 11,
visibility: ShaderStages::FRAGMENT, texture_2d(TextureSampleType::Float { filterable: false }),
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,
} }

View File

@ -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 {

View File

@ -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

View File

@ -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()
}
}

View File

@ -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 {
BindGroupLayoutEntry {
binding,
visibility,
ty: if device.limits().max_storage_buffers_per_shader_stage == 0 {
BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: true,
// BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use // BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use
// None here and let wgpu figure out the size. // None here and let wgpu figure out the size.
min_binding_size: None, None,
} )
} else { } else {
BindingType::Buffer { storage_buffer_read_only::<T>(false)
ty: BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: Some(T::min_size()),
}
},
count: None,
} }
} }

View File

@ -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::*;

View File

@ -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).

View File

@ -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 }
} }

View File

@ -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();

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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");

View File

@ -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 layout entries will only be visible in the fragment stage
ShaderStages::FRAGMENT,
(
// The screen texture // The screen texture
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,
},
// The sampler that will be used to sample the screen texture // The sampler that will be used to sample the screen texture
BindGroupLayoutEntry { sampler(SamplerBindingType::Filtering),
binding: 1,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Filtering),
count: None,
},
// The settings uniform that will control the effect // The settings uniform that will control the effect
BindGroupLayoutEntry { uniform_buffer::<PostProcessSettings>(false),
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());