Struct bevy::render::renderer::RenderDevice
source · pub struct RenderDevice { /* private fields */ }
Expand description
This GPU device is responsible for the creation of most rendering and compute resources.
Implementations§
source§impl RenderDevice
impl RenderDevice
sourcepub fn features(&self) -> Features
pub fn features(&self) -> Features
List all Features
that may be used with this device.
Functions may panic if you use unsupported features.
Examples found in repository?
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
fn finish(&self, app: &mut App) {
let Ok(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
let render_device = render_app.world.resource::<RenderDevice>();
// Check if the device support the required feature. If not, exit the example.
// In a real application, you should setup a fallback for the missing feature
if !render_device
.features()
.contains(WgpuFeatures::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING)
{
error!(
"Render device doesn't support feature \
SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, \
which is required for texture binding arrays"
);
exit(1);
}
}
More examples
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
fn cycle_cubemap_asset(
time: Res<Time>,
mut next_swap: Local<f32>,
mut cubemap: ResMut<Cubemap>,
asset_server: Res<AssetServer>,
render_device: Res<RenderDevice>,
) {
let now = time.elapsed_seconds();
if *next_swap == 0.0 {
*next_swap = now + CUBEMAP_SWAP_DELAY;
return;
} else if now < *next_swap {
return;
}
*next_swap += CUBEMAP_SWAP_DELAY;
let supported_compressed_formats =
CompressedImageFormats::from_features(render_device.features());
let mut new_index = cubemap.index;
for _ in 0..CUBEMAPS.len() {
new_index = (new_index + 1) % CUBEMAPS.len();
if supported_compressed_formats.contains(CUBEMAPS[new_index].1) {
break;
}
info!("Skipping unsupported format: {:?}", CUBEMAPS[new_index]);
}
// Skip swapping to the same texture. Useful for when ktx2, zstd, or compressed texture support
// is missing
if new_index == cubemap.index {
return;
}
cubemap.index = new_index;
cubemap.image_handle = asset_server.load(CUBEMAPS[cubemap.index].0);
cubemap.is_loaded = false;
}
sourcepub fn limits(&self) -> Limits
pub fn limits(&self) -> Limits
List all Limits
that were requested of this device.
If any of these limits are exceeded, functions may panic.
sourcepub fn create_shader_module(
&self,
desc: ShaderModuleDescriptor<'_>
) -> ShaderModule
pub fn create_shader_module( &self, desc: ShaderModuleDescriptor<'_> ) -> ShaderModule
Creates a ShaderModule
from either SPIR-V or WGSL source code.
sourcepub fn poll(&self, maintain: Maintain<SubmissionIndex>) -> MaintainResult
pub fn poll(&self, maintain: Maintain<SubmissionIndex>) -> MaintainResult
Check for resource cleanups and mapping callbacks.
Return true
if the queue is empty, or false
if there are more queue
submissions still in flight. (Note that, unless access to the wgpu::Queue
is
coordinated somehow, this information could be out of date by the time
the caller receives it. Queue
s can be shared between threads, so
other threads could submit new work at any time.)
no-op on the web, device is automatically polled.
sourcepub fn create_command_encoder(
&self,
desc: &CommandEncoderDescriptor<Option<&str>>
) -> CommandEncoder
pub fn create_command_encoder( &self, desc: &CommandEncoderDescriptor<Option<&str>> ) -> CommandEncoder
Creates an empty CommandEncoder
.
sourcepub fn create_render_bundle_encoder(
&self,
desc: &RenderBundleEncoderDescriptor<'_>
) -> RenderBundleEncoder<'_>
pub fn create_render_bundle_encoder( &self, desc: &RenderBundleEncoderDescriptor<'_> ) -> RenderBundleEncoder<'_>
Creates an empty RenderBundleEncoder
.
sourcepub fn create_bind_group<'a>(
&self,
label: impl Into<Option<&'a str>>,
layout: &'a BindGroupLayout,
entries: &'a [BindGroupEntry<'a>]
) -> BindGroup
pub fn create_bind_group<'a>( &self, label: impl Into<Option<&'a str>>, layout: &'a BindGroupLayout, entries: &'a [BindGroupEntry<'a>] ) -> BindGroup
Creates a new BindGroup
.
Examples found in repository?
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
fn prepare_bind_group(
mut commands: Commands,
pipeline: Res<GameOfLifePipeline>,
gpu_images: Res<RenderAssets<Image>>,
game_of_life_image: Res<GameOfLifeImage>,
render_device: Res<RenderDevice>,
) {
let view = gpu_images.get(&game_of_life_image.texture).unwrap();
let bind_group = render_device.create_bind_group(
None,
&pipeline.texture_bind_group_layout,
&BindGroupEntries::single(&view.texture_view),
);
commands.insert_resource(GameOfLifeImageBindGroup(bind_group));
}
More examples
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
fn as_bind_group(
&self,
layout: &BindGroupLayout,
render_device: &RenderDevice,
image_assets: &RenderAssets<Image>,
fallback_image: &FallbackImage,
) -> Result<PreparedBindGroup<Self::Data>, AsBindGroupError> {
// retrieve the render resources from handles
let mut images = vec![];
for handle in self.textures.iter().take(MAX_TEXTURE_COUNT) {
match image_assets.get(handle) {
Some(image) => images.push(image),
None => return Err(AsBindGroupError::RetryNextUpdate),
}
}
let fallback_image = &fallback_image.d2;
let textures = vec![&fallback_image.texture_view; MAX_TEXTURE_COUNT];
// convert bevy's resource types to WGPU's references
let mut textures: Vec<_> = textures.into_iter().map(|texture| &**texture).collect();
// fill in up to the first `MAX_TEXTURE_COUNT` textures and samplers to the arrays
for (id, image) in images.into_iter().enumerate() {
textures[id] = &*image.texture_view;
}
let bind_group = render_device.create_bind_group(
"bindless_material_bind_group",
layout,
&BindGroupEntries::sequential((&textures[..], &fallback_image.sampler)),
);
Ok(PreparedBindGroup {
bindings: vec![],
bind_group,
data: (),
})
}
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
fn run(
&self,
_graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
(view_target, _post_process_settings): QueryItem<Self::ViewQuery>,
world: &World,
) -> Result<(), NodeRunError> {
// Get the pipeline resource that contains the global data we need
// to create the render pipeline
let post_process_pipeline = world.resource::<PostProcessPipeline>();
// The pipeline cache is a cache of all previously created pipelines.
// It is required to avoid creating a new pipeline each frame,
// which is expensive due to shader compilation.
let pipeline_cache = world.resource::<PipelineCache>();
// Get the pipeline from the cache
let Some(pipeline) = pipeline_cache.get_render_pipeline(post_process_pipeline.pipeline_id)
else {
return Ok(());
};
// Get the settings uniform binding
let settings_uniforms = world.resource::<ComponentUniforms<PostProcessSettings>>();
let Some(settings_binding) = settings_uniforms.uniforms().binding() else {
return Ok(());
};
// This will start a new "post process write", obtaining two texture
// views from the view target - a `source` and a `destination`.
// `source` is the "current" main texture and you _must_ write into
// `destination` because calling `post_process_write()` on the
// [`ViewTarget`] will internally flip the [`ViewTarget`]'s main
// texture to the `destination` texture. Failing to do so will cause
// the current main texture information to be lost.
let post_process = view_target.post_process_write();
// The bind_group gets created each frame.
//
// Normally, you would create a bind_group in the Queue set,
// but this doesn't work with the post_process_write().
// 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
// is to make sure you get it during the node execution.
let bind_group = render_context.render_device().create_bind_group(
"post_process_bind_group",
&post_process_pipeline.layout,
// It's important for this to match the BindGroupLayout defined in the PostProcessPipeline
&BindGroupEntries::sequential((
// Make sure to use the source view
post_process.source,
// Use the sampler created for the pipeline
&post_process_pipeline.sampler,
// Set the settings binding
settings_binding.clone(),
)),
);
// Begin the render pass
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
label: Some("post_process_pass"),
color_attachments: &[Some(RenderPassColorAttachment {
// We need to specify the post process destination view here
// to make sure we write to the appropriate texture.
view: post_process.destination,
resolve_target: None,
ops: Operations::default(),
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
// This is mostly just wgpu boilerplate for drawing a fullscreen triangle,
// using the pipeline/bind_group created above
render_pass.set_render_pipeline(pipeline);
render_pass.set_bind_group(0, &bind_group, &[]);
render_pass.draw(0..3, 0..1);
Ok(())
}
sourcepub fn create_bind_group_layout<'a>(
&self,
label: impl Into<Option<&'a str>>,
entries: &'a [BindGroupLayoutEntry]
) -> BindGroupLayout
pub fn create_bind_group_layout<'a>( &self, label: impl Into<Option<&'a str>>, entries: &'a [BindGroupLayoutEntry] ) -> BindGroupLayout
Creates a BindGroupLayout
.
Examples found in repository?
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>();
// We need to define the bind group layout used for our pipeline
let layout = render_device.create_bind_group_layout(
"post_process_bind_group_layout",
&BindGroupLayoutEntries::sequential(
// The layout entries will only be visible in the fragment stage
ShaderStages::FRAGMENT,
(
// The screen texture
texture_2d(TextureSampleType::Float { filterable: true }),
// The sampler that will be used to sample the screen texture
sampler(SamplerBindingType::Filtering),
// The settings uniform that will control the effect
uniform_buffer::<PostProcessSettings>(false),
),
),
);
// 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());
// Get the shader handle
let shader = world
.resource::<AssetServer>()
.load("shaders/post_processing.wgsl");
let pipeline_id = world
.resource_mut::<PipelineCache>()
// This will add the pipeline to the cache and queue it's creation
.queue_render_pipeline(RenderPipelineDescriptor {
label: Some("post_process_pipeline".into()),
layout: vec![layout.clone()],
// This will setup a fullscreen triangle for the vertex state
vertex: fullscreen_shader_vertex_state(),
fragment: Some(FragmentState {
shader,
shader_defs: vec![],
// Make sure this matches the entry point of your shader.
// It can be anything as long as it matches here and in the shader.
entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {
format: TextureFormat::bevy_default(),
blend: None,
write_mask: ColorWrites::ALL,
})],
}),
// All of the following properties are not important for this effect so just use the default values.
// This struct doesn't have the Default trait implemented because not all field can have a default value.
primitive: PrimitiveState::default(),
depth_stencil: None,
multisample: MultisampleState::default(),
push_constant_ranges: vec![],
});
Self {
layout,
sampler,
pipeline_id,
}
}
sourcepub fn create_pipeline_layout(
&self,
desc: &PipelineLayoutDescriptor<'_>
) -> PipelineLayout
pub fn create_pipeline_layout( &self, desc: &PipelineLayoutDescriptor<'_> ) -> PipelineLayout
Creates a PipelineLayout
.
sourcepub fn create_render_pipeline(
&self,
desc: &RenderPipelineDescriptor<'_>
) -> RenderPipeline
pub fn create_render_pipeline( &self, desc: &RenderPipelineDescriptor<'_> ) -> RenderPipeline
Creates a RenderPipeline
.
sourcepub fn create_compute_pipeline(
&self,
desc: &ComputePipelineDescriptor<'_>
) -> ComputePipeline
pub fn create_compute_pipeline( &self, desc: &ComputePipelineDescriptor<'_> ) -> ComputePipeline
Creates a ComputePipeline
.
sourcepub fn create_buffer(&self, desc: &BufferDescriptor<Option<&str>>) -> Buffer
pub fn create_buffer(&self, desc: &BufferDescriptor<Option<&str>>) -> Buffer
Creates a Buffer
.
sourcepub fn create_buffer_with_data(&self, desc: &BufferInitDescriptor<'_>) -> Buffer
pub fn create_buffer_with_data(&self, desc: &BufferInitDescriptor<'_>) -> Buffer
Creates a Buffer
and initializes it with the specified data.
Examples found in repository?
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
fn prepare_instance_buffers(
mut commands: Commands,
query: Query<(Entity, &InstanceMaterialData)>,
render_device: Res<RenderDevice>,
) {
for (entity, instance_data) in &query {
let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
label: Some("instance data buffer"),
contents: bytemuck::cast_slice(instance_data.as_slice()),
usage: BufferUsages::VERTEX | BufferUsages::COPY_DST,
});
commands.entity(entity).insert(InstanceBuffer {
buffer,
length: instance_data.len(),
});
}
}
sourcepub fn create_texture_with_data(
&self,
render_queue: &RenderQueue,
desc: &TextureDescriptor<Option<&str>, &[TextureFormat]>,
order: TextureDataOrder,
data: &[u8]
) -> Texture
pub fn create_texture_with_data( &self, render_queue: &RenderQueue, desc: &TextureDescriptor<Option<&str>, &[TextureFormat]>, order: TextureDataOrder, data: &[u8] ) -> Texture
Creates a new Texture
and initializes it with the specified data.
desc
specifies the general format of the texture.
data
is the raw data.
sourcepub fn create_texture(
&self,
desc: &TextureDescriptor<Option<&str>, &[TextureFormat]>
) -> Texture
pub fn create_texture( &self, desc: &TextureDescriptor<Option<&str>, &[TextureFormat]> ) -> Texture
Creates a new Texture
.
desc
specifies the general format of the texture.
sourcepub fn create_sampler(&self, desc: &SamplerDescriptor<'_>) -> Sampler
pub fn create_sampler(&self, desc: &SamplerDescriptor<'_>) -> Sampler
Creates a new Sampler
.
desc
specifies the behavior of the sampler.
Examples found in repository?
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>();
// We need to define the bind group layout used for our pipeline
let layout = render_device.create_bind_group_layout(
"post_process_bind_group_layout",
&BindGroupLayoutEntries::sequential(
// The layout entries will only be visible in the fragment stage
ShaderStages::FRAGMENT,
(
// The screen texture
texture_2d(TextureSampleType::Float { filterable: true }),
// The sampler that will be used to sample the screen texture
sampler(SamplerBindingType::Filtering),
// The settings uniform that will control the effect
uniform_buffer::<PostProcessSettings>(false),
),
),
);
// 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());
// Get the shader handle
let shader = world
.resource::<AssetServer>()
.load("shaders/post_processing.wgsl");
let pipeline_id = world
.resource_mut::<PipelineCache>()
// This will add the pipeline to the cache and queue it's creation
.queue_render_pipeline(RenderPipelineDescriptor {
label: Some("post_process_pipeline".into()),
layout: vec![layout.clone()],
// This will setup a fullscreen triangle for the vertex state
vertex: fullscreen_shader_vertex_state(),
fragment: Some(FragmentState {
shader,
shader_defs: vec![],
// Make sure this matches the entry point of your shader.
// It can be anything as long as it matches here and in the shader.
entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {
format: TextureFormat::bevy_default(),
blend: None,
write_mask: ColorWrites::ALL,
})],
}),
// All of the following properties are not important for this effect so just use the default values.
// This struct doesn't have the Default trait implemented because not all field can have a default value.
primitive: PrimitiveState::default(),
depth_stencil: None,
multisample: MultisampleState::default(),
push_constant_ranges: vec![],
});
Self {
layout,
sampler,
pipeline_id,
}
}
sourcepub fn configure_surface(
&self,
surface: &Surface<'_>,
config: &SurfaceConfiguration<Vec<TextureFormat>>
)
pub fn configure_surface( &self, surface: &Surface<'_>, config: &SurfaceConfiguration<Vec<TextureFormat>> )
Initializes Surface
for presentation.
§Panics
- A old
SurfaceTexture
is still alive referencing an old surface. - Texture format requested is unsupported on the surface.
sourcepub fn wgpu_device(&self) -> &Device
pub fn wgpu_device(&self) -> &Device
Returns the wgpu Device
.
pub fn map_buffer( &self, buffer: &BufferSlice<'_>, map_mode: MapMode, callback: impl FnOnce(Result<(), BufferAsyncError>) + Send + 'static )
pub fn align_copy_bytes_per_row(row_bytes: usize) -> usize
pub fn get_supported_read_only_binding_type( &self, buffers_per_shader_stage: u32 ) -> BufferBindingType
Trait Implementations§
source§impl Clone for RenderDevice
impl Clone for RenderDevice
source§fn clone(&self) -> RenderDevice
fn clone(&self) -> RenderDevice
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl From<Device> for RenderDevice
impl From<Device> for RenderDevice
source§fn from(device: Device) -> RenderDevice
fn from(device: Device) -> RenderDevice
impl Resource for RenderDevice
Auto Trait Implementations§
impl Freeze for RenderDevice
impl RefUnwindSafe for RenderDevice
impl Send for RenderDevice
impl Sync for RenderDevice
impl Unpin for RenderDevice
impl UnwindSafe for RenderDevice
Blanket Implementations§
source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<Image>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<Image>) -> U
T
ShaderType
for self
. When used in AsBindGroup
derives, it is safe to assume that all images in self
exist.source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.