diff options
| author | HampusM <hampus@hampusmat.com> | 2026-08-28 18:32:58 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-08-28 18:32:58 +0200 |
| commit | be94cec078e86e643f52f0f3041a98b36e43ec8b (patch) | |
| tree | 0e79657d85020e76b0dc3e0586f9dcdacbfcd14e /engine/src/rendering/backend | |
| parent | d04bc21ac58a0bd8bcf8fa2fbb87f7b1dd4b140e (diff) | |
Diffstat (limited to 'engine/src/rendering/backend')
| -rw-r--r-- | engine/src/rendering/backend/opengl.rs | 295 |
1 files changed, 52 insertions, 243 deletions
diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs index 755388c..4d2a74f 100644 --- a/engine/src/rendering/backend/opengl.rs +++ b/engine/src/rendering/backend/opengl.rs @@ -6,7 +6,6 @@ use std::hint::cold_path; use std::num::NonZero; use ecs::query::term::With; -use ecs::util::BorrowedOrOwned; use glutin::config::Config as GlutinConfig; use glutin::display::GetGlDisplay; use glutin::error::Error as GlutinError; @@ -77,7 +76,6 @@ use crate::ecs::actions::Actions; use crate::ecs::query::term::Without; use crate::ecs::sole::Single; use crate::ecs::{Component, Query, Sole}; -use crate::image::{ColorType as ImageColorType, Image}; use crate::reflection::EnumReflectionExt; use crate::rendering::backend::opengl::glutin_compat::{ DisplayBuilder, @@ -117,6 +115,7 @@ use crate::rendering::{ Surface, SurfaceId, TargetWindow, + TextureCreation, TexturePixelDataFormat, TextureUpdate, POST_RENDER_PHASE, @@ -126,8 +125,6 @@ use crate::texture::{ CubeMapFace as CubeMapTextureFace, Filtering as TextureFiltering, Properties as TextureProperties, - TexCubeMap, - Texture, Wrapping as TextureWrapping, }; use crate::util::{MapVec, OptionExt}; @@ -364,7 +361,7 @@ enum BackendResource { texture: GlTexture, pixel_data_format: TexturePixelDataFormat, - metadata: TextureKind, + kind: TextureKind, }, } @@ -953,22 +950,39 @@ fn handle_commands( ) .unwrap(); } - Command::CreateTexture(object_id, texture) => { - let _ = backend_resources.try_create_resource::<()>( - object_store, - object_id, - || { - let (gl_texture, texture_pixel_data_format, texture_kind) = - create_texture_object(gl_context, assets, texture) - .map_err(|_| ())?; - - Ok(BackendResource::Texture { - texture: gl_texture, - pixel_data_format: texture_pixel_data_format, - metadata: texture_kind, - }) - }, - ); + Command::CreateTexture { + obj_id, + pixel_data_format, + creation, + properties, + } => { + let kind = match &creation { + TextureCreation::Texture2D { .. } => TextureKind::Texture2D, + TextureCreation::CubeMap { .. } => TextureKind::CubeMap, + }; + + if let Err(err) = backend_resources + .try_create_resource::<opengl_bindings::texture::Error>( + object_store, + obj_id, + || { + let gl_texture = create_gl_texture( + gl_context, + creation, + pixel_data_format, + &properties, + )?; + + Ok(BackendResource::Texture { + texture: gl_texture, + pixel_data_format, + kind, + }) + }, + ) + { + tracing::error!("Failed to create texture: {err}"); + } } Command::UpdateTexture { obj_id, @@ -987,7 +1001,7 @@ fn handle_commands( let BackendResource::Texture { texture: gl_texture, pixel_data_format: tex_pixel_data_format, - metadata: tex_metadata, + kind: tex_metadata, } = texture_resource else { unreachable!(); @@ -1298,176 +1312,6 @@ enum CreateGlContextError MakeContextCurrent(#[source] GlMakeContextCurrentError), } -enum TextureCreationData<'a> -{ - Texture2D - { - image: BorrowedOrOwned<'a, Image> - }, - CubeMap - { - images: [(CubeMapTextureFace, BorrowedOrOwned<'a, Image>); 6], - color_type: ImageColorType, - is_srgb: bool, - size: Dimens<u32>, - }, -} - -fn validate_cube_map_texture(texture: &TexCubeMap) -> bool -{ - let first_image_color_type = texture.images[0].1.color_type(); - - if !texture.images[1..] - .into_iter() - .all(|(_, image)| image.color_type() == first_image_color_type) - { - tracing::error!("All texture images must have same color type"); - return false; - } - - let first_image_size = texture.images[0].1.dimensions(); - - if !texture.images[1..] - .into_iter() - .all(|(_, image)| image.dimensions() == first_image_size) - { - tracing::error!("All texture images must have same dimensions"); - return false; - } - - let first_image_is_srgb = texture.images[0].1.color_space_is_srgb(); - - if !texture.images[1..] - .into_iter() - .all(|(_, image)| image.color_space_is_srgb() == first_image_is_srgb) - { - tracing::error!("All texture images must have same color space"); - return false; - } - - true -} - -fn convert_textures_if_unaligned<const IMAGE_CNT: usize, Extra>( - images: [(Extra, &Image); IMAGE_CNT], - color_type: ImageColorType, - size: Dimens<u32>, -) -> [(Extra, BorrowedOrOwned<'_, Image>); IMAGE_CNT] -{ - match color_type { - ImageColorType::Rgb8 if (size.width * 3) % 4 != 0 => { - // The texture will be corrupted if the alignment of each horizontal line of - // the texture pixel array is not multiple of 4. - // - // Read more about this at - // wikis.khronos.org/opengl/Common_Mistakes#Texture_upload_and_pixel_reads - // - // To prevent this, the image is converted to RGBA8. RGBA8 images have a pixel - // size of 4 bytes so they cannot have any alignment problems - - // TODO: Make it clearer in warning log which texture is being talked about - tracing::warn!(concat!( - "Converting texture image from RGB8 to RGBA8 to prevent alignment ", - "problems. This conversion may be slow. Consider changing the ", - "texture image's pixel format to RGBA8" - )); - - images.map(|(extra, image)| (extra, BorrowedOrOwned::Owned(image.to_rgba8()))) - } - _ => images.map(|(extra, image)| (extra, BorrowedOrOwned::Borrowned(image))), - } -} - -#[tracing::instrument(skip_all)] -fn create_texture_object( - curr_gl_ctx: &MaybeCurrentContextWithFns, - assets: &Assets, - texture: AssetOrValue<Texture>, -) -> Result<(GlTexture, TexturePixelDataFormat, TextureKind), ()> -{ - let texture = match &texture { - AssetOrValue::Asset(texture_asset) => { - let Some(texture) = assets.get(&texture_asset) else { - tracing::error!( - texture_asset_id=?texture_asset.id(), - "Texture asset does not exist" - ); - return Err(()); - }; - - texture - } - AssetOrValue::Value(texture) => texture, - }; - - let (texture_things, texture_properties, texture_pixel_data_format, texture_kind) = - match texture { - Texture::Texture2D(texture) => { - let [(_, image)] = convert_textures_if_unaligned( - [((), &texture.image)], - texture.image.color_type(), - texture.image.dimensions(), - ); - - let tex_pixel_data_format = TexturePixelDataFormat::for_image(&image) - .expect("No pixel data format is available for image"); - - ( - TextureCreationData::Texture2D { image }, - &texture.properties, - tex_pixel_data_format, - TextureKind::Texture2D, - ) - } - Texture::CubeMap(texture) => { - if !validate_cube_map_texture(texture) { - return Err(()); - } - - let first_image_color_type = texture.images[0].1.color_type(); - let first_image_size = texture.images[0].1.dimensions(); - let first_image_is_srgb = texture.images[0].1.color_space_is_srgb(); - - let images = convert_textures_if_unaligned( - std::array::from_fn::<_, 6, _>(|index| { - let (face, image) = &texture.images[index]; - - (*face, image) - }), - first_image_color_type, - first_image_size, - ); - - let tex_pixel_data_format = - TexturePixelDataFormat::for_image(&images[0].1) - .expect("No pixel data format is available for image"); - - ( - TextureCreationData::CubeMap { - images, - color_type: first_image_color_type, - is_srgb: first_image_is_srgb, - size: first_image_size, - }, - &texture.properties, - tex_pixel_data_format, - TextureKind::CubeMap, - ) - } - }; - - let gl_texture = - match create_gl_texture(curr_gl_ctx, texture_things, texture_properties) { - Ok(gl_texture) => gl_texture, - Err(err) => { - tracing::error!("Failed to create texture object: {err}"); - return Err(()); - } - }; - - Ok((gl_texture, texture_pixel_data_format, texture_kind)) -} - #[tracing::instrument(skip_all)] fn update_texture_object( curr_gl_ctx: &MaybeCurrentContextWithFns, @@ -1540,12 +1384,6 @@ fn draw_mesh( Ok(()) } -struct ImageDataProperties -{ - color_type: ImageColorType, - is_srgb: bool, -} - fn tex_pixel_data_format_into_gl( tex_pixel_data_format: TexturePixelDataFormat, ) -> GlTexturePixelDataFormat @@ -1582,59 +1420,30 @@ fn tex_pixel_data_format_into_gl( } } -fn create_pixel_data_format( - image_data_props: ImageDataProperties, -) -> GlTexturePixelDataFormat -{ - match image_data_props.color_type { - ImageColorType::Rgb8 if image_data_props.is_srgb => { - GlTexturePixelDataFormat::Srgb( - opengl_bindings::texture::SrgbDataType::UnsignedByte, - ) - } - ImageColorType::Rgb8 => GlTexturePixelDataFormat::Rgb( - opengl_bindings::texture::RgbDataType::UnsignedByte, - ), - ImageColorType::Rgba8 if image_data_props.is_srgb => { - GlTexturePixelDataFormat::Srgba( - opengl_bindings::texture::SrgbaDataType::UnsignedByte, - ) - } - ImageColorType::Rgba8 => GlTexturePixelDataFormat::Rgba( - opengl_bindings::texture::RgbaDataType::UnsignedByte, - ), - _ => { - unimplemented!(); - } - } -} - fn create_gl_texture( curr_gl_context: &MaybeCurrentContextWithFns, - texture_things: TextureCreationData<'_>, + texture_creation: TextureCreation, + texture_pixel_data_format: TexturePixelDataFormat, texture_properties: &TextureProperties, ) -> Result<GlTexture, GlTextureError> { - let gl_texture = match texture_things { - TextureCreationData::Texture2D { image } => GlTexture::builder() - .size(image.dimensions().into()) - .create_2d( + let gl_texture = match texture_creation { + TextureCreation::Texture2D { size, image } => { + GlTexture::builder().size(size.into()).create_2d( curr_gl_context, - Some(image.as_bytes()), - create_pixel_data_format(ImageDataProperties { - color_type: image.color_type(), - is_srgb: image.color_space_is_srgb(), - }), - ), - TextureCreationData::CubeMap { images, color_type, is_srgb, size } => { + image.as_deref(), + tex_pixel_data_format_into_gl(texture_pixel_data_format), + ) + } + TextureCreation::CubeMap { size, images } => { GlTexture::builder().size(size.into()).create_cube_map( curr_gl_context, - Some(std::array::from_fn::<_, 6, _>(|index| { - let (face, image) = &images[index]; - - (cube_map_texture_face_to_gl(*face), image.as_bytes()) - })), - create_pixel_data_format(ImageDataProperties { color_type, is_srgb }), + images.as_ref().map(|images| { + images.each_ref().map(|(face, image)| { + (cube_map_texture_face_to_gl(*face), &**image) + }) + }), + tex_pixel_data_format_into_gl(texture_pixel_data_format), ) } }?; |
