Bind group entries (#9694)

# Objective

Simplify bind group creation code. alternative to (and based on) #9476

## Solution

- Add a `BindGroupEntries` struct that can transparently be used where
`&[BindGroupEntry<'b>]` is required in BindGroupDescriptors.

Allows constructing the descriptor's entries as:
```rust
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &BindGroupEntries::with_indexes((
        (2, &my_sampler),
        (3, my_uniform),
    )),
);
```

instead of

```rust
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &[
        BindGroupEntry {
            binding: 2,
            resource: BindingResource::Sampler(&my_sampler),
        },
        BindGroupEntry {
            binding: 3,
            resource: my_uniform,
        },
    ],
);
```

or

```rust
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &BindGroupEntries::sequential((&my_sampler, my_uniform)),
);
```

instead of

```rust
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &[
        BindGroupEntry {
            binding: 0,
            resource: BindingResource::Sampler(&my_sampler),
        },
        BindGroupEntry {
            binding: 1,
            resource: my_uniform,
        },
    ],
);
```

the structs has no user facing macros, is tuple-type-based so stack
allocated, and has no noticeable impact on compile time.

- Also adds a `DynamicBindGroupEntries` struct with a similar api that
uses a `Vec` under the hood and allows extending the entries.
- Modifies `RenderDevice::create_bind_group` to take separate arguments
`label`, `layout` and `entries` instead of a `BindGroupDescriptor`
struct. The struct can't be stored due to the internal references, and
with only 3 members arguably does not add enough context to justify
itself.
- Modify the codebase to use the new api and the `BindGroupEntries` /
`DynamicBindGroupEntries` structs where appropriate (whenever the
entries slice contains more than 1 member).

## Migration Guide

- Calls to `RenderDevice::create_bind_group({BindGroupDescriptor {
label, layout, entries })` must be amended to
`RenderDevice::create_bind_group(label, layout, entries)`.
- If `label`s have been specified as `"bind_group_name".into()`, they
need to change to just `"bind_group_name"`. `Some("bind_group_name")`
and `None` will still work, but `Some("bind_group_name")` can optionally
be simplified to just `"bind_group_name"`.

---------

Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
This commit is contained in:
robtfm 2023-10-21 16:39:22 +01:00 committed by GitHub
parent 61bad4eb57
commit 6f2a5cb862
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 701 additions and 830 deletions

View File

@ -170,30 +170,16 @@ impl ViewNode for BloomNode {
// First downsample pass // First downsample pass
{ {
let downsampling_first_bind_group = let downsampling_first_bind_group = render_context.render_device().create_bind_group(
render_context "bloom_downsampling_first_bind_group",
.render_device() &downsampling_pipeline_res.bind_group_layout,
.create_bind_group(&BindGroupDescriptor { &BindGroupEntries::sequential((
label: Some("bloom_downsampling_first_bind_group"), // Read from main texture directly
layout: &downsampling_pipeline_res.bind_group_layout, view_target.main_texture_view(),
entries: &[ &bind_groups.sampler,
BindGroupEntry { uniforms.clone(),
binding: 0, )),
// Read from main texture directly );
resource: BindingResource::TextureView(
view_target.main_texture_view(),
),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&bind_groups.sampler),
},
BindGroupEntry {
binding: 2,
resource: uniforms.clone(),
},
],
});
let view = &bloom_texture.view(0); let view = &bloom_texture.view(0);
let mut downsampling_first_pass = let mut downsampling_first_pass =
@ -416,46 +402,28 @@ fn prepare_bloom_bind_groups(
let mut downsampling_bind_groups = Vec::with_capacity(bind_group_count); let mut downsampling_bind_groups = Vec::with_capacity(bind_group_count);
for mip in 1..bloom_texture.mip_count { for mip in 1..bloom_texture.mip_count {
downsampling_bind_groups.push(render_device.create_bind_group(&BindGroupDescriptor { downsampling_bind_groups.push(render_device.create_bind_group(
label: Some("bloom_downsampling_bind_group"), "bloom_downsampling_bind_group",
layout: &downsampling_pipeline.bind_group_layout, &downsampling_pipeline.bind_group_layout,
entries: &[ &BindGroupEntries::sequential((
BindGroupEntry { &bloom_texture.view(mip - 1),
binding: 0, sampler,
resource: BindingResource::TextureView(&bloom_texture.view(mip - 1)), uniforms.binding().unwrap(),
}, )),
BindGroupEntry { ));
binding: 1,
resource: BindingResource::Sampler(sampler),
},
BindGroupEntry {
binding: 2,
resource: uniforms.binding().unwrap(),
},
],
}));
} }
let mut upsampling_bind_groups = Vec::with_capacity(bind_group_count); let mut upsampling_bind_groups = Vec::with_capacity(bind_group_count);
for mip in (0..bloom_texture.mip_count).rev() { for mip in (0..bloom_texture.mip_count).rev() {
upsampling_bind_groups.push(render_device.create_bind_group(&BindGroupDescriptor { upsampling_bind_groups.push(render_device.create_bind_group(
label: Some("bloom_upsampling_bind_group"), "bloom_upsampling_bind_group",
layout: &upsampling_pipeline.bind_group_layout, &upsampling_pipeline.bind_group_layout,
entries: &[ &BindGroupEntries::sequential((
BindGroupEntry { &bloom_texture.view(mip),
binding: 0, sampler,
resource: BindingResource::TextureView(&bloom_texture.view(mip)), uniforms.binding().unwrap(),
}, )),
BindGroupEntry { ));
binding: 1,
resource: BindingResource::Sampler(sampler),
},
BindGroupEntry {
binding: 2,
resource: uniforms.binding().unwrap(),
},
],
}));
} }
commands.entity(entity).insert(BloomBindGroups { commands.entity(entity).insert(BloomBindGroups {

View File

@ -7,8 +7,8 @@ use bevy_render::{
extract_component::{ComponentUniforms, DynamicUniformIndex}, extract_component::{ComponentUniforms, DynamicUniformIndex},
render_graph::{Node, NodeRunError, RenderGraphContext}, render_graph::{Node, NodeRunError, RenderGraphContext},
render_resource::{ render_resource::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, BufferId, Operations, BindGroup, BindGroupEntries, BufferId, Operations, PipelineCache,
PipelineCache, RenderPassColorAttachment, RenderPassDescriptor, TextureViewId, RenderPassColorAttachment, RenderPassDescriptor, TextureViewId,
}, },
renderer::RenderContext, renderer::RenderContext,
view::{ExtractedView, ViewTarget}, view::{ExtractedView, ViewTarget},
@ -77,29 +77,15 @@ impl Node for CASNode {
bind_group bind_group
} }
cached_bind_group => { cached_bind_group => {
let bind_group = let bind_group = render_context.render_device().create_bind_group(
render_context "cas_bind_group",
.render_device() &sharpening_pipeline.texture_bind_group,
.create_bind_group(&BindGroupDescriptor { &BindGroupEntries::sequential((
label: Some("cas_bind_group"), view_target.source,
layout: &sharpening_pipeline.texture_bind_group, &sharpening_pipeline.sampler,
entries: &[ uniforms,
BindGroupEntry { )),
binding: 0, );
resource: BindingResource::TextureView(view_target.source),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(
&sharpening_pipeline.sampler,
),
},
BindGroupEntry {
binding: 2,
resource: uniforms,
},
],
});
let (_, _, bind_group) = let (_, _, bind_group) =
cached_bind_group.insert((uniforms_id, source.id(), bind_group)); cached_bind_group.insert((uniforms_id, source.id(), bind_group));

View File

@ -18,10 +18,7 @@ use bevy_render::{
use bevy_ecs::query::QueryItem; use bevy_ecs::query::QueryItem;
use bevy_render::{ use bevy_render::{
render_graph::{NodeRunError, RenderGraphContext, ViewNode}, render_graph::{NodeRunError, RenderGraphContext, ViewNode},
render_resource::{ render_resource::{Operations, PipelineCache, RenderPassDescriptor},
BindGroupDescriptor, BindGroupEntry, BindingResource, Operations, PipelineCache,
RenderPassDescriptor,
},
renderer::RenderContext, renderer::RenderContext,
}; };
@ -94,18 +91,11 @@ impl ViewNode for CopyDeferredLightingIdNode {
return Ok(()); return Ok(());
}; };
let bind_group = render_context let bind_group = render_context.render_device().create_bind_group(
.render_device() "copy_deferred_lighting_id_bind_group",
.create_bind_group(&BindGroupDescriptor { &copy_deferred_lighting_id_pipeline.layout,
label: Some("copy_deferred_lighting_id_bind_group"), &BindGroupEntries::single(&deferred_lighting_pass_id_texture.default_view),
layout: &copy_deferred_lighting_id_pipeline.layout, );
entries: &[BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(
&deferred_lighting_pass_id_texture.default_view,
),
}],
});
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor { let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
label: Some("copy_deferred_lighting_id_pass"), label: Some("copy_deferred_lighting_id_pass"),

View File

@ -6,9 +6,8 @@ use bevy_ecs::query::QueryItem;
use bevy_render::{ use bevy_render::{
render_graph::{NodeRunError, RenderGraphContext, ViewNode}, render_graph::{NodeRunError, RenderGraphContext, ViewNode},
render_resource::{ render_resource::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, FilterMode, Operations, BindGroup, BindGroupEntries, FilterMode, Operations, PipelineCache,
PipelineCache, RenderPassColorAttachment, RenderPassDescriptor, SamplerDescriptor, RenderPassColorAttachment, RenderPassDescriptor, SamplerDescriptor, TextureViewId,
TextureViewId,
}, },
renderer::RenderContext, renderer::RenderContext,
view::ViewTarget, view::ViewTarget,
@ -61,23 +60,11 @@ impl ViewNode for FxaaNode {
..default() ..default()
}); });
let bind_group = let bind_group = render_context.render_device().create_bind_group(
render_context None,
.render_device() &fxaa_pipeline.texture_bind_group,
.create_bind_group(&BindGroupDescriptor { &BindGroupEntries::sequential((source, &sampler)),
label: None, );
layout: &fxaa_pipeline.texture_bind_group,
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(source),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&sampler),
},
],
});
let (_, bind_group) = cached_bind_group.insert((source.id(), bind_group)); let (_, bind_group) = cached_bind_group.insert((source.id(), bind_group));
bind_group bind_group

View File

@ -8,6 +8,7 @@ use bevy_ecs::prelude::*;
use bevy_render::{ use bevy_render::{
camera::ExtractedCamera, camera::ExtractedCamera,
render_graph::{Node, NodeRunError, RenderGraphApp, RenderGraphContext}, render_graph::{Node, NodeRunError, RenderGraphApp, RenderGraphContext},
render_resource::BindGroupEntries,
renderer::RenderContext, renderer::RenderContext,
view::{Msaa, ViewTarget}, view::{Msaa, ViewTarget},
Render, RenderSet, Render, RenderSet,
@ -90,23 +91,11 @@ impl Node for MsaaWritebackNode {
depth_stencil_attachment: None, depth_stencil_attachment: None,
}; };
let bind_group = let bind_group = render_context.render_device().create_bind_group(
render_context None,
.render_device() &blit_pipeline.texture_bind_group,
.create_bind_group(&BindGroupDescriptor { &BindGroupEntries::sequential((post_process.source, &blit_pipeline.sampler)),
label: None, );
layout: &blit_pipeline.texture_bind_group,
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(post_process.source),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&blit_pipeline.sampler),
},
],
});
let mut render_pass = render_context let mut render_pass = render_context
.command_encoder() .command_encoder()

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, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor,
BindGroupLayoutEntry, BindingResource, BindingType, BufferBindingType, BindGroupLayoutEntry, BindingType, BufferBindingType, CachedRenderPipelineId,
CachedRenderPipelineId, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState,
DepthStencilState, FragmentState, MultisampleState, PipelineCache, PrimitiveState, FragmentState, MultisampleState, PipelineCache, PrimitiveState, RenderPipelineDescriptor,
RenderPipelineDescriptor, SamplerBindingType, Shader, ShaderStages, ShaderType, SamplerBindingType, Shader, ShaderStages, ShaderType, SpecializedRenderPipeline,
SpecializedRenderPipeline, SpecializedRenderPipelines, StencilFaceState, StencilState, SpecializedRenderPipelines, StencilFaceState, StencilState, TextureFormat,
TextureFormat, TextureSampleType, TextureViewDimension, VertexState, TextureSampleType, TextureViewDimension, VertexState,
}, },
renderer::RenderDevice, renderer::RenderDevice,
texture::{BevyDefault, Image}, texture::{BevyDefault, Image},
@ -224,24 +224,15 @@ fn prepare_skybox_bind_groups(
if let (Some(skybox), Some(view_uniforms)) = if let (Some(skybox), Some(view_uniforms)) =
(images.get(&skybox.0), view_uniforms.uniforms.binding()) (images.get(&skybox.0), view_uniforms.uniforms.binding())
{ {
let bind_group = render_device.create_bind_group(&BindGroupDescriptor { let bind_group = render_device.create_bind_group(
label: Some("skybox_bind_group"), "skybox_bind_group",
layout: &pipeline.bind_group_layout, &pipeline.bind_group_layout,
entries: &[ &BindGroupEntries::sequential((
BindGroupEntry { &skybox.texture_view,
binding: 0, &skybox.sampler,
resource: BindingResource::TextureView(&skybox.texture_view), view_uniforms,
}, )),
BindGroupEntry { );
binding: 1,
resource: BindingResource::Sampler(&skybox.sampler),
},
BindGroupEntry {
binding: 2,
resource: view_uniforms,
},
],
});
commands.entity(entity).insert(SkyboxBindGroup(bind_group)); commands.entity(entity).insert(SkyboxBindGroup(bind_group));
} }

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::{
BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
BindGroupLayoutEntry, BindingResource, BindingType, CachedRenderPipelineId, BindingType, CachedRenderPipelineId, ColorTargetState, ColorWrites, Extent3d, FilterMode,
ColorTargetState, ColorWrites, Extent3d, FilterMode, FragmentState, MultisampleState, FragmentState, MultisampleState, Operations, PipelineCache, PrimitiveState,
Operations, PipelineCache, PrimitiveState, RenderPassColorAttachment, RenderPassDescriptor, RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineDescriptor, Sampler,
RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor, Shader, SamplerBindingType, SamplerDescriptor, Shader, ShaderStages, SpecializedRenderPipeline,
ShaderStages, SpecializedRenderPipeline, SpecializedRenderPipelines, TextureDescriptor, SpecializedRenderPipelines, TextureDescriptor, TextureDimension, TextureFormat,
TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureViewDimension, TextureSampleType, TextureUsages, TextureViewDimension,
}, },
renderer::{RenderContext, RenderDevice}, renderer::{RenderContext, RenderDevice},
texture::{BevyDefault, CachedTexture, TextureCache}, texture::{BevyDefault, CachedTexture, TextureCache},
@ -197,45 +197,18 @@ impl ViewNode for TAANode {
}; };
let view_target = view_target.post_process_write(); let view_target = view_target.post_process_write();
let taa_bind_group = let taa_bind_group = render_context.render_device().create_bind_group(
render_context "taa_bind_group",
.render_device() &pipelines.taa_bind_group_layout,
.create_bind_group(&BindGroupDescriptor { &BindGroupEntries::sequential((
label: Some("taa_bind_group"), view_target.source,
layout: &pipelines.taa_bind_group_layout, &taa_history_textures.read.default_view,
entries: &[ &prepass_motion_vectors_texture.default_view,
BindGroupEntry { &prepass_depth_texture.default_view,
binding: 0, &pipelines.nearest_sampler,
resource: BindingResource::TextureView(view_target.source), &pipelines.linear_sampler,
}, )),
BindGroupEntry { );
binding: 1,
resource: BindingResource::TextureView(
&taa_history_textures.read.default_view,
),
},
BindGroupEntry {
binding: 2,
resource: BindingResource::TextureView(
&prepass_motion_vectors_texture.default_view,
),
},
BindGroupEntry {
binding: 3,
resource: BindingResource::TextureView(
&prepass_depth_texture.default_view,
),
},
BindGroupEntry {
binding: 4,
resource: BindingResource::Sampler(&pipelines.nearest_sampler),
},
BindGroupEntry {
binding: 5,
resource: BindingResource::Sampler(&pipelines.linear_sampler),
},
],
});
{ {
let mut taa_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor { let mut taa_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {

View File

@ -306,8 +306,7 @@ pub fn get_lut_bindings<'a>(
images: &'a RenderAssets<Image>, images: &'a RenderAssets<Image>,
tonemapping_luts: &'a TonemappingLuts, tonemapping_luts: &'a TonemappingLuts,
tonemapping: &Tonemapping, tonemapping: &Tonemapping,
bindings: [u32; 2], ) -> (&'a TextureView, &'a Sampler) {
) -> [BindGroupEntry<'a>; 2] {
let image = match tonemapping { let image = match tonemapping {
// AgX lut texture used when tonemapping doesn't need a texture since it's very small (32x32x32) // AgX lut texture used when tonemapping doesn't need a texture since it's very small (32x32x32)
Tonemapping::None Tonemapping::None
@ -320,16 +319,7 @@ pub fn get_lut_bindings<'a>(
Tonemapping::BlenderFilmic => &tonemapping_luts.blender_filmic, Tonemapping::BlenderFilmic => &tonemapping_luts.blender_filmic,
}; };
let lut_image = images.get(image).unwrap(); let lut_image = images.get(image).unwrap();
[ (&lut_image.texture_view, &lut_image.sampler)
BindGroupEntry {
binding: bindings[0],
resource: BindingResource::TextureView(&lut_image.texture_view),
},
BindGroupEntry {
binding: bindings[1],
resource: BindingResource::Sampler(&lut_image.sampler),
},
]
} }
pub fn get_lut_bind_group_layout_entries(bindings: [u32; 2]) -> [BindGroupLayoutEntry; 2] { pub fn get_lut_bind_group_layout_entries(bindings: [u32; 2]) -> [BindGroupLayoutEntry; 2] {

View File

@ -7,9 +7,8 @@ use bevy_render::{
render_asset::RenderAssets, render_asset::RenderAssets,
render_graph::{NodeRunError, RenderGraphContext, ViewNode}, render_graph::{NodeRunError, RenderGraphContext, ViewNode},
render_resource::{ render_resource::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, BufferId, LoadOp, BindGroup, BindGroupEntries, BufferId, LoadOp, Operations, PipelineCache,
Operations, PipelineCache, RenderPassColorAttachment, RenderPassDescriptor, RenderPassColorAttachment, RenderPassDescriptor, SamplerDescriptor, TextureViewId,
SamplerDescriptor, TextureViewId,
}, },
renderer::RenderContext, renderer::RenderContext,
texture::Image, texture::Image,
@ -88,36 +87,19 @@ impl ViewNode for TonemappingNode {
let tonemapping_luts = world.resource::<TonemappingLuts>(); let tonemapping_luts = world.resource::<TonemappingLuts>();
let mut entries = vec![ let lut_bindings = get_lut_bindings(gpu_images, tonemapping_luts, tonemapping);
BindGroupEntry {
binding: 0,
resource: view_uniforms.binding().unwrap(),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::TextureView(source),
},
BindGroupEntry {
binding: 2,
resource: BindingResource::Sampler(&sampler),
},
];
entries.extend(get_lut_bindings( let bind_group = render_context.render_device().create_bind_group(
gpu_images, None,
tonemapping_luts, &tonemapping_pipeline.texture_bind_group,
tonemapping, &BindGroupEntries::sequential((
[3, 4], view_uniforms,
)); source,
&sampler,
let bind_group = lut_bindings.0,
render_context lut_bindings.1,
.render_device() )),
.create_bind_group(&BindGroupDescriptor { );
label: None,
layout: &tonemapping_pipeline.texture_bind_group,
entries: &entries,
});
let (_, _, bind_group) = let (_, _, bind_group) =
cached_bind_group.insert((view_uniforms_id, source.id(), bind_group)); cached_bind_group.insert((view_uniforms_id, source.id(), bind_group));

View File

@ -4,9 +4,8 @@ use bevy_render::{
camera::{CameraOutputMode, ExtractedCamera}, camera::{CameraOutputMode, ExtractedCamera},
render_graph::{NodeRunError, RenderGraphContext, ViewNode}, render_graph::{NodeRunError, RenderGraphContext, ViewNode},
render_resource::{ render_resource::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, LoadOp, Operations, BindGroup, BindGroupEntries, LoadOp, Operations, PipelineCache, RenderPassColorAttachment,
PipelineCache, RenderPassColorAttachment, RenderPassDescriptor, SamplerDescriptor, RenderPassDescriptor, SamplerDescriptor, TextureViewId,
TextureViewId,
}, },
renderer::RenderContext, renderer::RenderContext,
view::ViewTarget, view::ViewTarget,
@ -57,23 +56,11 @@ impl ViewNode for UpscalingNode {
.render_device() .render_device()
.create_sampler(&SamplerDescriptor::default()); .create_sampler(&SamplerDescriptor::default());
let bind_group = let bind_group = render_context.render_device().create_bind_group(
render_context None,
.render_device() &blit_pipeline.texture_bind_group,
.create_bind_group(&BindGroupDescriptor { &BindGroupEntries::sequential((upscaled_texture, &sampler)),
label: None, );
layout: &blit_pipeline.texture_bind_group,
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(upscaled_texture),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&sampler),
},
],
});
let (_, bind_group) = cached_bind_group.insert((upscaled_texture.id(), bind_group)); let (_, bind_group) = cached_bind_group.insert((upscaled_texture.id(), bind_group));
bind_group bind_group

View File

@ -52,7 +52,7 @@ 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, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor,
BindGroupLayoutEntry, BindingType, Buffer, BufferBindingType, BufferInitDescriptor, BindGroupLayoutEntry, BindingType, Buffer, BufferBindingType, BufferInitDescriptor,
BufferUsages, Shader, ShaderStages, ShaderType, VertexAttribute, VertexBufferLayout, BufferUsages, Shader, ShaderStages, ShaderType, VertexAttribute, VertexBufferLayout,
VertexFormat, VertexStepMode, VertexFormat, VertexStepMode,
@ -422,14 +422,11 @@ fn prepare_line_gizmo_bind_group(
) { ) {
if let Some(binding) = line_gizmo_uniforms.uniforms().binding() { if let Some(binding) = line_gizmo_uniforms.uniforms().binding() {
commands.insert_resource(LineGizmoUniformBindgroup { commands.insert_resource(LineGizmoUniformBindgroup {
bindgroup: render_device.create_bind_group(&BindGroupDescriptor { bindgroup: render_device.create_bind_group(
entries: &[BindGroupEntry { "LineGizmoUniform bindgroup",
binding: 0, &line_gizmo_uniform_layout.layout,
resource: binding, &BindGroupEntries::single(binding),
}], ),
label: Some("LineGizmoUniform bindgroup"),
layout: &line_gizmo_uniform_layout.layout,
}),
}); });
} }
} }

View File

@ -191,16 +191,11 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode {
return Ok(()); return Ok(());
}; };
let bind_group_1 = render_context let bind_group_1 = render_context.render_device().create_bind_group(
.render_device() "deferred_lighting_layout_group_1",
.create_bind_group(&BindGroupDescriptor { &deferred_lighting_layout.bind_group_layout_1,
label: Some("deferred_lighting_layout_group_1"), &BindGroupEntries::single(deferred_lighting_pass_id_binding),
layout: &deferred_lighting_layout.bind_group_layout_1, );
entries: &[BindGroupEntry {
binding: 0,
resource: deferred_lighting_pass_id_binding.clone(),
}],
});
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor { let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
label: Some("deferred_lighting_pass"), label: Some("deferred_lighting_pass"),

View File

@ -7,8 +7,8 @@ use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin}, extract_component::{ExtractComponent, ExtractComponentPlugin},
render_asset::RenderAssets, render_asset::RenderAssets,
render_resource::{ render_resource::{
BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, SamplerBindingType, BindGroupLayoutEntry, BindingType, Sampler, SamplerBindingType, Shader, ShaderStages,
Shader, ShaderStages, TextureSampleType, TextureViewDimension, TextureSampleType, TextureView, TextureViewDimension,
}, },
texture::{FallbackImageCubemap, Image}, texture::{FallbackImageCubemap, Image},
}; };
@ -65,8 +65,7 @@ pub fn get_bindings<'a>(
environment_map_light: Option<&EnvironmentMapLight>, environment_map_light: Option<&EnvironmentMapLight>,
images: &'a RenderAssets<Image>, images: &'a RenderAssets<Image>,
fallback_image_cubemap: &'a FallbackImageCubemap, fallback_image_cubemap: &'a FallbackImageCubemap,
bindings: [u32; 3], ) -> (&'a TextureView, &'a TextureView, &'a Sampler) {
) -> [BindGroupEntry<'a>; 3] {
let (diffuse_map, specular_map) = match ( let (diffuse_map, specular_map) = match (
environment_map_light.and_then(|env_map| images.get(&env_map.diffuse_map)), environment_map_light.and_then(|env_map| images.get(&env_map.diffuse_map)),
environment_map_light.and_then(|env_map| images.get(&env_map.specular_map)), environment_map_light.and_then(|env_map| images.get(&env_map.specular_map)),
@ -80,20 +79,7 @@ pub fn get_bindings<'a>(
), ),
}; };
[ (diffuse_map, specular_map, &fallback_image_cubemap.sampler)
BindGroupEntry {
binding: bindings[0],
resource: BindingResource::TextureView(diffuse_map),
},
BindGroupEntry {
binding: bindings[1],
resource: BindingResource::TextureView(specular_map),
},
BindGroupEntry {
binding: bindings[2],
resource: BindingResource::Sampler(&fallback_image_cubemap.sampler),
},
]
} }
pub fn get_bind_group_layout_entries(bindings: [u32; 3]) -> [BindGroupLayoutEntry; 3] { pub fn get_bind_group_layout_entries(bindings: [u32; 3]) -> [BindGroupLayoutEntry; 3] {

View File

@ -35,7 +35,7 @@ use bevy_render::{
RenderPhase, SetItemPipeline, TrackedRenderPass, RenderPhase, SetItemPipeline, TrackedRenderPass,
}, },
render_resource::{ render_resource::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor,
BindGroupLayoutEntry, BindingType, BufferBindingType, ColorTargetState, ColorWrites, BindGroupLayoutEntry, BindingType, BufferBindingType, ColorTargetState, ColorWrites,
CompareFunction, DepthBiasState, DepthStencilState, DynamicUniformBuffer, FragmentState, CompareFunction, DepthBiasState, DepthStencilState, DynamicUniformBuffer, FragmentState,
FrontFace, MultisampleState, PipelineCache, PolygonMode, PrimitiveState, PushConstantRange, FrontFace, MultisampleState, PipelineCache, PolygonMode, PrimitiveState, PushConstantRange,
@ -713,42 +713,22 @@ pub fn prepare_prepass_view_bind_group<M: Material>(
view_uniforms.uniforms.binding(), view_uniforms.uniforms.binding(),
globals_buffer.buffer.binding(), globals_buffer.buffer.binding(),
) { ) {
prepass_view_bind_group.no_motion_vectors = prepass_view_bind_group.no_motion_vectors = Some(render_device.create_bind_group(
Some(render_device.create_bind_group(&BindGroupDescriptor { "prepass_view_no_motion_vectors_bind_group",
entries: &[ &prepass_pipeline.view_layout_no_motion_vectors,
BindGroupEntry { &BindGroupEntries::sequential((view_binding.clone(), globals_binding.clone())),
binding: 0, ));
resource: view_binding.clone(),
},
BindGroupEntry {
binding: 1,
resource: globals_binding.clone(),
},
],
label: Some("prepass_view_no_motion_vectors_bind_group"),
layout: &prepass_pipeline.view_layout_no_motion_vectors,
}));
if let Some(previous_view_proj_binding) = previous_view_proj_uniforms.uniforms.binding() { if let Some(previous_view_proj_binding) = previous_view_proj_uniforms.uniforms.binding() {
prepass_view_bind_group.motion_vectors = prepass_view_bind_group.motion_vectors = Some(render_device.create_bind_group(
Some(render_device.create_bind_group(&BindGroupDescriptor { "prepass_view_motion_vectors_bind_group",
entries: &[ &prepass_pipeline.view_layout_motion_vectors,
BindGroupEntry { &BindGroupEntries::sequential((
binding: 0, view_binding,
resource: view_binding, globals_binding,
}, previous_view_proj_binding,
BindGroupEntry { )),
binding: 1, ));
resource: globals_binding,
},
BindGroupEntry {
binding: 2,
resource: previous_view_proj_binding,
},
],
label: Some("prepass_view_motion_vectors_bind_group"),
layout: &prepass_pipeline.view_layout_motion_vectors,
}));
} }
} }
} }

View File

@ -1,7 +1,7 @@
use bevy_core_pipeline::prepass::ViewPrepassTextures; use bevy_core_pipeline::prepass::ViewPrepassTextures;
use bevy_render::render_resource::{ use bevy_render::render_resource::{
BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, ShaderStages, BindGroupLayoutEntry, BindingType, ShaderStages, TextureAspect, TextureSampleType, TextureView,
TextureAspect, TextureSampleType, TextureView, TextureViewDescriptor, TextureViewDimension, TextureViewDescriptor, TextureViewDimension,
}; };
use bevy_utils::default; use bevy_utils::default;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -83,51 +83,7 @@ pub fn get_bind_group_layout_entries(
result result
} }
// Needed so the texture views can live long enough. pub fn get_bindings(prepass_textures: Option<&ViewPrepassTextures>) -> [Option<TextureView>; 4] {
pub struct PrepassBindingsSet {
depth_view: Option<TextureView>,
normal_view: Option<TextureView>,
motion_vectors_view: Option<TextureView>,
deferred_view: Option<TextureView>,
}
impl PrepassBindingsSet {
pub fn get_entries(&self, bindings: [u32; 4]) -> SmallVec<[BindGroupEntry; 4]> {
let mut result = SmallVec::<[BindGroupEntry; 4]>::new();
if let Some(ref depth_view) = self.depth_view {
result.push(BindGroupEntry {
binding: bindings[0],
resource: BindingResource::TextureView(depth_view),
});
}
if let Some(ref normal_view) = self.normal_view {
result.push(BindGroupEntry {
binding: bindings[1],
resource: BindingResource::TextureView(normal_view),
});
}
if let Some(ref motion_vectors_view) = self.motion_vectors_view {
result.push(BindGroupEntry {
binding: bindings[2],
resource: BindingResource::TextureView(motion_vectors_view),
});
}
if let Some(ref deferred_view) = self.deferred_view {
result.push(BindGroupEntry {
binding: bindings[3],
resource: BindingResource::TextureView(deferred_view),
});
}
result
}
}
pub fn get_bindings(prepass_textures: Option<&ViewPrepassTextures>) -> PrepassBindingsSet {
let depth_desc = TextureViewDescriptor { let depth_desc = TextureViewDescriptor {
label: Some("prepass_depth"), label: Some("prepass_depth"),
aspect: TextureAspect::DepthOnly, aspect: TextureAspect::DepthOnly,
@ -149,10 +105,5 @@ pub fn get_bindings(prepass_textures: Option<&ViewPrepassTextures>) -> PrepassBi
.and_then(|x| x.deferred.as_ref()) .and_then(|x| x.deferred.as_ref())
.map(|texture| texture.default_view.clone()); .map(|texture| texture.default_view.clone());
PrepassBindingsSet { [depth_view, normal_view, motion_vectors_view, deferred_view]
depth_view,
normal_view,
motion_vectors_view,
deferred_view,
}
} }

View File

@ -4,8 +4,7 @@ use bevy_math::Mat4;
use bevy_render::{ use bevy_render::{
mesh::morph::MAX_MORPH_WEIGHTS, mesh::morph::MAX_MORPH_WEIGHTS,
render_resource::{ render_resource::{
BindGroup, BindGroupDescriptor, BindGroupLayout, BindGroupLayoutDescriptor, BindGroup, BindGroupLayout, BindGroupLayoutDescriptor, BindingResource, Buffer, TextureView,
BindingResource, Buffer, TextureView,
}, },
renderer::RenderDevice, renderer::RenderDevice,
}; };
@ -179,11 +178,11 @@ impl MeshLayouts {
// ---------- BindGroup methods ---------- // ---------- BindGroup methods ----------
pub fn model_only(&self, render_device: &RenderDevice, model: &BindingResource) -> BindGroup { pub fn model_only(&self, render_device: &RenderDevice, model: &BindingResource) -> BindGroup {
render_device.create_bind_group(&BindGroupDescriptor { render_device.create_bind_group(
entries: &[entry::model(0, model.clone())], "model_only_mesh_bind_group",
layout: &self.model_only, &self.model_only,
label: Some("model_only_mesh_bind_group"), &[entry::model(0, model.clone())],
}) )
} }
pub fn skinned( pub fn skinned(
&self, &self,
@ -191,11 +190,11 @@ impl MeshLayouts {
model: &BindingResource, model: &BindingResource,
skin: &Buffer, skin: &Buffer,
) -> BindGroup { ) -> BindGroup {
render_device.create_bind_group(&BindGroupDescriptor { render_device.create_bind_group(
entries: &[entry::model(0, model.clone()), entry::skinning(1, skin)], "skinned_mesh_bind_group",
layout: &self.skinned, &self.skinned,
label: Some("skinned_mesh_bind_group"), &[entry::model(0, model.clone()), entry::skinning(1, skin)],
}) )
} }
pub fn morphed( pub fn morphed(
&self, &self,
@ -204,15 +203,15 @@ impl MeshLayouts {
weights: &Buffer, weights: &Buffer,
targets: &TextureView, targets: &TextureView,
) -> BindGroup { ) -> BindGroup {
render_device.create_bind_group(&BindGroupDescriptor { render_device.create_bind_group(
entries: &[ "morphed_mesh_bind_group",
&self.morphed,
&[
entry::model(0, model.clone()), entry::model(0, model.clone()),
entry::weights(2, weights), entry::weights(2, weights),
entry::targets(3, targets), entry::targets(3, targets),
], ],
layout: &self.morphed, )
label: Some("morphed_mesh_bind_group"),
})
} }
pub fn morphed_skinned( pub fn morphed_skinned(
&self, &self,
@ -222,15 +221,15 @@ impl MeshLayouts {
weights: &Buffer, weights: &Buffer,
targets: &TextureView, targets: &TextureView,
) -> BindGroup { ) -> BindGroup {
render_device.create_bind_group(&BindGroupDescriptor { render_device.create_bind_group(
entries: &[ "morphed_skinned_mesh_bind_group",
&self.morphed_skinned,
&[
entry::model(0, model.clone()), entry::model(0, model.clone()),
entry::skinning(1, skin), entry::skinning(1, skin),
entry::weights(2, weights), entry::weights(2, weights),
entry::targets(3, targets), entry::targets(3, targets),
], ],
layout: &self.morphed_skinned, )
label: Some("morphed_skinned_mesh_bind_group"),
})
} }
} }

View File

@ -15,9 +15,9 @@ use bevy_render::{
globals::{GlobalsBuffer, GlobalsUniform}, globals::{GlobalsBuffer, GlobalsUniform},
render_asset::RenderAssets, render_asset::RenderAssets,
render_resource::{ render_resource::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroup, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType,
BindGroupLayoutEntry, BindingResource, BindingType, BufferBindingType, SamplerBindingType, BufferBindingType, DynamicBindGroupEntries, SamplerBindingType, ShaderStages, ShaderType,
ShaderStages, ShaderType, TextureFormat, TextureSampleType, TextureViewDimension, TextureFormat, TextureSampleType, TextureViewDimension,
}, },
renderer::RenderDevice, renderer::RenderDevice,
texture::{BevyDefault, FallbackImageCubemap, FallbackImageMsaa, Image}, texture::{BevyDefault, FallbackImageCubemap, FallbackImageMsaa, Image},
@ -383,8 +383,8 @@ pub fn prepare_mesh_view_bind_groups(
) { ) {
for ( for (
entity, entity,
view_shadow_bindings, shadow_bindings,
view_cluster_bindings, cluster_bindings,
ssao_textures, ssao_textures,
prepass_textures, prepass_textures,
environment_map, environment_map,
@ -395,108 +395,58 @@ pub fn prepare_mesh_view_bind_groups(
.image_for_samplecount(1, TextureFormat::bevy_default()) .image_for_samplecount(1, TextureFormat::bevy_default())
.texture_view .texture_view
.clone(); .clone();
let ssao_view = ssao_textures
.map(|t| &t.screen_space_ambient_occlusion_texture.default_view)
.unwrap_or(&fallback_ssao);
let layout = &mesh_pipeline.get_view_layout( let layout = &mesh_pipeline.get_view_layout(
MeshPipelineViewLayoutKey::from(*msaa) MeshPipelineViewLayoutKey::from(*msaa)
| MeshPipelineViewLayoutKey::from(prepass_textures), | MeshPipelineViewLayoutKey::from(prepass_textures),
); );
let mut entries = vec![ let mut entries = DynamicBindGroupEntries::new_with_indices((
BindGroupEntry { (0, view_binding.clone()),
binding: 0, (1, light_binding.clone()),
resource: view_binding.clone(), (2, &shadow_bindings.point_light_depth_texture_view),
}, (3, &shadow_samplers.point_light_sampler),
BindGroupEntry { (4, &shadow_bindings.directional_light_depth_texture_view),
binding: 1, (5, &shadow_samplers.directional_light_sampler),
resource: light_binding.clone(), (6, point_light_binding.clone()),
}, (7, cluster_bindings.light_index_lists_binding().unwrap()),
BindGroupEntry { (8, cluster_bindings.offsets_and_counts_binding().unwrap()),
binding: 2, (9, globals.clone()),
resource: BindingResource::TextureView( (10, fog_binding.clone()),
&view_shadow_bindings.point_light_depth_texture_view, (11, ssao_view),
), ));
},
BindGroupEntry {
binding: 3,
resource: BindingResource::Sampler(&shadow_samplers.point_light_sampler),
},
BindGroupEntry {
binding: 4,
resource: BindingResource::TextureView(
&view_shadow_bindings.directional_light_depth_texture_view,
),
},
BindGroupEntry {
binding: 5,
resource: BindingResource::Sampler(&shadow_samplers.directional_light_sampler),
},
BindGroupEntry {
binding: 6,
resource: point_light_binding.clone(),
},
BindGroupEntry {
binding: 7,
resource: view_cluster_bindings.light_index_lists_binding().unwrap(),
},
BindGroupEntry {
binding: 8,
resource: view_cluster_bindings.offsets_and_counts_binding().unwrap(),
},
BindGroupEntry {
binding: 9,
resource: globals.clone(),
},
BindGroupEntry {
binding: 10,
resource: fog_binding.clone(),
},
BindGroupEntry {
binding: 11,
resource: BindingResource::TextureView(
ssao_textures
.map(|t| &t.screen_space_ambient_occlusion_texture.default_view)
.unwrap_or(&fallback_ssao),
),
},
];
let env_map = environment_map::get_bindings( let env_map_bindings =
environment_map, environment_map::get_bindings(environment_map, &images, &fallback_cubemap);
&images, entries = entries.extend_with_indices((
&fallback_cubemap, (12, env_map_bindings.0),
[12, 13, 14], (13, env_map_bindings.1),
); (14, env_map_bindings.2),
entries.extend_from_slice(&env_map); ));
let tonemapping_luts = let lut_bindings = get_lut_bindings(&images, &tonemapping_luts, tonemapping);
get_lut_bindings(&images, &tonemapping_luts, tonemapping, [15, 16]); entries = entries.extend_with_indices(((15, lut_bindings.0), (16, lut_bindings.1)));
entries.extend_from_slice(&tonemapping_luts);
let label = Some("mesh_view_bind_group");
// When using WebGL, we can't have a depth texture with multisampling // When using WebGL, we can't have a depth texture with multisampling
let prepass_bindings = if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32"))) let prepass_bindings;
|| (cfg!(all(feature = "webgl", target_arch = "wasm32")) && msaa.samples() == 1) if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32"))) || msaa.samples() == 1
{ {
Some(prepass::get_bindings(prepass_textures)) prepass_bindings = prepass::get_bindings(prepass_textures);
} else { for (binding, index) in prepass_bindings
None .iter()
}; .map(Option::as_ref)
.zip([17, 18, 19, 20])
// This if statement is here to make the borrow checker happy. .flat_map(|(b, i)| b.map(|b| (b, i)))
// Ideally we could just have `entries.extend_from_slice(&prepass_bindings.get_entries([17, 18, 19, 20]));` {
// in the existing if statement above, but that either doesn't allow `prepass_bindings` to live long enough, entries = entries.extend_with_indices(((index, binding),));
// as its used when creating the bind group at the end of the function, or causes a `cannot move out of` error. }
if let Some(prepass_bindings) = &prepass_bindings {
entries.extend_from_slice(&prepass_bindings.get_entries([17, 18, 19, 20]));
} }
commands.entity(entity).insert(MeshViewBindGroup { commands.entity(entity).insert(MeshViewBindGroup {
value: render_device.create_bind_group(&BindGroupDescriptor { value: render_device.create_bind_group("mesh_view_bind_group", layout, &entries),
entries: &entries,
label,
layout,
}),
}); });
} }
} }

View File

@ -21,12 +21,11 @@ use bevy_render::{
prelude::Camera, prelude::Camera,
render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner}, render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner},
render_resource::{ render_resource::{
AddressMode, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, AddressMode, BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor,
BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BindGroupLayoutEntry, BindingType, BufferBindingType, CachedComputePipelineId,
BufferBindingType, CachedComputePipelineId, ComputePassDescriptor, ComputePassDescriptor, ComputePipelineDescriptor, Extent3d, FilterMode, PipelineCache,
ComputePipelineDescriptor, Extent3d, FilterMode, PipelineCache, Sampler, Sampler, SamplerBindingType, SamplerDescriptor, Shader, ShaderDefVal, ShaderStages,
SamplerBindingType, SamplerDescriptor, Shader, ShaderDefVal, ShaderStages, ShaderType, ShaderType, SpecializedComputePipeline, SpecializedComputePipelines, StorageTextureAccess,
SpecializedComputePipeline, SpecializedComputePipelines, StorageTextureAccess,
TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, TextureUsages,
TextureView, TextureViewDescriptor, TextureViewDimension, TextureView, TextureViewDescriptor, TextureViewDimension,
}, },
@ -776,171 +775,63 @@ fn prepare_ssao_bind_groups(
}; };
for (entity, ssao_textures, prepass_textures) in &views { for (entity, ssao_textures, prepass_textures) in &views {
let common_bind_group = render_device.create_bind_group(&BindGroupDescriptor { let common_bind_group = render_device.create_bind_group(
label: Some("ssao_common_bind_group"), "ssao_common_bind_group",
layout: &pipelines.common_bind_group_layout, &pipelines.common_bind_group_layout,
entries: &[ &BindGroupEntries::sequential((&pipelines.point_clamp_sampler, view_uniforms.clone())),
BindGroupEntry { );
binding: 0,
resource: BindingResource::Sampler(&pipelines.point_clamp_sampler),
},
BindGroupEntry {
binding: 1,
resource: view_uniforms.clone(),
},
],
});
let preprocess_depth_mip_view_descriptor = TextureViewDescriptor { let create_depth_view = |mip_level| {
format: Some(TextureFormat::R16Float), ssao_textures
dimension: Some(TextureViewDimension::D2), .preprocessed_depth_texture
mip_level_count: Some(1), .texture
..default() .create_view(&TextureViewDescriptor {
label: Some("ssao_preprocessed_depth_texture_mip_view"),
base_mip_level: mip_level,
format: Some(TextureFormat::R16Float),
dimension: Some(TextureViewDimension::D2),
mip_level_count: Some(1),
..default()
})
}; };
let preprocess_depth_bind_group = render_device.create_bind_group(&BindGroupDescriptor { let preprocess_depth_bind_group = render_device.create_bind_group(
label: Some("ssao_preprocess_depth_bind_group"), "ssao_preprocess_depth_bind_group",
layout: &pipelines.preprocess_depth_bind_group_layout, &pipelines.preprocess_depth_bind_group_layout,
entries: &[ &BindGroupEntries::sequential((
BindGroupEntry { &prepass_textures.depth.as_ref().unwrap().default_view,
binding: 0, &create_depth_view(0),
resource: BindingResource::TextureView( &create_depth_view(1),
&prepass_textures.depth.as_ref().unwrap().default_view, &create_depth_view(2),
), &create_depth_view(3),
}, &create_depth_view(4),
BindGroupEntry { )),
binding: 1, );
resource: BindingResource::TextureView(
&ssao_textures
.preprocessed_depth_texture
.texture
.create_view(&TextureViewDescriptor {
label: Some("ssao_preprocessed_depth_texture_mip_view_0"),
base_mip_level: 0,
..preprocess_depth_mip_view_descriptor
}),
),
},
BindGroupEntry {
binding: 2,
resource: BindingResource::TextureView(
&ssao_textures
.preprocessed_depth_texture
.texture
.create_view(&TextureViewDescriptor {
label: Some("ssao_preprocessed_depth_texture_mip_view_1"),
base_mip_level: 1,
..preprocess_depth_mip_view_descriptor
}),
),
},
BindGroupEntry {
binding: 3,
resource: BindingResource::TextureView(
&ssao_textures
.preprocessed_depth_texture
.texture
.create_view(&TextureViewDescriptor {
label: Some("ssao_preprocessed_depth_texture_mip_view_2"),
base_mip_level: 2,
..preprocess_depth_mip_view_descriptor
}),
),
},
BindGroupEntry {
binding: 4,
resource: BindingResource::TextureView(
&ssao_textures
.preprocessed_depth_texture
.texture
.create_view(&TextureViewDescriptor {
label: Some("ssao_preprocessed_depth_texture_mip_view_3"),
base_mip_level: 3,
..preprocess_depth_mip_view_descriptor
}),
),
},
BindGroupEntry {
binding: 5,
resource: BindingResource::TextureView(
&ssao_textures
.preprocessed_depth_texture
.texture
.create_view(&TextureViewDescriptor {
label: Some("ssao_preprocessed_depth_texture_mip_view_4"),
base_mip_level: 4,
..preprocess_depth_mip_view_descriptor
}),
),
},
],
});
let gtao_bind_group = render_device.create_bind_group(&BindGroupDescriptor { let gtao_bind_group = render_device.create_bind_group(
label: Some("ssao_gtao_bind_group"), "ssao_gtao_bind_group",
layout: &pipelines.gtao_bind_group_layout, &pipelines.gtao_bind_group_layout,
entries: &[ &BindGroupEntries::sequential((
BindGroupEntry { &ssao_textures.preprocessed_depth_texture.default_view,
binding: 0, &prepass_textures.normal.as_ref().unwrap().default_view,
resource: BindingResource::TextureView( &pipelines.hilbert_index_lut,
&ssao_textures.preprocessed_depth_texture.default_view, &ssao_textures.ssao_noisy_texture.default_view,
), &ssao_textures.depth_differences_texture.default_view,
}, globals_uniforms.clone(),
BindGroupEntry { )),
binding: 1, );
resource: BindingResource::TextureView(
&prepass_textures.normal.as_ref().unwrap().default_view,
),
},
BindGroupEntry {
binding: 2,
resource: BindingResource::TextureView(&pipelines.hilbert_index_lut),
},
BindGroupEntry {
binding: 3,
resource: BindingResource::TextureView(
&ssao_textures.ssao_noisy_texture.default_view,
),
},
BindGroupEntry {
binding: 4,
resource: BindingResource::TextureView(
&ssao_textures.depth_differences_texture.default_view,
),
},
BindGroupEntry {
binding: 5,
resource: globals_uniforms.clone(),
},
],
});
let spatial_denoise_bind_group = render_device.create_bind_group(&BindGroupDescriptor { let spatial_denoise_bind_group = render_device.create_bind_group(
label: Some("ssao_spatial_denoise_bind_group"), "ssao_spatial_denoise_bind_group",
layout: &pipelines.spatial_denoise_bind_group_layout, &pipelines.spatial_denoise_bind_group_layout,
entries: &[ &BindGroupEntries::sequential((
BindGroupEntry { &ssao_textures.ssao_noisy_texture.default_view,
binding: 0, &ssao_textures.depth_differences_texture.default_view,
resource: BindingResource::TextureView( &ssao_textures
&ssao_textures.ssao_noisy_texture.default_view, .screen_space_ambient_occlusion_texture
), .default_view,
}, )),
BindGroupEntry { );
binding: 1,
resource: BindingResource::TextureView(
&ssao_textures.depth_differences_texture.default_view,
),
},
BindGroupEntry {
binding: 2,
resource: BindingResource::TextureView(
&ssao_textures
.screen_space_ambient_occlusion_texture
.default_view,
),
},
],
});
commands.entity(entity).insert(SsaoBindGroups { commands.entity(entity).insert(SsaoBindGroups {
common_bind_group, common_bind_group,

View File

@ -9,10 +9,7 @@ use crate::{
pub use bevy_render_macros::AsBindGroup; pub use bevy_render_macros::AsBindGroup;
use encase::ShaderType; use encase::ShaderType;
use std::ops::Deref; use std::ops::Deref;
use wgpu::{ use wgpu::{BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource};
BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
BindingResource,
};
define_atomic_id!(BindGroupId); define_atomic_id!(BindGroupId);
render_resource_wrapper!(ErasedBindGroup, wgpu::BindGroup); render_resource_wrapper!(ErasedBindGroup, wgpu::BindGroup);
@ -289,11 +286,7 @@ pub trait AsBindGroup {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let bind_group = render_device.create_bind_group(&BindGroupDescriptor { let bind_group = render_device.create_bind_group(Self::label(), layout, &entries);
label: Self::label(),
layout,
entries: &entries,
});
Ok(PreparedBindGroup { Ok(PreparedBindGroup {
bindings, bindings,

View File

@ -0,0 +1,282 @@
use bevy_utils::all_tuples_with_size;
use wgpu::{BindGroupEntry, BindingResource};
use super::{Sampler, TextureView};
/// Helper for constructing bindgroups.
///
/// Allows constructing the descriptor's entries as:
/// ```ignore
/// render_device.create_bind_group(
/// "my_bind_group",
/// &my_layout,
/// &BindGroupEntries::with_indices((
/// (2, &my_sampler),
/// (3, my_uniform),
/// )),
/// );
/// ```
///
/// instead of
///
/// ```ignore
/// render_device.create_bind_group(
/// "my_bind_group",
/// &my_layout,
/// &[
/// BindGroupEntry {
/// binding: 2,
/// resource: BindingResource::Sampler(&my_sampler),
/// },
/// BindGroupEntry {
/// binding: 3,
/// resource: my_uniform,
/// },
/// ],
/// );
/// ```
///
/// or
///
/// ```ignore
/// render_device.create_bind_group(
/// "my_bind_group",
/// &my_layout,
/// &BindGroupEntries::sequential((
/// &my_sampler,
/// my_uniform,
/// )),
/// );
/// ```
///
/// instead of
///
/// ```ignore
/// render_device.create_bind_group(
/// "my_bind_group",
/// &my_layout,
/// &[
/// BindGroupEntry {
/// binding: 0,
/// resource: BindingResource::Sampler(&my_sampler),
/// },
/// BindGroupEntry {
/// binding: 1,
/// resource: my_uniform,
/// },
/// ],
/// );
/// ```
///
/// or
///
/// ```ignore
/// render_device.create_bind_group(
/// "my_bind_group",
/// &my_layout,
/// &BindGroupEntries::single(my_uniform),
/// );
/// ```
///
/// instead of
///
/// ```ignore
/// render_device.create_bind_group(
/// "my_bind_group",
/// &my_layout,
/// &[
/// BindGroupEntry {
/// binding: 0,
/// resource: my_uniform,
/// },
/// ],
/// );
/// ```
pub struct BindGroupEntries<'b, const N: usize = 1> {
entries: [BindGroupEntry<'b>; N],
}
impl<'b, const N: usize> BindGroupEntries<'b, N> {
#[inline]
pub fn sequential(resources: impl IntoBindingArray<'b, N>) -> Self {
let mut i = 0;
Self {
entries: resources.into_array().map(|resource| {
let binding = i;
i += 1;
BindGroupEntry { binding, resource }
}),
}
}
#[inline]
pub fn with_indices(indexed_resources: impl IntoIndexedBindingArray<'b, N>) -> Self {
Self {
entries: indexed_resources
.into_array()
.map(|(binding, resource)| BindGroupEntry { binding, resource }),
}
}
}
impl<'b> BindGroupEntries<'b, 1> {
pub fn single(resource: impl IntoBinding<'b>) -> [BindGroupEntry<'b>; 1] {
[BindGroupEntry {
binding: 0,
resource: resource.into_binding(),
}]
}
}
impl<'b, const N: usize> std::ops::Deref for BindGroupEntries<'b, N> {
type Target = [BindGroupEntry<'b>];
fn deref(&self) -> &[BindGroupEntry<'b>] {
&self.entries
}
}
pub trait IntoBinding<'a> {
fn into_binding(self) -> BindingResource<'a>;
}
impl<'a> IntoBinding<'a> for &'a TextureView {
#[inline]
fn into_binding(self) -> BindingResource<'a> {
BindingResource::TextureView(self)
}
}
impl<'a> IntoBinding<'a> for &'a [&'a wgpu::TextureView] {
#[inline]
fn into_binding(self) -> BindingResource<'a> {
BindingResource::TextureViewArray(self)
}
}
impl<'a> IntoBinding<'a> for &'a Sampler {
#[inline]
fn into_binding(self) -> BindingResource<'a> {
BindingResource::Sampler(self)
}
}
impl<'a> IntoBinding<'a> for BindingResource<'a> {
#[inline]
fn into_binding(self) -> BindingResource<'a> {
self
}
}
impl<'a> IntoBinding<'a> for wgpu::BufferBinding<'a> {
#[inline]
fn into_binding(self) -> BindingResource<'a> {
BindingResource::Buffer(self)
}
}
pub trait IntoBindingArray<'b, const N: usize> {
fn into_array(self) -> [BindingResource<'b>; N];
}
macro_rules! impl_to_binding_slice {
($N: expr, $(($T: ident, $I: ident)),*) => {
impl<'b, $($T: IntoBinding<'b>),*> IntoBindingArray<'b, $N> for ($($T,)*) {
#[inline]
fn into_array(self) -> [BindingResource<'b>; $N] {
let ($($I,)*) = self;
[$($I.into_binding(), )*]
}
}
}
}
all_tuples_with_size!(impl_to_binding_slice, 1, 32, T, s);
pub trait IntoIndexedBindingArray<'b, const N: usize> {
fn into_array(self) -> [(u32, BindingResource<'b>); N];
}
macro_rules! impl_to_indexed_binding_slice {
($N: expr, $(($T: ident, $S: ident, $I: ident)),*) => {
impl<'b, $($T: IntoBinding<'b>),*> IntoIndexedBindingArray<'b, $N> for ($((u32, $T),)*) {
#[inline]
fn into_array(self) -> [(u32, BindingResource<'b>); $N] {
let ($(($S, $I),)*) = self;
[$(($S, $I.into_binding())), *]
}
}
}
}
all_tuples_with_size!(impl_to_indexed_binding_slice, 1, 32, T, n, s);
pub struct DynamicBindGroupEntries<'b> {
entries: Vec<BindGroupEntry<'b>>,
}
impl<'b> DynamicBindGroupEntries<'b> {
pub fn sequential<const N: usize>(entries: impl IntoBindingArray<'b, N>) -> Self {
Self {
entries: entries
.into_array()
.into_iter()
.enumerate()
.map(|(ix, resource)| BindGroupEntry {
binding: ix as u32,
resource,
})
.collect(),
}
}
pub fn extend_sequential<const N: usize>(
mut self,
entries: impl IntoBindingArray<'b, N>,
) -> Self {
let start = self.entries.last().unwrap().binding + 1;
self.entries.extend(
entries
.into_array()
.into_iter()
.enumerate()
.map(|(ix, resource)| BindGroupEntry {
binding: start + ix as u32,
resource,
}),
);
self
}
pub fn new_with_indices<const N: usize>(entries: impl IntoIndexedBindingArray<'b, N>) -> Self {
Self {
entries: entries
.into_array()
.into_iter()
.map(|(binding, resource)| BindGroupEntry { binding, resource })
.collect(),
}
}
pub fn extend_with_indices<const N: usize>(
mut self,
entries: impl IntoIndexedBindingArray<'b, N>,
) -> Self {
self.entries.extend(
entries
.into_array()
.into_iter()
.map(|(binding, resource)| BindGroupEntry { binding, resource }),
);
self
}
}
impl<'b> std::ops::Deref for DynamicBindGroupEntries<'b> {
type Target = [BindGroupEntry<'b>];
fn deref(&self) -> &[BindGroupEntry<'b>] {
&self.entries
}
}

View File

@ -1,5 +1,6 @@
mod batched_uniform_buffer; mod batched_uniform_buffer;
mod bind_group; mod bind_group;
mod bind_group_entries;
mod bind_group_layout; mod bind_group_layout;
mod buffer; mod buffer;
mod buffer_vec; mod buffer_vec;
@ -14,6 +15,7 @@ mod texture;
mod uniform_buffer; mod uniform_buffer;
pub use bind_group::*; pub use bind_group::*;
pub use bind_group_entries::*;
pub use bind_group_layout::*; pub use bind_group_layout::*;
pub use buffer::*; pub use buffer::*;
pub use buffer_vec::*; pub use buffer_vec::*;

View File

@ -13,6 +13,8 @@ use wgpu::{
util::BufferInitDescriptor, BindingResource, BufferBinding, BufferDescriptor, BufferUsages, util::BufferInitDescriptor, BindingResource, BufferBinding, BufferDescriptor, BufferUsages,
}; };
use super::IntoBinding;
/// Stores data to be transferred to the GPU and made accessible to shaders as a uniform buffer. /// Stores data to be transferred to the GPU and made accessible to shaders as a uniform buffer.
/// ///
/// Uniform buffers are available to shaders on a read-only basis. Uniform buffers are commonly used to make available to shaders /// Uniform buffers are available to shaders on a read-only basis. Uniform buffers are commonly used to make available to shaders
@ -139,6 +141,16 @@ impl<T: ShaderType + WriteInto> UniformBuffer<T> {
} }
} }
impl<'a, T: ShaderType + WriteInto> IntoBinding<'a> for &'a UniformBuffer<T> {
#[inline]
fn into_binding(self) -> BindingResource<'a> {
self.buffer()
.expect("Failed to get buffer")
.as_entire_buffer_binding()
.into_binding()
}
}
/// Stores data to be transferred to the GPU and made accessible to shaders as a dynamic uniform buffer. /// Stores data to be transferred to the GPU and made accessible to shaders as a dynamic uniform buffer.
/// ///
/// Dynamic uniform buffers are available to shaders on a read-only basis. Dynamic uniform buffers are commonly used to make /// Dynamic uniform buffers are available to shaders on a read-only basis. Dynamic uniform buffers are commonly used to make
@ -367,3 +379,10 @@ impl<'a> BufferMut for QueueWriteBufferViewWrapper<'a> {
self.buffer_view.write(offset, val); self.buffer_view.write(offset, val);
} }
} }
impl<'a, T: ShaderType + WriteInto> IntoBinding<'a> for &'a DynamicUniformBuffer<T> {
#[inline]
fn into_binding(self) -> BindingResource<'a> {
self.binding().unwrap()
}
}

View File

@ -3,7 +3,9 @@ use crate::render_resource::{
RenderPipeline, Sampler, Texture, RenderPipeline, Sampler, Texture,
}; };
use bevy_ecs::system::Resource; use bevy_ecs::system::Resource;
use wgpu::{util::DeviceExt, BufferAsyncError, BufferBindingType}; use wgpu::{
util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BufferAsyncError, BufferBindingType,
};
use super::RenderQueue; use super::RenderQueue;
@ -82,8 +84,17 @@ impl RenderDevice {
/// Creates a new [`BindGroup`](wgpu::BindGroup). /// Creates a new [`BindGroup`](wgpu::BindGroup).
#[inline] #[inline]
pub fn create_bind_group(&self, desc: &wgpu::BindGroupDescriptor) -> BindGroup { pub fn create_bind_group<'a>(
let wgpu_bind_group = self.device.create_bind_group(desc); &self,
label: impl Into<wgpu::Label<'a>>,
layout: &'a BindGroupLayout,
entries: &'a [BindGroupEntry<'a>],
) -> BindGroup {
let wgpu_bind_group = self.device.create_bind_group(&BindGroupDescriptor {
label: label.into(),
layout,
entries,
});
BindGroup::from(wgpu_bind_group) BindGroup::from(wgpu_bind_group)
} }

View File

@ -1,5 +1,7 @@
use crate::{ use crate::{
render_resource::{PipelineCache, SpecializedRenderPipelines, SurfaceTexture, TextureView}, render_resource::{
BindGroupEntries, PipelineCache, SpecializedRenderPipelines, SurfaceTexture, TextureView,
},
renderer::{RenderAdapter, RenderDevice, RenderInstance}, renderer::{RenderAdapter, RenderDevice, RenderInstance},
texture::TextureFormatPixelInfo, texture::TextureFormatPixelInfo,
Extract, ExtractSchedule, Render, RenderApp, RenderSet, Extract, ExtractSchedule, Render, RenderApp, RenderSet,
@ -413,14 +415,11 @@ pub fn prepare_windows(
usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST, usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST,
mapped_at_creation: false, mapped_at_creation: false,
}); });
let bind_group = render_device.create_bind_group(&wgpu::BindGroupDescriptor { let bind_group = render_device.create_bind_group(
label: Some("screenshot-to-screen-bind-group"), "screenshot-to-screen-bind-group",
layout: &screenshot_pipeline.bind_group_layout, &screenshot_pipeline.bind_group_layout,
entries: &[wgpu::BindGroupEntry { &BindGroupEntries::single(&texture_view),
binding: 0, );
resource: wgpu::BindingResource::TextureView(&texture_view),
}],
});
let pipeline_id = pipelines.specialize( let pipeline_id = pipelines.specialize(
&pipeline_cache, &pipeline_cache,
&screenshot_pipeline, &screenshot_pipeline,

View File

@ -596,14 +596,11 @@ pub fn prepare_mesh2d_bind_group(
) { ) {
if let Some(binding) = mesh2d_uniforms.binding() { if let Some(binding) = mesh2d_uniforms.binding() {
commands.insert_resource(Mesh2dBindGroup { commands.insert_resource(Mesh2dBindGroup {
value: render_device.create_bind_group(&BindGroupDescriptor { value: render_device.create_bind_group(
entries: &[BindGroupEntry { "mesh2d_bind_group",
binding: 0, &mesh2d_pipeline.mesh_layout,
resource: binding, &BindGroupEntries::single(binding),
}], ),
label: Some("mesh2d_bind_group"),
layout: &mesh2d_pipeline.mesh_layout,
}),
}); });
} }
} }
@ -626,20 +623,11 @@ pub fn prepare_mesh2d_view_bind_groups(
globals_buffer.buffer.binding(), globals_buffer.buffer.binding(),
) { ) {
for entity in &views { for entity in &views {
let view_bind_group = render_device.create_bind_group(&BindGroupDescriptor { let view_bind_group = render_device.create_bind_group(
entries: &[ "mesh2d_view_bind_group",
BindGroupEntry { &mesh2d_pipeline.view_layout,
binding: 0, &BindGroupEntries::sequential((view_binding.clone(), globals.clone())),
resource: view_binding.clone(), );
},
BindGroupEntry {
binding: 1,
resource: globals.clone(),
},
],
label: Some("mesh2d_view_bind_group"),
layout: &mesh2d_pipeline.view_layout,
});
commands.entity(entity).insert(Mesh2dViewBindGroup { commands.entity(entity).insert(Mesh2dViewBindGroup {
value: view_bind_group, value: view_bind_group,

View File

@ -21,7 +21,7 @@ use bevy_render::{
DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, SetItemPipeline, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, SetItemPipeline,
TrackedRenderPass, TrackedRenderPass,
}, },
render_resource::*, render_resource::{BindGroupEntries, *},
renderer::{RenderDevice, RenderQueue}, renderer::{RenderDevice, RenderQueue},
texture::{ texture::{
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo, BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
@ -623,14 +623,11 @@ pub fn prepare_sprites(
// Clear the sprite instances // Clear the sprite instances
sprite_meta.sprite_instance_buffer.clear(); sprite_meta.sprite_instance_buffer.clear();
sprite_meta.view_bind_group = Some(render_device.create_bind_group(&BindGroupDescriptor { sprite_meta.view_bind_group = Some(render_device.create_bind_group(
entries: &[BindGroupEntry { "sprite_view_bind_group",
binding: 0, &sprite_pipeline.view_layout,
resource: view_binding, &BindGroupEntries::single(view_binding),
}], ));
label: Some("sprite_view_bind_group"),
layout: &sprite_pipeline.view_layout,
}));
// Index buffer indices // Index buffer indices
let mut index = 0; let mut index = 0;
@ -667,22 +664,14 @@ pub fn prepare_sprites(
.values .values
.entry(batch_image_handle) .entry(batch_image_handle)
.or_insert_with(|| { .or_insert_with(|| {
render_device.create_bind_group(&BindGroupDescriptor { render_device.create_bind_group(
entries: &[ "sprite_material_bind_group",
BindGroupEntry { &sprite_pipeline.material_layout,
binding: 0, &BindGroupEntries::sequential((
resource: BindingResource::TextureView( &gpu_image.texture_view,
&gpu_image.texture_view, &gpu_image.sampler,
), )),
}, )
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&gpu_image.sampler),
},
],
label: Some("sprite_material_bind_group"),
layout: &sprite_pipeline.material_layout,
})
}); });
} }

View File

@ -5,7 +5,7 @@ use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d};
use bevy_hierarchy::Parent; use bevy_hierarchy::Parent;
use bevy_render::render_phase::PhaseItem; use bevy_render::render_phase::PhaseItem;
use bevy_render::view::ViewVisibility; use bevy_render::view::ViewVisibility;
use bevy_render::{ExtractSchedule, Render}; use bevy_render::{render_resource::BindGroupEntries, ExtractSchedule, Render};
use bevy_window::{PrimaryWindow, Window}; use bevy_window::{PrimaryWindow, Window};
pub use pipeline::*; pub use pipeline::*;
pub use render_pass::*; pub use render_pass::*;
@ -812,14 +812,11 @@ pub fn prepare_uinodes(
let mut batches: Vec<(Entity, UiBatch)> = Vec::with_capacity(*previous_len); let mut batches: Vec<(Entity, UiBatch)> = Vec::with_capacity(*previous_len);
ui_meta.vertices.clear(); ui_meta.vertices.clear();
ui_meta.view_bind_group = Some(render_device.create_bind_group(&BindGroupDescriptor { ui_meta.view_bind_group = Some(render_device.create_bind_group(
entries: &[BindGroupEntry { "ui_view_bind_group",
binding: 0, &ui_pipeline.view_layout,
resource: view_binding, &BindGroupEntries::single(view_binding),
}], ));
label: Some("ui_view_bind_group"),
layout: &ui_pipeline.view_layout,
}));
// Vertex buffer index // Vertex buffer index
let mut index = 0; let mut index = 0;
@ -851,24 +848,14 @@ pub fn prepare_uinodes(
.values .values
.entry(batch_image_handle) .entry(batch_image_handle)
.or_insert_with(|| { .or_insert_with(|| {
render_device.create_bind_group(&BindGroupDescriptor { render_device.create_bind_group(
entries: &[ "ui_material_bind_group",
BindGroupEntry { &ui_pipeline.image_layout,
binding: 0, &BindGroupEntries::sequential((
resource: BindingResource::TextureView( &gpu_image.texture_view,
&gpu_image.texture_view, &gpu_image.sampler,
), )),
}, )
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(
&gpu_image.sampler,
),
},
],
label: Some("ui_material_bind_group"),
layout: &ui_pipeline.image_layout,
})
}); });
existing_batch = batches.last_mut(); existing_batch = batches.last_mut();

View File

@ -136,3 +136,38 @@ pub fn all_tuples(input: TokenStream) -> TokenStream {
)* )*
}) })
} }
#[proc_macro]
pub fn all_tuples_with_size(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as AllTuples);
let len = 1 + input.end - input.start;
let mut ident_tuples = Vec::with_capacity(len);
for i in 0..=len {
let idents = input
.idents
.iter()
.map(|ident| format_ident!("{}{}", ident, i));
if input.idents.len() < 2 {
ident_tuples.push(quote! {
#(#idents)*
});
} else {
ident_tuples.push(quote! {
(#(#idents),*)
});
}
}
let macro_ident = &input.macro_ident;
let invocations = (input.start..=input.end).map(|i| {
let ident_tuples = &ident_tuples[..i];
quote! {
#macro_ident!(#i, #(#ident_tuples),*);
}
});
TokenStream::from(quote! {
#(
#invocations
)*
})
}

View File

@ -107,14 +107,11 @@ fn prepare_bind_group(
render_device: Res<RenderDevice>, render_device: Res<RenderDevice>,
) { ) {
let view = gpu_images.get(&game_of_life_image.0).unwrap(); let view = gpu_images.get(&game_of_life_image.0).unwrap();
let bind_group = render_device.create_bind_group(&BindGroupDescriptor { let bind_group = render_device.create_bind_group(
label: None, None,
layout: &pipeline.texture_bind_group_layout, &pipeline.texture_bind_group_layout,
entries: &[BindGroupEntry { &BindGroupEntries::single(&view.texture_view),
binding: 0, );
resource: BindingResource::TextureView(&view.texture_view),
}],
});
commands.insert_resource(GameOfLifeImageBindGroup(bind_group)); commands.insert_resource(GameOfLifeImageBindGroup(bind_group));
} }

View File

@ -20,12 +20,12 @@ use bevy::{
NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner, NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner,
}, },
render_resource::{ render_resource::{
BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
BindGroupLayoutEntry, BindingResource, BindingType, CachedRenderPipelineId, BindingType, CachedRenderPipelineId, ColorTargetState, ColorWrites, FragmentState,
ColorTargetState, ColorWrites, FragmentState, MultisampleState, Operations, MultisampleState, Operations, PipelineCache, PrimitiveState, RenderPassColorAttachment,
PipelineCache, PrimitiveState, RenderPassColorAttachment, RenderPassDescriptor, RenderPassDescriptor, RenderPipelineDescriptor, Sampler, SamplerBindingType,
RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages, SamplerDescriptor, ShaderStages, ShaderType, TextureFormat, TextureSampleType,
ShaderType, TextureFormat, TextureSampleType, TextureViewDimension, TextureViewDimension,
}, },
renderer::{RenderContext, RenderDevice}, renderer::{RenderContext, RenderDevice},
texture::BevyDefault, texture::BevyDefault,
@ -176,30 +176,19 @@ impl ViewNode for PostProcessNode {
// The reason it doesn't work is because each post_process_write will alternate the source/destination. // The reason it doesn't work is because each post_process_write will alternate the source/destination.
// The only way to have the correct source/destination for the bind_group // The only way to have the correct source/destination for the bind_group
// is to make sure you get it during the node execution. // is to make sure you get it during the node execution.
let bind_group = render_context let bind_group = render_context.render_device().create_bind_group(
.render_device() "post_process_bind_group",
.create_bind_group(&BindGroupDescriptor { &post_process_pipeline.layout,
label: Some("post_process_bind_group"), // It's important for this to match the BindGroupLayout defined in the PostProcessPipeline
layout: &post_process_pipeline.layout, &BindGroupEntries::sequential((
// It's important for this to match the BindGroupLayout defined in the PostProcessPipeline // Make sure to use the source view
entries: &[ post_process.source,
BindGroupEntry { // Use the sampler created for the pipeline
binding: 0, &post_process_pipeline.sampler,
// Make sure to use the source view // Set the settings binding
resource: BindingResource::TextureView(post_process.source), settings_binding.clone(),
}, )),
BindGroupEntry { );
binding: 1,
// Use the sampler created for the pipeline
resource: BindingResource::Sampler(&post_process_pipeline.sampler),
},
BindGroupEntry {
binding: 2,
// Set the settings binding
resource: settings_binding.clone(),
},
],
});
// Begin the render pass // Begin the render pass
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor { let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {

View File

@ -5,11 +5,8 @@ use bevy::{
prelude::*, prelude::*,
reflect::TypePath, reflect::TypePath,
render::{ render::{
render_asset::RenderAssets, render_asset::RenderAssets, render_resource::*, renderer::RenderDevice,
render_resource::{AsBindGroupError, PreparedBindGroup, *}, texture::FallbackImage, RenderApp,
renderer::RenderDevice,
texture::FallbackImage,
RenderApp,
}, },
}; };
use std::{num::NonZeroU32, process::exit}; use std::{num::NonZeroU32, process::exit};
@ -119,20 +116,11 @@ impl AsBindGroup for BindlessMaterial {
textures[id] = &*image.texture_view; textures[id] = &*image.texture_view;
} }
let bind_group = render_device.create_bind_group(&BindGroupDescriptor { let bind_group = render_device.create_bind_group(
label: "bindless_material_bind_group".into(), "bindless_material_bind_group",
layout, layout,
entries: &[ &BindGroupEntries::sequential((&textures[..], &fallback_image.sampler)),
BindGroupEntry { );
binding: 0,
resource: BindingResource::TextureViewArray(&textures[..]),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(&fallback_image.sampler),
},
],
});
Ok(PreparedBindGroup { Ok(PreparedBindGroup {
bindings: vec![], bindings: vec![],