From 9ab41d06b4ff0b52360a8cda756a3b1343a1e2fc Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 26 Mar 2026 16:42:22 +0100 Subject: fix(engine): prevent uploading textures with invalid row alignments --- engine/src/renderer/opengl.rs | 55 ++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 14 deletions(-) (limited to 'engine/src/renderer') diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs index 11a4ca9..dc8e561 100644 --- a/engine/src/renderer/opengl.rs +++ b/engine/src/renderer/opengl.rs @@ -61,7 +61,7 @@ use opengl_bindings::{ContextWithFns, CurrentContextWithFns}; use safer_ffi::layout::ReprC; use zerocopy::{Immutable, IntoBytes}; -use crate::asset::{Assets, Id as AssetId}; +use crate::asset::{Assets, Handle as AssetHandle}; use crate::data_types::dimens::Dimens; use crate::image::{ColorType as ImageColorType, Image}; use crate::matrix::Matrix; @@ -100,6 +100,7 @@ use crate::shader::{ use crate::texture::{ Filtering as TextureFiltering, Properties as TextureProperties, + Texture, Wrapping as TextureWrapping, }; use crate::vector::{Vec2, Vec3}; @@ -898,17 +899,11 @@ fn handle_commands( continue; }; - let Some(texture) = assets.get(&texture_asset) else { - tracing::error!("Texture asset is not loaded",); - continue; - }; - if let Err(err) = create_texture_object( curr_gl_ctx, &mut renderer_object_store, - texture_asset.id(), - &texture.image, - &texture.properties, + &assets, + &texture_asset, ) { tracing::error!("Failed to create texture object: {err}"); } @@ -1058,12 +1053,11 @@ fn handle_commands( fn create_texture_object( curr_gl_ctx: &CurrentContextWithFns<'_>, renderer_object_store: &mut RendererObjectStore, - texture_image_asset_id: AssetId, - image: &Image, - texture_properties: &TextureProperties, + assets: &Assets, + texture_asset: &AssetHandle, ) -> Result<(), GlTextureGenerateError> { - let object_id = RendererObjectId::Asset(texture_image_asset_id); + let object_id = RendererObjectId::Asset(texture_asset.id()); if renderer_object_store.contains_with_id(&object_id) { tracing::error!( @@ -1073,10 +1067,43 @@ fn create_texture_object( return Ok(()); } + let Some(texture) = assets.get(&texture_asset) else { + tracing::error!("Texture asset is not loaded",); + return Ok(()); + }; + + let texture_image = match texture.image.color_type() { + ImageColorType::Rgb8 if (texture.image.dimensions().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 + + tracing::warn!( + texture_asset = %assets + .get_label(&texture_asset) + .expect("Not possible"), + 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" + ) + ); + + &texture.image.to_rgba8() + } + _ => &texture.image, + }; + renderer_object_store.insert( object_id, RendererObject::from_raw( - create_gl_texture(curr_gl_ctx, image, texture_properties)?.into_raw(), + create_gl_texture(curr_gl_ctx, texture_image, &texture.properties)? + .into_raw(), RendererObjectKind::Texture, ), ); -- cgit v1.2.3-18-g5258