Skip to content

Commit b9a7032

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 1c23421 commit b9a7032

File tree

8 files changed

+116
-27
lines changed

8 files changed

+116
-27
lines changed

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ use bevy_render::{
2020
render_asset::RenderAssets,
2121
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
2222
render_resource::*,
23-
renderer::{RenderDevice, RenderQueue},
24-
texture::{
25-
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
26-
},
23+
renderer::{AvailableTextureFormats, RenderDevice, RenderQueue},
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<AvailableTextureFormats>,
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, available_texture_formats) =
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+
available_texture_formats[0],
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: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,19 @@ 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+
));
154157
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
155158
debug!("Configured wgpu adapter Features: {:#?}", device.features());
156159
app.insert_resource(device.clone())
157160
.insert_resource(queue.clone())
158161
.insert_resource(adapter_info.clone())
162+
.insert_resource(render_adapter.clone())
163+
.insert_resource(available_texture_formats.clone())
159164
.init_resource::<ScratchMainWorld>()
160165
.register_type::<Frustum>()
161166
.register_type::<CubemapFrusta>();
@@ -197,6 +202,8 @@ impl Plugin for RenderPlugin {
197202
.insert_resource(instance)
198203
.insert_resource(device)
199204
.insert_resource(queue)
205+
.insert_resource(render_adapter)
206+
.insert_resource(available_texture_formats)
200207
.insert_resource(adapter_info)
201208
.insert_resource(pipeline_cache)
202209
.insert_resource(asset_server)

crates/bevy_render/src/renderer/mod.rs

Lines changed: 27 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
/// aswell 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,22 @@ 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+
(
267+
RenderDevice::from(device),
268+
queue,
269+
adapter_info,
270+
adapter,
271+
available_texture_formats,
272+
)
249273
}
250274

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

crates/bevy_render/src/view/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
rangefinder::ViewRangefinder3d,
1616
render_asset::RenderAssets,
1717
render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView},
18-
renderer::{RenderDevice, RenderQueue},
18+
renderer::{AvailableTextureFormats, RenderDevice, RenderQueue},
1919
texture::{BevyDefault, TextureCache},
2020
RenderApp, RenderStage,
2121
};
@@ -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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ impl FromWorld for Mesh2dPipeline {
197197
Extent3d::default(),
198198
TextureDimension::D2,
199199
&[255u8; 4],
200-
TextureFormat::bevy_default(),
200+
TextureFormat::Bgra8Unorm,
201201
);
202202
let texture = render_device.create_texture(&image.texture_descriptor);
203203
let sampler = match image.sampler_descriptor {
@@ -353,7 +353,7 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
353353
shader_defs,
354354
entry_point: "fragment".into(),
355355
targets: vec![Some(ColorTargetState {
356-
format: TextureFormat::bevy_default(),
356+
format: TextureFormat::Bgra8Unorm,
357357
blend: Some(BlendState::ALPHA_BLENDING),
358358
write_mask: ColorWrites::ALL,
359359
})],

crates/bevy_sprite/src/render/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl SpecializedRenderPipeline for SpritePipeline {
147147
shader_defs,
148148
entry_point: "fragment".into(),
149149
targets: vec![Some(ColorTargetState {
150-
format: TextureFormat::bevy_default(),
150+
format: TextureFormat::Bgra8Unorm,
151151
blend: Some(BlendState::ALPHA_BLENDING),
152152
write_mask: ColorWrites::ALL,
153153
})],

crates/bevy_ui/src/render/pipeline.rs

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
1-
use bevy_ecs::prelude::*;
1+
use bevy_ecs::{prelude::*, system::SystemState};
2+
use bevy_math::Vec2;
23
use bevy_render::{
3-
render_resource::*, renderer::RenderDevice, texture::BevyDefault, view::ViewUniform,
4+
render_resource::*,
5+
renderer::{AvailableTextureFormats, RenderDevice, RenderQueue},
6+
texture::{DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo},
7+
view::ViewUniform,
48
};
59

610
pub struct UiPipeline {
711
pub view_layout: BindGroupLayout,
812
pub image_layout: BindGroupLayout,
13+
pub dummy_white_gpu_image: GpuImage,
914
}
1015

1116
impl FromWorld for UiPipeline {
1217
fn from_world(world: &mut World) -> Self {
13-
let render_device = world.resource::<RenderDevice>();
18+
let mut system_state: SystemState<(
19+
Res<RenderDevice>,
20+
Res<DefaultImageSampler>,
21+
Res<RenderQueue>,
22+
Res<AvailableTextureFormats>,
23+
)> = SystemState::new(world);
24+
let (render_device, default_sampler, render_queue, available_texture_formats) =
25+
system_state.get_mut(world);
1426

1527
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
1628
entries: &[BindGroupLayoutEntry {
@@ -47,10 +59,57 @@ impl FromWorld for UiPipeline {
4759
],
4860
label: Some("ui_image_layout"),
4961
});
62+
let dummy_white_gpu_image = {
63+
let image = Image::new_fill(
64+
Extent3d::default(),
65+
TextureDimension::D2,
66+
&[255u8; 4],
67+
available_texture_formats[0],
68+
);
69+
let texture = render_device.create_texture(&image.texture_descriptor);
70+
let sampler = match image.sampler_descriptor {
71+
ImageSampler::Default => (**default_sampler).clone(),
72+
ImageSampler::Descriptor(descriptor) => render_device.create_sampler(&descriptor),
73+
};
74+
75+
let format_size = image.texture_descriptor.format.pixel_size();
76+
render_queue.write_texture(
77+
ImageCopyTexture {
78+
texture: &texture,
79+
mip_level: 0,
80+
origin: Origin3d::ZERO,
81+
aspect: TextureAspect::All,
82+
},
83+
&image.data,
84+
ImageDataLayout {
85+
offset: 0,
86+
bytes_per_row: Some(
87+
std::num::NonZeroU32::new(
88+
image.texture_descriptor.size.width * format_size as u32,
89+
)
90+
.unwrap(),
91+
),
92+
rows_per_image: None,
93+
},
94+
image.texture_descriptor.size,
95+
);
96+
let texture_view = texture.create_view(&TextureViewDescriptor::default());
97+
GpuImage {
98+
texture,
99+
texture_view,
100+
texture_format: image.texture_descriptor.format,
101+
sampler,
102+
size: Vec2::new(
103+
image.texture_descriptor.size.width as f32,
104+
image.texture_descriptor.size.height as f32,
105+
),
106+
}
107+
};
50108

51109
UiPipeline {
52110
view_layout,
53111
image_layout,
112+
dummy_white_gpu_image,
54113
}
55114
}
56115
}
@@ -87,7 +146,7 @@ impl SpecializedRenderPipeline for UiPipeline {
87146
shader_defs,
88147
entry_point: "fragment".into(),
89148
targets: vec![Some(ColorTargetState {
90-
format: TextureFormat::bevy_default(),
149+
format: self.dummy_white_gpu_image.texture_format,
91150
blend: Some(BlendState::ALPHA_BLENDING),
92151
write_mask: ColorWrites::ALL,
93152
})],

0 commit comments

Comments
 (0)