Skip to content

Commit d622e30

Browse files
committed
Fix non-sRGB image formats for RenderTarget::Image
1 parent def974c commit d622e30

File tree

12 files changed

+193
-39
lines changed

12 files changed

+193
-39
lines changed

crates/bevy_core_pipeline/src/upscaling/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ fn prepare_view_upscaling_pipelines(
7272
};
7373

7474
let key = BlitPipelineKey {
75-
texture_format: view_target.out_texture_format(),
75+
texture_format: view_target.out_texture_view_format(),
7676
blend_state,
7777
samples: 1,
7878
};

crates/bevy_image/src/image.rs

Lines changed: 138 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,130 @@ impl BevyDefault for TextureFormat {
3838
}
3939
}
4040

41+
/// Trait used to provide texture srgb view formats with static lifetime for `TextureDescriptor.view_formats`.
42+
pub trait TextureSrgbViewFormats {
43+
/// Returns the srgb view formats for a type.
44+
fn srgb_view_formats(&self) -> &'static [TextureFormat];
45+
}
46+
47+
impl TextureSrgbViewFormats for TextureFormat {
48+
/// Returns the srgb view formats if the format has an srgb variant, otherwise returns an empty slice.
49+
///
50+
/// The return result covers all the results of [`TextureFormat::add_srgb_suffix`](wgpu_types::TextureFormat::add_srgb_suffix).
51+
fn srgb_view_formats(&self) -> &'static [TextureFormat] {
52+
match self {
53+
TextureFormat::Rgba8Unorm => &[TextureFormat::Rgba8UnormSrgb],
54+
TextureFormat::Bgra8Unorm => &[TextureFormat::Bgra8UnormSrgb],
55+
TextureFormat::Bc1RgbaUnorm => &[TextureFormat::Bc1RgbaUnormSrgb],
56+
TextureFormat::Bc2RgbaUnorm => &[TextureFormat::Bc2RgbaUnormSrgb],
57+
TextureFormat::Bc3RgbaUnorm => &[TextureFormat::Bc3RgbaUnormSrgb],
58+
TextureFormat::Bc7RgbaUnorm => &[TextureFormat::Bc7RgbaUnormSrgb],
59+
TextureFormat::Etc2Rgb8Unorm => &[TextureFormat::Etc2Rgb8UnormSrgb],
60+
TextureFormat::Etc2Rgb8A1Unorm => &[TextureFormat::Etc2Rgb8A1UnormSrgb],
61+
TextureFormat::Etc2Rgba8Unorm => &[TextureFormat::Etc2Rgba8UnormSrgb],
62+
TextureFormat::Astc {
63+
block: wgpu_types::AstcBlock::B4x4,
64+
channel: wgpu_types::AstcChannel::Unorm,
65+
} => &[TextureFormat::Astc {
66+
block: wgpu_types::AstcBlock::B4x4,
67+
channel: wgpu_types::AstcChannel::UnormSrgb,
68+
}],
69+
TextureFormat::Astc {
70+
block: wgpu_types::AstcBlock::B5x4,
71+
channel: wgpu_types::AstcChannel::Unorm,
72+
} => &[TextureFormat::Astc {
73+
block: wgpu_types::AstcBlock::B5x4,
74+
channel: wgpu_types::AstcChannel::UnormSrgb,
75+
}],
76+
TextureFormat::Astc {
77+
block: wgpu_types::AstcBlock::B5x5,
78+
channel: wgpu_types::AstcChannel::Unorm,
79+
} => &[TextureFormat::Astc {
80+
block: wgpu_types::AstcBlock::B5x5,
81+
channel: wgpu_types::AstcChannel::UnormSrgb,
82+
}],
83+
TextureFormat::Astc {
84+
block: wgpu_types::AstcBlock::B6x5,
85+
channel: wgpu_types::AstcChannel::Unorm,
86+
} => &[TextureFormat::Astc {
87+
block: wgpu_types::AstcBlock::B6x5,
88+
channel: wgpu_types::AstcChannel::UnormSrgb,
89+
}],
90+
TextureFormat::Astc {
91+
block: wgpu_types::AstcBlock::B6x6,
92+
channel: wgpu_types::AstcChannel::Unorm,
93+
} => &[TextureFormat::Astc {
94+
block: wgpu_types::AstcBlock::B6x6,
95+
channel: wgpu_types::AstcChannel::UnormSrgb,
96+
}],
97+
TextureFormat::Astc {
98+
block: wgpu_types::AstcBlock::B8x5,
99+
channel: wgpu_types::AstcChannel::Unorm,
100+
} => &[TextureFormat::Astc {
101+
block: wgpu_types::AstcBlock::B8x5,
102+
channel: wgpu_types::AstcChannel::UnormSrgb,
103+
}],
104+
TextureFormat::Astc {
105+
block: wgpu_types::AstcBlock::B8x6,
106+
channel: wgpu_types::AstcChannel::Unorm,
107+
} => &[TextureFormat::Astc {
108+
block: wgpu_types::AstcBlock::B8x6,
109+
channel: wgpu_types::AstcChannel::UnormSrgb,
110+
}],
111+
TextureFormat::Astc {
112+
block: wgpu_types::AstcBlock::B8x8,
113+
channel: wgpu_types::AstcChannel::Unorm,
114+
} => &[TextureFormat::Astc {
115+
block: wgpu_types::AstcBlock::B8x8,
116+
channel: wgpu_types::AstcChannel::UnormSrgb,
117+
}],
118+
TextureFormat::Astc {
119+
block: wgpu_types::AstcBlock::B10x5,
120+
channel: wgpu_types::AstcChannel::Unorm,
121+
} => &[TextureFormat::Astc {
122+
block: wgpu_types::AstcBlock::B10x5,
123+
channel: wgpu_types::AstcChannel::UnormSrgb,
124+
}],
125+
TextureFormat::Astc {
126+
block: wgpu_types::AstcBlock::B10x6,
127+
channel: wgpu_types::AstcChannel::Unorm,
128+
} => &[TextureFormat::Astc {
129+
block: wgpu_types::AstcBlock::B10x6,
130+
channel: wgpu_types::AstcChannel::UnormSrgb,
131+
}],
132+
TextureFormat::Astc {
133+
block: wgpu_types::AstcBlock::B10x8,
134+
channel: wgpu_types::AstcChannel::Unorm,
135+
} => &[TextureFormat::Astc {
136+
block: wgpu_types::AstcBlock::B10x8,
137+
channel: wgpu_types::AstcChannel::UnormSrgb,
138+
}],
139+
TextureFormat::Astc {
140+
block: wgpu_types::AstcBlock::B10x10,
141+
channel: wgpu_types::AstcChannel::Unorm,
142+
} => &[TextureFormat::Astc {
143+
block: wgpu_types::AstcBlock::B10x10,
144+
channel: wgpu_types::AstcChannel::UnormSrgb,
145+
}],
146+
TextureFormat::Astc {
147+
block: wgpu_types::AstcBlock::B12x10,
148+
channel: wgpu_types::AstcChannel::Unorm,
149+
} => &[TextureFormat::Astc {
150+
block: wgpu_types::AstcBlock::B12x10,
151+
channel: wgpu_types::AstcChannel::UnormSrgb,
152+
}],
153+
TextureFormat::Astc {
154+
block: wgpu_types::AstcBlock::B12x12,
155+
channel: wgpu_types::AstcChannel::Unorm,
156+
} => &[TextureFormat::Astc {
157+
block: wgpu_types::AstcBlock::B12x12,
158+
channel: wgpu_types::AstcChannel::UnormSrgb,
159+
}],
160+
_ => &[],
161+
}
162+
}
163+
}
164+
41165
/// A handle to a 1 x 1 transparent white image.
42166
///
43167
/// Like [`Handle<Image>::default`], this is a handle to a fallback image asset.
@@ -1010,7 +1134,12 @@ impl Image {
10101134
///
10111135
/// [`Camera`]: https://docs.rs/bevy/latest/bevy/render/camera/struct.Camera.html
10121136
/// [`RenderTarget::Image`]: https://docs.rs/bevy/latest/bevy/render/camera/enum.RenderTarget.html#variant.Image
1013-
pub fn new_target_texture(width: u32, height: u32, format: TextureFormat) -> Self {
1137+
pub fn new_target_texture(
1138+
width: u32,
1139+
height: u32,
1140+
format: TextureFormat,
1141+
view_format: Option<TextureFormat>,
1142+
) -> Self {
10141143
let size = Extent3d {
10151144
width,
10161145
height,
@@ -1039,10 +1168,16 @@ impl Image {
10391168
mip_level_count: 1,
10401169
sample_count: 1,
10411170
usage,
1042-
view_formats: &[],
1171+
view_formats: match view_format {
1172+
Some(_) => format.srgb_view_formats(),
1173+
None => &[],
1174+
},
10431175
},
10441176
sampler: ImageSampler::Default,
1045-
texture_view_descriptor: None,
1177+
texture_view_descriptor: Some(TextureViewDescriptor {
1178+
format: view_format,
1179+
..Default::default()
1180+
}),
10461181
asset_usage: RenderAssetUsages::default(),
10471182
copy_on_resize: true,
10481183
}

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,6 +1878,7 @@ pub fn build_dummy_white_gpu_image(
18781878
texture,
18791879
texture_view,
18801880
texture_format: image.texture_descriptor.format,
1881+
texture_view_format: image.texture_view_descriptor.and_then(|v| v.format),
18811882
sampler,
18821883
size: image.texture_descriptor.size,
18831884
mip_level_count: image.texture_descriptor.mip_level_count,

crates/bevy_render/src/camera.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ pub trait NormalizedRenderTargetExt {
156156
) -> Option<&'a TextureView>;
157157

158158
/// Retrieves the [`TextureFormat`] of this render target, if it exists.
159-
fn get_texture_format<'a>(
159+
fn get_texture_view_format<'a>(
160160
&self,
161161
windows: &'a ExtractedWindows,
162162
images: &'a RenderAssets<GpuImage>,
@@ -199,8 +199,8 @@ impl NormalizedRenderTargetExt for NormalizedRenderTarget {
199199
}
200200
}
201201

202-
/// Retrieves the [`TextureFormat`] of this render target, if it exists.
203-
fn get_texture_format<'a>(
202+
/// Retrieves the texture view's [`TextureFormat`] of this render target, if it exists.
203+
fn get_texture_view_format<'a>(
204204
&self,
205205
windows: &'a ExtractedWindows,
206206
images: &'a RenderAssets<GpuImage>,
@@ -209,12 +209,12 @@ impl NormalizedRenderTargetExt for NormalizedRenderTarget {
209209
match self {
210210
NormalizedRenderTarget::Window(window_ref) => windows
211211
.get(&window_ref.entity())
212-
.and_then(|window| window.swap_chain_texture_format),
212+
.and_then(|window| window.swap_chain_texture_view_format),
213213
NormalizedRenderTarget::Image(image_target) => images
214214
.get(&image_target.handle)
215-
.map(|image| image.texture_format),
215+
.map(|image| image.texture_view_format.unwrap_or(image.texture_format)),
216216
NormalizedRenderTarget::TextureView(id) => {
217-
manual_texture_views.get(id).map(|tex| tex.format)
217+
manual_texture_views.get(id).map(|tex| tex.view_format)
218218
}
219219
NormalizedRenderTarget::None { .. } => None,
220220
}

crates/bevy_render/src/texture/fallback_image.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ fn fallback_image_new(
135135
texture,
136136
texture_view,
137137
texture_format: image.texture_descriptor.format,
138+
texture_view_format: image.texture_view_descriptor.and_then(|v| v.format),
138139
sampler,
139140
size: image.texture_descriptor.size,
140141
mip_level_count: image.texture_descriptor.mip_level_count,

crates/bevy_render/src/texture/gpu_image.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub struct GpuImage {
1717
pub texture: Texture,
1818
pub texture_view: TextureView,
1919
pub texture_format: TextureFormat,
20+
pub texture_view_format: Option<TextureFormat>,
2021
pub sampler: Sampler,
2122
pub size: Extent3d,
2223
pub mip_level_count: u32,
@@ -92,9 +93,8 @@ impl RenderAsset for GpuImage {
9293
let texture_view = texture.create_view(
9394
image
9495
.texture_view_descriptor
95-
.or_else(|| Some(TextureViewDescriptor::default()))
9696
.as_ref()
97-
.unwrap(),
97+
.unwrap_or(&TextureViewDescriptor::default()),
9898
);
9999
let sampler = match image.sampler {
100100
ImageSampler::Default => (***default_sampler).clone(),
@@ -107,6 +107,7 @@ impl RenderAsset for GpuImage {
107107
texture,
108108
texture_view,
109109
texture_format: image.texture_descriptor.format,
110+
texture_view_format: image.texture_view_descriptor.and_then(|v| v.format),
110111
sampler,
111112
size: image.texture_descriptor.size,
112113
mip_level_count: image.texture_descriptor.mip_level_count,

crates/bevy_render/src/texture/manual_texture_view.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ use crate::render_resource::TextureView;
1313
pub struct ManualTextureView {
1414
pub texture_view: TextureView,
1515
pub size: UVec2,
16-
pub format: TextureFormat,
16+
pub view_format: TextureFormat,
1717
}
1818

1919
impl ManualTextureView {
2020
pub fn with_default_format(texture_view: TextureView, size: UVec2) -> Self {
2121
Self {
2222
texture_view,
2323
size,
24-
format: TextureFormat::bevy_default(),
24+
view_format: TextureFormat::bevy_default(),
2525
}
2626
}
2727
}

crates/bevy_render/src/texture/texture_attachment.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,15 @@ impl DepthAttachment {
127127
#[derive(Clone)]
128128
pub struct OutputColorAttachment {
129129
pub view: TextureView,
130-
pub format: TextureFormat,
130+
pub view_format: TextureFormat,
131131
is_first_call: Arc<AtomicBool>,
132132
}
133133

134134
impl OutputColorAttachment {
135-
pub fn new(view: TextureView, format: TextureFormat) -> Self {
135+
pub fn new(view: TextureView, view_format: TextureFormat) -> Self {
136136
Self {
137137
view,
138-
format,
138+
view_format,
139139
is_first_call: Arc::new(AtomicBool::new(true)),
140140
}
141141
}

crates/bevy_render/src/view/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -847,8 +847,8 @@ impl ViewTarget {
847847

848848
/// The format of the final texture this view will render to
849849
#[inline]
850-
pub fn out_texture_format(&self) -> TextureFormat {
851-
self.out_texture.format
850+
pub fn out_texture_view_format(&self) -> TextureFormat {
851+
self.out_texture.view_format
852852
}
853853

854854
/// This will start a new "post process write", which assumes that the caller
@@ -1024,10 +1024,8 @@ pub fn prepare_view_attachments(
10241024
let Some(attachment) = target
10251025
.get_texture_view(&windows, &images, &manual_texture_views)
10261026
.cloned()
1027-
.zip(target.get_texture_format(&windows, &images, &manual_texture_views))
1028-
.map(|(view, format)| {
1029-
OutputColorAttachment::new(view.clone(), format.add_srgb_suffix())
1030-
})
1027+
.zip(target.get_texture_view_format(&windows, &images, &manual_texture_views))
1028+
.map(|(view, format)| OutputColorAttachment::new(view.clone(), format))
10311029
else {
10321030
continue;
10331031
};

crates/bevy_render/src/view/window/mod.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,17 @@ pub struct ExtractedWindow {
6060
pub swap_chain_texture_view: Option<TextureView>,
6161
pub swap_chain_texture: Option<SurfaceTexture>,
6262
pub swap_chain_texture_format: Option<TextureFormat>,
63+
pub swap_chain_texture_view_format: Option<TextureFormat>,
6364
pub size_changed: bool,
6465
pub present_mode_changed: bool,
6566
pub alpha_mode: CompositeAlphaMode,
6667
}
6768

6869
impl ExtractedWindow {
6970
fn set_swapchain_texture(&mut self, frame: wgpu::SurfaceTexture) {
71+
self.swap_chain_texture_view_format = Some(frame.texture.format().add_srgb_suffix());
7072
let texture_view_descriptor = TextureViewDescriptor {
71-
format: Some(frame.texture.format().add_srgb_suffix()),
73+
format: self.swap_chain_texture_view_format,
7274
..default()
7375
};
7476
self.swap_chain_texture_view = Some(TextureView::from(
@@ -140,6 +142,7 @@ fn extract_windows(
140142
swap_chain_texture_view: None,
141143
size_changed: false,
142144
swap_chain_texture_format: None,
145+
swap_chain_texture_view_format: None,
143146
present_mode_changed: false,
144147
alpha_mode: window.composite_alpha_mode,
145148
});
@@ -191,6 +194,7 @@ struct SurfaceData {
191194
// TODO: what lifetime should this be?
192195
surface: WgpuWrapper<wgpu::Surface<'static>>,
193196
configuration: SurfaceConfiguration,
197+
texture_view_format: Option<TextureFormat>,
194198
}
195199

196200
#[derive(Resource, Default)]
@@ -363,6 +367,11 @@ pub fn create_surfaces(
363367
}
364368
}
365369

370+
let texture_view_format = if !format.is_srgb() {
371+
Some(format.add_srgb_suffix())
372+
} else {
373+
None
374+
};
366375
let configuration = SurfaceConfiguration {
367376
format,
368377
width: window.physical_width,
@@ -391,10 +400,9 @@ pub fn create_surfaces(
391400
}
392401
CompositeAlphaMode::Inherit => wgpu::CompositeAlphaMode::Inherit,
393402
},
394-
view_formats: if !format.is_srgb() {
395-
vec![format.add_srgb_suffix()]
396-
} else {
397-
vec![]
403+
view_formats: match texture_view_format {
404+
Some(format) => vec![format],
405+
None => vec![],
398406
},
399407
};
400408

@@ -403,6 +411,7 @@ pub fn create_surfaces(
403411
SurfaceData {
404412
surface: WgpuWrapper::new(surface),
405413
configuration,
414+
texture_view_format,
406415
}
407416
});
408417

0 commit comments

Comments
 (0)