Skip to content

Commit 728e885

Browse files
committed
get proper texture format after the renderer is initialized, fix #3897
# Objective There is no Srgb support on some platforms with some GPUs and display protocols (for example, Nvidia's GPUs with Wayland). Thus `TextureFormat::bevy_default()` which returns `Rgba8UnormSrgb` or `Bgra8UnormSrgb` will cause panics on such platforms. This patch will resolve this problem. Fix #3897 ## Solution Make `initialize_renderer` expose `wgpu::Adapter` and use `wgpu::Adapter` to get proper `TextureFormat`. ## Changelog * Fixed #3897
1 parent 2d2ea33 commit 728e885

File tree

8 files changed

+192
-37
lines changed

8 files changed

+192
-37
lines changed

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ use bevy_render::{
2121
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
2222
render_resource::*,
2323
renderer::{RenderDevice, RenderQueue},
24-
texture::{
25-
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
26-
},
24+
texture::{DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo},
2725
view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms},
2826
Extract, RenderApp, RenderStage,
2927
};
@@ -263,8 +261,10 @@ impl FromWorld for MeshPipeline {
263261
Res<RenderDevice>,
264262
Res<DefaultImageSampler>,
265263
Res<RenderQueue>,
264+
Res<TextureFormat>,
266265
)> = SystemState::new(world);
267-
let (render_device, default_sampler, render_queue) = system_state.get_mut(world);
266+
let (render_device, default_sampler, render_queue, firstly_available_texture_format) =
267+
system_state.get_mut(world);
268268
let clustered_forward_buffer_binding_type = render_device
269269
.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
270270

@@ -421,7 +421,7 @@ impl FromWorld for MeshPipeline {
421421
Extent3d::default(),
422422
TextureDimension::D2,
423423
&[255u8; 4],
424-
TextureFormat::bevy_default(),
424+
*firstly_available_texture_format,
425425
);
426426
let texture = render_device.create_texture(&image.texture_descriptor);
427427
let sampler = match image.sampler_descriptor {
@@ -610,7 +610,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
610610
shader_defs,
611611
entry_point: "fragment".into(),
612612
targets: vec![Some(ColorTargetState {
613-
format: TextureFormat::bevy_default(),
613+
format: self.dummy_white_gpu_image.texture_format,
614614
blend,
615615
write_mask: ColorWrites::ALL,
616616
})],

crates/bevy_render/src/lib.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,23 @@ impl Plugin for RenderPlugin {
148148
compatible_surface: surface.as_ref(),
149149
..Default::default()
150150
};
151-
let (device, queue, adapter_info) = futures_lite::future::block_on(
152-
renderer::initialize_renderer(&instance, &options, &request_adapter_options),
153-
);
151+
let (device, queue, adapter_info, render_adapter, available_texture_formats) =
152+
futures_lite::future::block_on(renderer::initialize_renderer(
153+
&instance,
154+
&options,
155+
&request_adapter_options,
156+
));
157+
// `available_texture_formats` won't be empty, or else will panick in the former
158+
// `initialize_renderer` call.
159+
let firstly_available_texture_format = available_texture_formats[0];
154160
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
155161
debug!("Configured wgpu adapter Features: {:#?}", device.features());
156162
app.insert_resource(device.clone())
157163
.insert_resource(queue.clone())
158164
.insert_resource(adapter_info.clone())
165+
.insert_resource(render_adapter.clone())
166+
.insert_resource(available_texture_formats.clone())
167+
.insert_resource(firstly_available_texture_format)
159168
.init_resource::<ScratchMainWorld>()
160169
.register_type::<Frustum>()
161170
.register_type::<CubemapFrusta>();
@@ -197,6 +206,9 @@ impl Plugin for RenderPlugin {
197206
.insert_resource(instance)
198207
.insert_resource(device)
199208
.insert_resource(queue)
209+
.insert_resource(render_adapter)
210+
.insert_resource(available_texture_formats)
211+
.insert_resource(firstly_available_texture_format)
200212
.insert_resource(adapter_info)
201213
.insert_resource(pipeline_cache)
202214
.insert_resource(asset_server)

crates/bevy_render/src/renderer/mod.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use bevy_ecs::prelude::*;
1414
use bevy_time::TimeSender;
1515
use bevy_utils::Instant;
1616
use std::sync::Arc;
17-
use wgpu::{AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions};
17+
use wgpu::{Adapter, AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions};
1818

1919
/// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame.
2020
pub fn render_system(world: &mut World) {
@@ -86,17 +86,28 @@ pub fn render_system(world: &mut World) {
8686
/// This queue is used to enqueue tasks for the GPU to execute asynchronously.
8787
pub type RenderQueue = Arc<Queue>;
8888

89+
/// This is the adapter that the GPU is using to render.
90+
pub type RenderAdapter = Arc<Adapter>;
91+
8992
/// The GPU instance is used to initialize the [`RenderQueue`] and [`RenderDevice`],
9093
/// as well as to create [`WindowSurfaces`](crate::view::window::WindowSurfaces).
9194
pub type RenderInstance = Instance;
9295

96+
pub type AvailableTextureFormats = Arc<Vec<wgpu::TextureFormat>>;
97+
9398
/// Initializes the renderer by retrieving and preparing the GPU instance, device and queue
9499
/// for the specified backend.
95100
pub async fn initialize_renderer(
96101
instance: &Instance,
97102
options: &WgpuSettings,
98103
request_adapter_options: &RequestAdapterOptions<'_>,
99-
) -> (RenderDevice, RenderQueue, AdapterInfo) {
104+
) -> (
105+
RenderDevice,
106+
RenderQueue,
107+
AdapterInfo,
108+
RenderAdapter,
109+
AvailableTextureFormats,
110+
) {
100111
let adapter = instance
101112
.request_adapter(request_adapter_options)
102113
.await
@@ -243,9 +254,26 @@ pub async fn initialize_renderer(
243254
)
244255
.await
245256
.unwrap();
257+
246258
let device = Arc::new(device);
247259
let queue = Arc::new(queue);
248-
(RenderDevice::from(device), queue, adapter_info)
260+
let adapter = Arc::new(adapter);
261+
let mut available_texture_formats = Vec::new();
262+
if let Some(s) = request_adapter_options.compatible_surface {
263+
available_texture_formats = s.get_supported_formats(&adapter);
264+
};
265+
let available_texture_formats = Arc::new(available_texture_formats);
266+
if available_texture_formats.is_empty() {
267+
info!("{:?}", adapter_info);
268+
panic!("No supported texture formats found!");
269+
}
270+
(
271+
RenderDevice::from(device),
272+
queue,
273+
adapter_info,
274+
adapter,
275+
available_texture_formats,
276+
)
249277
}
250278

251279
/// The context with all information required to interact with the GPU.

crates/bevy_render/src/view/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub mod window;
44
pub use visibility::*;
55
use wgpu::{
66
Color, Extent3d, Operations, RenderPassColorAttachment, TextureDescriptor, TextureDimension,
7-
TextureFormat, TextureUsages,
7+
TextureUsages,
88
};
99
pub use window::*;
1010

@@ -15,8 +15,8 @@ use crate::{
1515
rangefinder::ViewRangefinder3d,
1616
render_asset::RenderAssets,
1717
render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView},
18-
renderer::{RenderDevice, RenderQueue},
19-
texture::{BevyDefault, TextureCache},
18+
renderer::{AvailableTextureFormats, RenderDevice, RenderQueue},
19+
texture::TextureCache,
2020
RenderApp, RenderStage,
2121
};
2222
use bevy_app::{App, Plugin};
@@ -183,6 +183,7 @@ fn prepare_view_targets(
183183
images: Res<RenderAssets<Image>>,
184184
msaa: Res<Msaa>,
185185
render_device: Res<RenderDevice>,
186+
available_texture_formats: Res<AvailableTextureFormats>,
186187
mut texture_cache: ResMut<TextureCache>,
187188
cameras: Query<(Entity, &ExtractedCamera)>,
188189
) {
@@ -206,7 +207,7 @@ fn prepare_view_targets(
206207
mip_level_count: 1,
207208
sample_count: msaa.samples,
208209
dimension: TextureDimension::D2,
209-
format: TextureFormat::bevy_default(),
210+
format: available_texture_formats[0],
210211
usage: TextureUsages::RENDER_ATTACHMENT,
211212
},
212213
)

crates/bevy_render/src/view/window.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
use crate::{
22
render_resource::TextureView,
3-
renderer::{RenderDevice, RenderInstance},
4-
texture::BevyDefault,
3+
renderer::{RenderAdapter, RenderDevice, RenderInstance},
54
Extract, RenderApp, RenderStage,
65
};
76
use bevy_app::{App, Plugin};
87
use bevy_ecs::prelude::*;
98
use bevy_utils::{tracing::debug, HashMap, HashSet};
109
use bevy_window::{PresentMode, RawWindowHandleWrapper, WindowClosed, WindowId, Windows};
1110
use std::ops::{Deref, DerefMut};
12-
use wgpu::TextureFormat;
1311

1412
/// Token to ensure a system runs on the main thread.
1513
#[derive(Default)]
@@ -149,6 +147,7 @@ pub fn prepare_windows(
149147
mut window_surfaces: ResMut<WindowSurfaces>,
150148
render_device: Res<RenderDevice>,
151149
render_instance: Res<RenderInstance>,
150+
render_adapter: Res<RenderAdapter>,
152151
) {
153152
let window_surfaces = window_surfaces.deref_mut();
154153
for window in windows.windows.values_mut() {
@@ -161,7 +160,7 @@ pub fn prepare_windows(
161160
});
162161

163162
let swap_chain_descriptor = wgpu::SurfaceConfiguration {
164-
format: TextureFormat::bevy_default(),
163+
format: surface.get_supported_formats(&render_adapter)[0],
165164
width: window.physical_width,
166165
height: window.physical_height,
167166
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
@@ -173,7 +172,6 @@ pub fn prepare_windows(
173172
PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync,
174173
},
175174
};
176-
177175
// Do the initial surface configuration if it hasn't been configured yet
178176
if window_surfaces.configured_windows.insert(window.id) || window.size_changed {
179177
render_device.configure_surface(surface, &swap_chain_descriptor);

crates/bevy_sprite/src/mesh2d/mesh.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ use bevy_render::{
1313
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
1414
render_resource::*,
1515
renderer::{RenderDevice, RenderQueue},
16-
texture::{
17-
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
18-
},
16+
texture::{DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo},
1917
view::{ComputedVisibility, ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms},
2018
Extract, RenderApp, RenderStage,
2119
};
@@ -158,9 +156,13 @@ pub struct Mesh2dPipeline {
158156

159157
impl FromWorld for Mesh2dPipeline {
160158
fn from_world(world: &mut World) -> Self {
161-
let mut system_state: SystemState<(Res<RenderDevice>, Res<DefaultImageSampler>)> =
162-
SystemState::new(world);
163-
let (render_device, default_sampler) = system_state.get_mut(world);
159+
let mut system_state: SystemState<(
160+
Res<RenderDevice>,
161+
Res<DefaultImageSampler>,
162+
Res<TextureFormat>,
163+
)> = SystemState::new(world);
164+
let (render_device, default_sampler, firstly_available_texture_format) =
165+
system_state.get_mut(world);
164166
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
165167
entries: &[
166168
// View
@@ -197,7 +199,7 @@ impl FromWorld for Mesh2dPipeline {
197199
Extent3d::default(),
198200
TextureDimension::D2,
199201
&[255u8; 4],
200-
TextureFormat::bevy_default(),
202+
*firstly_available_texture_format,
201203
);
202204
let texture = render_device.create_texture(&image.texture_descriptor);
203205
let sampler = match image.sampler_descriptor {
@@ -353,7 +355,7 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
353355
shader_defs,
354356
entry_point: "fragment".into(),
355357
targets: vec![Some(ColorTargetState {
356-
format: TextureFormat::bevy_default(),
358+
format: self.dummy_white_gpu_image.texture_format,
357359
blend: Some(BlendState::ALPHA_BLENDING),
358360
write_mask: ColorWrites::ALL,
359361
})],

crates/bevy_sprite/src/render/mod.rs

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use bevy_asset::{AssetEvent, Assets, Handle, HandleId};
88
use bevy_core_pipeline::core_2d::Transparent2d;
99
use bevy_ecs::{
1010
prelude::*,
11-
system::{lifetimeless::*, SystemParamItem},
11+
system::{lifetimeless::*, SystemParamItem, SystemState},
1212
};
1313
use bevy_math::Vec2;
1414
use bevy_reflect::Uuid;
@@ -21,7 +21,7 @@ use bevy_render::{
2121
},
2222
render_resource::*,
2323
renderer::{RenderDevice, RenderQueue},
24-
texture::{BevyDefault, Image},
24+
texture::{DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo},
2525
view::{
2626
ComputedVisibility, Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities,
2727
},
@@ -37,11 +37,19 @@ use fixedbitset::FixedBitSet;
3737
pub struct SpritePipeline {
3838
view_layout: BindGroupLayout,
3939
material_layout: BindGroupLayout,
40+
pub dummy_white_gpu_image: GpuImage,
4041
}
4142

4243
impl FromWorld for SpritePipeline {
4344
fn from_world(world: &mut World) -> Self {
44-
let render_device = world.resource::<RenderDevice>();
45+
let mut system_state: SystemState<(
46+
Res<RenderDevice>,
47+
Res<DefaultImageSampler>,
48+
Res<RenderQueue>,
49+
Res<TextureFormat>,
50+
)> = SystemState::new(world);
51+
let (render_device, default_sampler, render_queue, firstly_available_texture_format) =
52+
system_state.get_mut(world);
4553

4654
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
4755
entries: &[BindGroupLayoutEntry {
@@ -78,10 +86,57 @@ impl FromWorld for SpritePipeline {
7886
],
7987
label: Some("sprite_material_layout"),
8088
});
89+
let dummy_white_gpu_image = {
90+
let image = Image::new_fill(
91+
Extent3d::default(),
92+
TextureDimension::D2,
93+
&[255u8; 4],
94+
*firstly_available_texture_format,
95+
);
96+
let texture = render_device.create_texture(&image.texture_descriptor);
97+
let sampler = match image.sampler_descriptor {
98+
ImageSampler::Default => (**default_sampler).clone(),
99+
ImageSampler::Descriptor(descriptor) => render_device.create_sampler(&descriptor),
100+
};
101+
102+
let format_size = image.texture_descriptor.format.pixel_size();
103+
render_queue.write_texture(
104+
ImageCopyTexture {
105+
texture: &texture,
106+
mip_level: 0,
107+
origin: Origin3d::ZERO,
108+
aspect: TextureAspect::All,
109+
},
110+
&image.data,
111+
ImageDataLayout {
112+
offset: 0,
113+
bytes_per_row: Some(
114+
std::num::NonZeroU32::new(
115+
image.texture_descriptor.size.width * format_size as u32,
116+
)
117+
.unwrap(),
118+
),
119+
rows_per_image: None,
120+
},
121+
image.texture_descriptor.size,
122+
);
123+
let texture_view = texture.create_view(&TextureViewDescriptor::default());
124+
GpuImage {
125+
texture,
126+
texture_view,
127+
texture_format: image.texture_descriptor.format,
128+
sampler,
129+
size: Vec2::new(
130+
image.texture_descriptor.size.width as f32,
131+
image.texture_descriptor.size.height as f32,
132+
),
133+
}
134+
};
81135

82136
SpritePipeline {
83137
view_layout,
84138
material_layout,
139+
dummy_white_gpu_image,
85140
}
86141
}
87142
}
@@ -147,7 +202,7 @@ impl SpecializedRenderPipeline for SpritePipeline {
147202
shader_defs,
148203
entry_point: "fragment".into(),
149204
targets: vec![Some(ColorTargetState {
150-
format: TextureFormat::bevy_default(),
205+
format: self.dummy_white_gpu_image.texture_format,
151206
blend: Some(BlendState::ALPHA_BLENDING),
152207
write_mask: ColorWrites::ALL,
153208
})],

0 commit comments

Comments
 (0)