Skip to content

Commit f5322cd

Browse files
committed
get proper texture format after the renderer is initialized, fix #3897 (#5413)
# Objective There is no Srgb support on some GPU and display protocols with `winit` (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 `first_available_texture_format`, use the `first_available_texture_format` by default. ## Changelog * Fixed #3897.
1 parent 1738527 commit f5322cd

File tree

8 files changed

+209
-39
lines changed

8 files changed

+209
-39
lines changed

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ use bevy_render::{
2121
render_asset::RenderAssets,
2222
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
2323
render_resource::*,
24-
renderer::{RenderDevice, RenderQueue},
25-
texture::{
26-
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
27-
},
24+
renderer::{RenderDevice, RenderQueue, RenderTextureFormat},
25+
texture::{DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo},
2826
view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms},
2927
Extract, RenderApp, RenderStage,
3028
};
@@ -270,8 +268,10 @@ impl FromWorld for MeshPipeline {
270268
Res<RenderDevice>,
271269
Res<DefaultImageSampler>,
272270
Res<RenderQueue>,
271+
Res<RenderTextureFormat>,
273272
)> = SystemState::new(world);
274-
let (render_device, default_sampler, render_queue) = system_state.get_mut(world);
273+
let (render_device, default_sampler, render_queue, first_available_texture_format) =
274+
system_state.get_mut(world);
275275
let clustered_forward_buffer_binding_type = render_device
276276
.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
277277

@@ -438,7 +438,7 @@ impl FromWorld for MeshPipeline {
438438
Extent3d::default(),
439439
TextureDimension::D2,
440440
&[255u8; 4],
441-
TextureFormat::bevy_default(),
441+
first_available_texture_format.0,
442442
);
443443
let texture = render_device.create_texture(&image.texture_descriptor);
444444
let sampler = match image.sampler_descriptor {
@@ -629,7 +629,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
629629
shader_defs,
630630
entry_point: "fragment".into(),
631631
targets: vec![Some(ColorTargetState {
632-
format: TextureFormat::bevy_default(),
632+
format: self.dummy_white_gpu_image.texture_format,
633633
blend,
634634
write_mask: ColorWrites::ALL,
635635
})],

crates/bevy_render/src/lib.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use crate::{
4747
primitives::{CubemapFrusta, Frustum},
4848
render_graph::RenderGraph,
4949
render_resource::{PipelineCache, Shader, ShaderLoader},
50-
renderer::{render_system, RenderInstance},
50+
renderer::{render_system, RenderInstance, RenderTextureFormat},
5151
texture::ImagePlugin,
5252
view::{ViewPlugin, WindowRenderPlugin},
5353
};
@@ -157,14 +157,23 @@ impl Plugin for RenderPlugin {
157157
compatible_surface: surface.as_ref(),
158158
..Default::default()
159159
};
160-
let (device, queue, adapter_info) = futures_lite::future::block_on(
161-
renderer::initialize_renderer(&instance, &options, &request_adapter_options),
162-
);
160+
let (device, queue, adapter_info, render_adapter, available_texture_formats) =
161+
futures_lite::future::block_on(renderer::initialize_renderer(
162+
&instance,
163+
&options,
164+
&request_adapter_options,
165+
));
166+
// `available_texture_formats` won't be empty, or else will panick in the former
167+
// `initialize_renderer` call.
168+
let first_available_texture_format = RenderTextureFormat(available_texture_formats[0]);
163169
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
164170
debug!("Configured wgpu adapter Features: {:#?}", device.features());
165171
app.insert_resource(device.clone())
166172
.insert_resource(queue.clone())
167173
.insert_resource(adapter_info.clone())
174+
.insert_resource(render_adapter.clone())
175+
.insert_resource(available_texture_formats.clone())
176+
.insert_resource(first_available_texture_format.clone())
168177
.init_resource::<ScratchMainWorld>()
169178
.register_type::<Frustum>()
170179
.register_type::<CubemapFrusta>();
@@ -206,6 +215,9 @@ impl Plugin for RenderPlugin {
206215
.insert_resource(RenderInstance(instance))
207216
.insert_resource(device)
208217
.insert_resource(queue)
218+
.insert_resource(render_adapter)
219+
.insert_resource(available_texture_formats)
220+
.insert_resource(first_available_texture_format)
209221
.insert_resource(adapter_info)
210222
.insert_resource(pipeline_cache)
211223
.insert_resource(asset_server);

crates/bevy_render/src/renderer/mod.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use bevy_ecs::prelude::*;
1515
use bevy_time::TimeSender;
1616
use bevy_utils::Instant;
1717
use std::sync::Arc;
18-
use wgpu::{AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions};
18+
use wgpu::{Adapter, AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions};
1919

2020
/// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame.
2121
pub fn render_system(world: &mut World) {
@@ -88,6 +88,11 @@ pub fn render_system(world: &mut World) {
8888
#[derive(Resource, Clone, Deref, DerefMut)]
8989
pub struct RenderQueue(pub Arc<Queue>);
9090

91+
/// The handle to the physical device being used for rendering.
92+
/// See [`wgpu::Adapter`] for more info.
93+
#[derive(Resource, Clone, Debug, Deref, DerefMut)]
94+
pub struct RenderAdapter(pub Arc<Adapter>);
95+
9196
/// The GPU instance is used to initialize the [`RenderQueue`] and [`RenderDevice`],
9297
/// as well as to create [`WindowSurfaces`](crate::view::window::WindowSurfaces).
9398
#[derive(Resource, Deref, DerefMut)]
@@ -97,13 +102,29 @@ pub struct RenderInstance(pub Instance);
97102
#[derive(Resource, Clone, Deref, DerefMut)]
98103
pub struct RenderAdapterInfo(pub AdapterInfo);
99104

105+
/// The [`TextureFormat`](wgpu::TextureFormat) used for rendering.
106+
/// Initially it's the first element in `AvailableTextureFormats`.
107+
#[derive(Resource, Clone, Deref, DerefMut)]
108+
pub struct RenderTextureFormat(pub wgpu::TextureFormat);
109+
110+
/// The available [`TextureFormat`](wgpu::TextureFormat)s on the [`RenderAdapter`].
111+
/// Will be inserted as a `Resource` after the renderer is initialized.
112+
#[derive(Resource, Clone, Deref, DerefMut)]
113+
pub struct AvailableTextureFormats(pub Arc<Vec<wgpu::TextureFormat>>);
114+
100115
/// Initializes the renderer by retrieving and preparing the GPU instance, device and queue
101116
/// for the specified backend.
102117
pub async fn initialize_renderer(
103118
instance: &Instance,
104119
options: &WgpuSettings,
105120
request_adapter_options: &RequestAdapterOptions<'_>,
106-
) -> (RenderDevice, RenderQueue, RenderAdapterInfo) {
121+
) -> (
122+
RenderDevice,
123+
RenderQueue,
124+
RenderAdapterInfo,
125+
RenderAdapter,
126+
AvailableTextureFormats,
127+
) {
107128
let adapter = instance
108129
.request_adapter(request_adapter_options)
109130
.await
@@ -250,12 +271,25 @@ pub async fn initialize_renderer(
250271
)
251272
.await
252273
.unwrap();
274+
253275
let device = Arc::new(device);
254276
let queue = Arc::new(queue);
277+
let adapter = Arc::new(adapter);
278+
let mut available_texture_formats = Vec::new();
279+
if let Some(s) = request_adapter_options.compatible_surface {
280+
available_texture_formats = s.get_supported_formats(&adapter);
281+
if available_texture_formats.is_empty() {
282+
info!("{:?}", adapter_info);
283+
panic!("No supported texture formats found!");
284+
}
285+
};
286+
let available_texture_formats = Arc::new(available_texture_formats);
255287
(
256288
RenderDevice::from(device),
257289
RenderQueue(queue),
258290
RenderAdapterInfo(adapter_info),
291+
RenderAdapter(adapter),
292+
AvailableTextureFormats(available_texture_formats),
259293
)
260294
}
261295

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::{RenderDevice, RenderQueue, RenderTextureFormat},
19+
texture::TextureCache,
2020
RenderApp, RenderStage,
2121
};
2222
use bevy_app::{App, Plugin};
@@ -182,6 +182,7 @@ fn prepare_view_targets(
182182
images: Res<RenderAssets<Image>>,
183183
msaa: Res<Msaa>,
184184
render_device: Res<RenderDevice>,
185+
texture_format: Res<RenderTextureFormat>,
185186
mut texture_cache: ResMut<TextureCache>,
186187
cameras: Query<(Entity, &ExtractedCamera)>,
187188
) {
@@ -205,7 +206,7 @@ fn prepare_view_targets(
205206
mip_level_count: 1,
206207
sample_count: msaa.samples,
207208
dimension: TextureDimension::D2,
208-
format: TextureFormat::bevy_default(),
209+
format: **texture_format,
209210
usage: TextureUsages::RENDER_ATTACHMENT,
210211
},
211212
)

crates/bevy_render/src/view/window.rs

Lines changed: 11 additions & 4 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(Resource, Default)]
@@ -161,6 +159,7 @@ pub fn prepare_windows(
161159
mut window_surfaces: ResMut<WindowSurfaces>,
162160
render_device: Res<RenderDevice>,
163161
render_instance: Res<RenderInstance>,
162+
render_adapter: Res<RenderAdapter>,
164163
) {
165164
let window_surfaces = window_surfaces.deref_mut();
166165
for window in windows.windows.values_mut() {
@@ -173,7 +172,15 @@ pub fn prepare_windows(
173172
});
174173

175174
let swap_chain_descriptor = wgpu::SurfaceConfiguration {
176-
format: TextureFormat::bevy_default(),
175+
format: *surface
176+
.get_supported_formats(&render_adapter)
177+
.get(0)
178+
.unwrap_or_else(|| {
179+
panic!(
180+
"No supported formats found for surface {:?} on adapter {:?}",
181+
surface, render_adapter
182+
)
183+
}),
177184
width: window.physical_width,
178185
height: window.physical_height,
179186
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,

crates/bevy_sprite/src/mesh2d/mesh.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@ use bevy_render::{
1212
render_asset::RenderAssets,
1313
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
1414
render_resource::*,
15-
renderer::{RenderDevice, RenderQueue},
16-
texture::{
17-
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
18-
},
15+
renderer::{RenderDevice, RenderQueue, RenderTextureFormat},
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<RenderTextureFormat>,
163+
)> = SystemState::new(world);
164+
let (render_device, default_sampler, first_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+
first_available_texture_format.0,
201203
);
202204
let texture = render_device.create_texture(&image.texture_descriptor);
203205
let sampler = match image.sampler_descriptor {
@@ -354,7 +356,7 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
354356
shader_defs,
355357
entry_point: "fragment".into(),
356358
targets: vec![Some(ColorTargetState {
357-
format: TextureFormat::bevy_default(),
359+
format: self.dummy_white_gpu_image.texture_format,
358360
blend: Some(BlendState::ALPHA_BLENDING),
359361
write_mask: ColorWrites::ALL,
360362
})],

0 commit comments

Comments
 (0)