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 https://github.com/bevyengine/bevy/issues/3897.

## Solution

Make `initialize_renderer` expose `wgpu::Adapter` and `first_available_texture_format`, use the `first_available_texture_format` by default.

## Changelog

* Fixed https://github.com/bevyengine/bevy/issues/3897.
This commit is contained in:
VitalyR 2022-10-10 16:10:05 +00:00
parent 1738527902
commit f5322cd757
8 changed files with 209 additions and 39 deletions

View File

@ -21,10 +21,8 @@ use bevy_render::{
render_asset::RenderAssets, render_asset::RenderAssets,
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass}, render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
render_resource::*, render_resource::*,
renderer::{RenderDevice, RenderQueue}, renderer::{RenderDevice, RenderQueue, RenderTextureFormat},
texture::{ texture::{DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo},
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
},
view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms}, view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms},
Extract, RenderApp, RenderStage, Extract, RenderApp, RenderStage,
}; };
@ -270,8 +268,10 @@ impl FromWorld for MeshPipeline {
Res<RenderDevice>, Res<RenderDevice>,
Res<DefaultImageSampler>, Res<DefaultImageSampler>,
Res<RenderQueue>, Res<RenderQueue>,
Res<RenderTextureFormat>,
)> = SystemState::new(world); )> = SystemState::new(world);
let (render_device, default_sampler, render_queue) = system_state.get_mut(world); let (render_device, default_sampler, render_queue, first_available_texture_format) =
system_state.get_mut(world);
let clustered_forward_buffer_binding_type = render_device let clustered_forward_buffer_binding_type = render_device
.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT); .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
@ -438,7 +438,7 @@ impl FromWorld for MeshPipeline {
Extent3d::default(), Extent3d::default(),
TextureDimension::D2, TextureDimension::D2,
&[255u8; 4], &[255u8; 4],
TextureFormat::bevy_default(), first_available_texture_format.0,
); );
let texture = render_device.create_texture(&image.texture_descriptor); let texture = render_device.create_texture(&image.texture_descriptor);
let sampler = match image.sampler_descriptor { let sampler = match image.sampler_descriptor {
@ -629,7 +629,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
shader_defs, shader_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {
format: TextureFormat::bevy_default(), format: self.dummy_white_gpu_image.texture_format,
blend, blend,
write_mask: ColorWrites::ALL, write_mask: ColorWrites::ALL,
})], })],

View File

@ -47,7 +47,7 @@ use crate::{
primitives::{CubemapFrusta, Frustum}, primitives::{CubemapFrusta, Frustum},
render_graph::RenderGraph, render_graph::RenderGraph,
render_resource::{PipelineCache, Shader, ShaderLoader}, render_resource::{PipelineCache, Shader, ShaderLoader},
renderer::{render_system, RenderInstance}, renderer::{render_system, RenderInstance, RenderTextureFormat},
texture::ImagePlugin, texture::ImagePlugin,
view::{ViewPlugin, WindowRenderPlugin}, view::{ViewPlugin, WindowRenderPlugin},
}; };
@ -157,14 +157,23 @@ impl Plugin for RenderPlugin {
compatible_surface: surface.as_ref(), compatible_surface: surface.as_ref(),
..Default::default() ..Default::default()
}; };
let (device, queue, adapter_info) = futures_lite::future::block_on( let (device, queue, adapter_info, render_adapter, available_texture_formats) =
renderer::initialize_renderer(&instance, &options, &request_adapter_options), futures_lite::future::block_on(renderer::initialize_renderer(
); &instance,
&options,
&request_adapter_options,
));
// `available_texture_formats` won't be empty, or else will panick in the former
// `initialize_renderer` call.
let first_available_texture_format = RenderTextureFormat(available_texture_formats[0]);
debug!("Configured wgpu adapter Limits: {:#?}", device.limits()); debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
debug!("Configured wgpu adapter Features: {:#?}", device.features()); debug!("Configured wgpu adapter Features: {:#?}", device.features());
app.insert_resource(device.clone()) app.insert_resource(device.clone())
.insert_resource(queue.clone()) .insert_resource(queue.clone())
.insert_resource(adapter_info.clone()) .insert_resource(adapter_info.clone())
.insert_resource(render_adapter.clone())
.insert_resource(available_texture_formats.clone())
.insert_resource(first_available_texture_format.clone())
.init_resource::<ScratchMainWorld>() .init_resource::<ScratchMainWorld>()
.register_type::<Frustum>() .register_type::<Frustum>()
.register_type::<CubemapFrusta>(); .register_type::<CubemapFrusta>();
@ -206,6 +215,9 @@ impl Plugin for RenderPlugin {
.insert_resource(RenderInstance(instance)) .insert_resource(RenderInstance(instance))
.insert_resource(device) .insert_resource(device)
.insert_resource(queue) .insert_resource(queue)
.insert_resource(render_adapter)
.insert_resource(available_texture_formats)
.insert_resource(first_available_texture_format)
.insert_resource(adapter_info) .insert_resource(adapter_info)
.insert_resource(pipeline_cache) .insert_resource(pipeline_cache)
.insert_resource(asset_server); .insert_resource(asset_server);

View File

@ -15,7 +15,7 @@ use bevy_ecs::prelude::*;
use bevy_time::TimeSender; use bevy_time::TimeSender;
use bevy_utils::Instant; use bevy_utils::Instant;
use std::sync::Arc; use std::sync::Arc;
use wgpu::{AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions}; use wgpu::{Adapter, AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions};
/// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame. /// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame.
pub fn render_system(world: &mut World) { pub fn render_system(world: &mut World) {
@ -88,6 +88,11 @@ pub fn render_system(world: &mut World) {
#[derive(Resource, Clone, Deref, DerefMut)] #[derive(Resource, Clone, Deref, DerefMut)]
pub struct RenderQueue(pub Arc<Queue>); pub struct RenderQueue(pub Arc<Queue>);
/// The handle to the physical device being used for rendering.
/// See [`wgpu::Adapter`] for more info.
#[derive(Resource, Clone, Debug, Deref, DerefMut)]
pub struct RenderAdapter(pub Arc<Adapter>);
/// The GPU instance is used to initialize the [`RenderQueue`] and [`RenderDevice`], /// The GPU instance is used to initialize the [`RenderQueue`] and [`RenderDevice`],
/// as well as to create [`WindowSurfaces`](crate::view::window::WindowSurfaces). /// as well as to create [`WindowSurfaces`](crate::view::window::WindowSurfaces).
#[derive(Resource, Deref, DerefMut)] #[derive(Resource, Deref, DerefMut)]
@ -97,13 +102,29 @@ pub struct RenderInstance(pub Instance);
#[derive(Resource, Clone, Deref, DerefMut)] #[derive(Resource, Clone, Deref, DerefMut)]
pub struct RenderAdapterInfo(pub AdapterInfo); pub struct RenderAdapterInfo(pub AdapterInfo);
/// The [`TextureFormat`](wgpu::TextureFormat) used for rendering.
/// Initially it's the first element in `AvailableTextureFormats`.
#[derive(Resource, Clone, Deref, DerefMut)]
pub struct RenderTextureFormat(pub wgpu::TextureFormat);
/// The available [`TextureFormat`](wgpu::TextureFormat)s on the [`RenderAdapter`].
/// Will be inserted as a `Resource` after the renderer is initialized.
#[derive(Resource, Clone, Deref, DerefMut)]
pub struct AvailableTextureFormats(pub Arc<Vec<wgpu::TextureFormat>>);
/// Initializes the renderer by retrieving and preparing the GPU instance, device and queue /// Initializes the renderer by retrieving and preparing the GPU instance, device and queue
/// for the specified backend. /// for the specified backend.
pub async fn initialize_renderer( pub async fn initialize_renderer(
instance: &Instance, instance: &Instance,
options: &WgpuSettings, options: &WgpuSettings,
request_adapter_options: &RequestAdapterOptions<'_>, request_adapter_options: &RequestAdapterOptions<'_>,
) -> (RenderDevice, RenderQueue, RenderAdapterInfo) { ) -> (
RenderDevice,
RenderQueue,
RenderAdapterInfo,
RenderAdapter,
AvailableTextureFormats,
) {
let adapter = instance let adapter = instance
.request_adapter(request_adapter_options) .request_adapter(request_adapter_options)
.await .await
@ -250,12 +271,25 @@ pub async fn initialize_renderer(
) )
.await .await
.unwrap(); .unwrap();
let device = Arc::new(device); let device = Arc::new(device);
let queue = Arc::new(queue); let queue = Arc::new(queue);
let adapter = Arc::new(adapter);
let mut available_texture_formats = Vec::new();
if let Some(s) = request_adapter_options.compatible_surface {
available_texture_formats = s.get_supported_formats(&adapter);
if available_texture_formats.is_empty() {
info!("{:?}", adapter_info);
panic!("No supported texture formats found!");
}
};
let available_texture_formats = Arc::new(available_texture_formats);
( (
RenderDevice::from(device), RenderDevice::from(device),
RenderQueue(queue), RenderQueue(queue),
RenderAdapterInfo(adapter_info), RenderAdapterInfo(adapter_info),
RenderAdapter(adapter),
AvailableTextureFormats(available_texture_formats),
) )
} }

View File

@ -4,7 +4,7 @@ pub mod window;
pub use visibility::*; pub use visibility::*;
use wgpu::{ use wgpu::{
Color, Extent3d, Operations, RenderPassColorAttachment, TextureDescriptor, TextureDimension, Color, Extent3d, Operations, RenderPassColorAttachment, TextureDescriptor, TextureDimension,
TextureFormat, TextureUsages, TextureUsages,
}; };
pub use window::*; pub use window::*;
@ -15,8 +15,8 @@ use crate::{
rangefinder::ViewRangefinder3d, rangefinder::ViewRangefinder3d,
render_asset::RenderAssets, render_asset::RenderAssets,
render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView}, render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView},
renderer::{RenderDevice, RenderQueue}, renderer::{RenderDevice, RenderQueue, RenderTextureFormat},
texture::{BevyDefault, TextureCache}, texture::TextureCache,
RenderApp, RenderStage, RenderApp, RenderStage,
}; };
use bevy_app::{App, Plugin}; use bevy_app::{App, Plugin};
@ -182,6 +182,7 @@ fn prepare_view_targets(
images: Res<RenderAssets<Image>>, images: Res<RenderAssets<Image>>,
msaa: Res<Msaa>, msaa: Res<Msaa>,
render_device: Res<RenderDevice>, render_device: Res<RenderDevice>,
texture_format: Res<RenderTextureFormat>,
mut texture_cache: ResMut<TextureCache>, mut texture_cache: ResMut<TextureCache>,
cameras: Query<(Entity, &ExtractedCamera)>, cameras: Query<(Entity, &ExtractedCamera)>,
) { ) {
@ -205,7 +206,7 @@ fn prepare_view_targets(
mip_level_count: 1, mip_level_count: 1,
sample_count: msaa.samples, sample_count: msaa.samples,
dimension: TextureDimension::D2, dimension: TextureDimension::D2,
format: TextureFormat::bevy_default(), format: **texture_format,
usage: TextureUsages::RENDER_ATTACHMENT, usage: TextureUsages::RENDER_ATTACHMENT,
}, },
) )

View File

@ -1,7 +1,6 @@
use crate::{ use crate::{
render_resource::TextureView, render_resource::TextureView,
renderer::{RenderDevice, RenderInstance}, renderer::{RenderAdapter, RenderDevice, RenderInstance},
texture::BevyDefault,
Extract, RenderApp, RenderStage, Extract, RenderApp, RenderStage,
}; };
use bevy_app::{App, Plugin}; use bevy_app::{App, Plugin};
@ -9,7 +8,6 @@ use bevy_ecs::prelude::*;
use bevy_utils::{tracing::debug, HashMap, HashSet}; use bevy_utils::{tracing::debug, HashMap, HashSet};
use bevy_window::{PresentMode, RawWindowHandleWrapper, WindowClosed, WindowId, Windows}; use bevy_window::{PresentMode, RawWindowHandleWrapper, WindowClosed, WindowId, Windows};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use wgpu::TextureFormat;
/// Token to ensure a system runs on the main thread. /// Token to ensure a system runs on the main thread.
#[derive(Resource, Default)] #[derive(Resource, Default)]
@ -161,6 +159,7 @@ pub fn prepare_windows(
mut window_surfaces: ResMut<WindowSurfaces>, mut window_surfaces: ResMut<WindowSurfaces>,
render_device: Res<RenderDevice>, render_device: Res<RenderDevice>,
render_instance: Res<RenderInstance>, render_instance: Res<RenderInstance>,
render_adapter: Res<RenderAdapter>,
) { ) {
let window_surfaces = window_surfaces.deref_mut(); let window_surfaces = window_surfaces.deref_mut();
for window in windows.windows.values_mut() { for window in windows.windows.values_mut() {
@ -173,7 +172,15 @@ pub fn prepare_windows(
}); });
let swap_chain_descriptor = wgpu::SurfaceConfiguration { let swap_chain_descriptor = wgpu::SurfaceConfiguration {
format: TextureFormat::bevy_default(), format: *surface
.get_supported_formats(&render_adapter)
.get(0)
.unwrap_or_else(|| {
panic!(
"No supported formats found for surface {:?} on adapter {:?}",
surface, render_adapter
)
}),
width: window.physical_width, width: window.physical_width,
height: window.physical_height, height: window.physical_height,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT, usage: wgpu::TextureUsages::RENDER_ATTACHMENT,

View File

@ -12,10 +12,8 @@ use bevy_render::{
render_asset::RenderAssets, render_asset::RenderAssets,
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass}, render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
render_resource::*, render_resource::*,
renderer::{RenderDevice, RenderQueue}, renderer::{RenderDevice, RenderQueue, RenderTextureFormat},
texture::{ texture::{DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo},
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
},
view::{ComputedVisibility, ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms}, view::{ComputedVisibility, ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms},
Extract, RenderApp, RenderStage, Extract, RenderApp, RenderStage,
}; };
@ -158,9 +156,13 @@ pub struct Mesh2dPipeline {
impl FromWorld for Mesh2dPipeline { impl FromWorld for Mesh2dPipeline {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let mut system_state: SystemState<(Res<RenderDevice>, Res<DefaultImageSampler>)> = let mut system_state: SystemState<(
SystemState::new(world); Res<RenderDevice>,
let (render_device, default_sampler) = system_state.get_mut(world); Res<DefaultImageSampler>,
Res<RenderTextureFormat>,
)> = SystemState::new(world);
let (render_device, default_sampler, first_available_texture_format) =
system_state.get_mut(world);
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[ entries: &[
// View // View
@ -197,7 +199,7 @@ impl FromWorld for Mesh2dPipeline {
Extent3d::default(), Extent3d::default(),
TextureDimension::D2, TextureDimension::D2,
&[255u8; 4], &[255u8; 4],
TextureFormat::bevy_default(), first_available_texture_format.0,
); );
let texture = render_device.create_texture(&image.texture_descriptor); let texture = render_device.create_texture(&image.texture_descriptor);
let sampler = match image.sampler_descriptor { let sampler = match image.sampler_descriptor {
@ -354,7 +356,7 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
shader_defs, shader_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {
format: TextureFormat::bevy_default(), format: self.dummy_white_gpu_image.texture_format,
blend: Some(BlendState::ALPHA_BLENDING), blend: Some(BlendState::ALPHA_BLENDING),
write_mask: ColorWrites::ALL, write_mask: ColorWrites::ALL,
})], })],

View File

@ -8,7 +8,7 @@ use bevy_asset::{AssetEvent, Assets, Handle, HandleId};
use bevy_core_pipeline::core_2d::Transparent2d; use bevy_core_pipeline::core_2d::Transparent2d;
use bevy_ecs::{ use bevy_ecs::{
prelude::*, prelude::*,
system::{lifetimeless::*, SystemParamItem}, system::{lifetimeless::*, SystemParamItem, SystemState},
}; };
use bevy_math::{Rect, Vec2}; use bevy_math::{Rect, Vec2};
use bevy_reflect::Uuid; use bevy_reflect::Uuid;
@ -20,8 +20,8 @@ use bevy_render::{
RenderPhase, SetItemPipeline, TrackedRenderPass, RenderPhase, SetItemPipeline, TrackedRenderPass,
}, },
render_resource::*, render_resource::*,
renderer::{RenderDevice, RenderQueue}, renderer::{RenderDevice, RenderQueue, RenderTextureFormat},
texture::{BevyDefault, Image}, texture::{DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo},
view::{ view::{
ComputedVisibility, Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities, ComputedVisibility, Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities,
}, },
@ -37,11 +37,19 @@ use fixedbitset::FixedBitSet;
pub struct SpritePipeline { pub struct SpritePipeline {
view_layout: BindGroupLayout, view_layout: BindGroupLayout,
material_layout: BindGroupLayout, material_layout: BindGroupLayout,
pub dummy_white_gpu_image: GpuImage,
} }
impl FromWorld for SpritePipeline { impl FromWorld for SpritePipeline {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>(); let mut system_state: SystemState<(
Res<RenderDevice>,
Res<DefaultImageSampler>,
Res<RenderQueue>,
Res<RenderTextureFormat>,
)> = SystemState::new(world);
let (render_device, default_sampler, render_queue, first_available_texture_format) =
system_state.get_mut(world);
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry { entries: &[BindGroupLayoutEntry {
@ -78,10 +86,57 @@ impl FromWorld for SpritePipeline {
], ],
label: Some("sprite_material_layout"), label: Some("sprite_material_layout"),
}); });
let dummy_white_gpu_image = {
let image = Image::new_fill(
Extent3d::default(),
TextureDimension::D2,
&[255u8; 4],
first_available_texture_format.0,
);
let texture = render_device.create_texture(&image.texture_descriptor);
let sampler = match image.sampler_descriptor {
ImageSampler::Default => (**default_sampler).clone(),
ImageSampler::Descriptor(descriptor) => render_device.create_sampler(&descriptor),
};
let format_size = image.texture_descriptor.format.pixel_size();
render_queue.write_texture(
ImageCopyTexture {
texture: &texture,
mip_level: 0,
origin: Origin3d::ZERO,
aspect: TextureAspect::All,
},
&image.data,
ImageDataLayout {
offset: 0,
bytes_per_row: Some(
std::num::NonZeroU32::new(
image.texture_descriptor.size.width * format_size as u32,
)
.unwrap(),
),
rows_per_image: None,
},
image.texture_descriptor.size,
);
let texture_view = texture.create_view(&TextureViewDescriptor::default());
GpuImage {
texture,
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size: Vec2::new(
image.texture_descriptor.size.width as f32,
image.texture_descriptor.size.height as f32,
),
}
};
SpritePipeline { SpritePipeline {
view_layout, view_layout,
material_layout, material_layout,
dummy_white_gpu_image,
} }
} }
} }
@ -148,7 +203,7 @@ impl SpecializedRenderPipeline for SpritePipeline {
shader_defs, shader_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {
format: TextureFormat::bevy_default(), format: self.dummy_white_gpu_image.texture_format,
blend: Some(BlendState::ALPHA_BLENDING), blend: Some(BlendState::ALPHA_BLENDING),
write_mask: ColorWrites::ALL, write_mask: ColorWrites::ALL,
})], })],

View File

@ -1,17 +1,29 @@
use bevy_ecs::prelude::*; use bevy_ecs::{prelude::*, system::SystemState};
use bevy_math::Vec2;
use bevy_render::{ use bevy_render::{
render_resource::*, renderer::RenderDevice, texture::BevyDefault, view::ViewUniform, render_resource::*,
renderer::{RenderDevice, RenderQueue, RenderTextureFormat},
texture::{DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo},
view::ViewUniform,
}; };
#[derive(Resource)] #[derive(Resource)]
pub struct UiPipeline { pub struct UiPipeline {
pub view_layout: BindGroupLayout, pub view_layout: BindGroupLayout,
pub image_layout: BindGroupLayout, pub image_layout: BindGroupLayout,
pub dummy_white_gpu_image: GpuImage,
} }
impl FromWorld for UiPipeline { impl FromWorld for UiPipeline {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>(); let mut system_state: SystemState<(
Res<RenderDevice>,
Res<DefaultImageSampler>,
Res<RenderQueue>,
Res<RenderTextureFormat>,
)> = SystemState::new(world);
let (render_device, default_sampler, render_queue, first_available_texture_format) =
system_state.get_mut(world);
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry { entries: &[BindGroupLayoutEntry {
@ -48,10 +60,57 @@ impl FromWorld for UiPipeline {
], ],
label: Some("ui_image_layout"), label: Some("ui_image_layout"),
}); });
let dummy_white_gpu_image = {
let image = Image::new_fill(
Extent3d::default(),
TextureDimension::D2,
&[255u8; 4],
first_available_texture_format.0,
);
let texture = render_device.create_texture(&image.texture_descriptor);
let sampler = match image.sampler_descriptor {
ImageSampler::Default => (**default_sampler).clone(),
ImageSampler::Descriptor(descriptor) => render_device.create_sampler(&descriptor),
};
let format_size = image.texture_descriptor.format.pixel_size();
render_queue.write_texture(
ImageCopyTexture {
texture: &texture,
mip_level: 0,
origin: Origin3d::ZERO,
aspect: TextureAspect::All,
},
&image.data,
ImageDataLayout {
offset: 0,
bytes_per_row: Some(
std::num::NonZeroU32::new(
image.texture_descriptor.size.width * format_size as u32,
)
.unwrap(),
),
rows_per_image: None,
},
image.texture_descriptor.size,
);
let texture_view = texture.create_view(&TextureViewDescriptor::default());
GpuImage {
texture,
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size: Vec2::new(
image.texture_descriptor.size.width as f32,
image.texture_descriptor.size.height as f32,
),
}
};
UiPipeline { UiPipeline {
view_layout, view_layout,
image_layout, image_layout,
dummy_white_gpu_image,
} }
} }
} }
@ -88,7 +147,7 @@ impl SpecializedRenderPipeline for UiPipeline {
shader_defs, shader_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState { targets: vec![Some(ColorTargetState {
format: TextureFormat::bevy_default(), format: self.dummy_white_gpu_image.texture_format,
blend: Some(BlendState::ALPHA_BLENDING), blend: Some(BlendState::ALPHA_BLENDING),
write_mask: ColorWrites::ALL, write_mask: ColorWrites::ALL,
})], })],