Store Option<ImageInfo> instead of making fields optional

This commit is contained in:
teapotd 2019-10-31 19:20:52 +01:00
parent 48d918dcde
commit a4fa36f9fb
4 changed files with 47 additions and 69 deletions

View file

@ -613,7 +613,7 @@ impl<'a> WebGLValidator for CompressedTexSubImage2DValidator<'a> {
compression, compression,
} = self.compression_validator.validate()?; } = self.compression_validator.validate()?;
let tex_info = texture.image_info_for_target(&target, level); let tex_info = texture.image_info_for_target(&target, level).unwrap();
// GL_INVALID_VALUE is generated if: // GL_INVALID_VALUE is generated if:
// - xoffset or yoffset is less than 0 // - xoffset or yoffset is less than 0
@ -630,7 +630,7 @@ impl<'a> WebGLValidator for CompressedTexSubImage2DValidator<'a> {
// GL_INVALID_OPERATION is generated if format does not match // GL_INVALID_OPERATION is generated if format does not match
// internal_format. // internal_format.
if compression.format != tex_info.internal_format().unwrap() { if compression.format != tex_info.internal_format() {
context.webgl_error(InvalidOperation); context.webgl_error(InvalidOperation);
return Err(TexImageValidationError::TextureFormatMismatch); return Err(TexImageValidationError::TextureFormatMismatch);
} }

View file

@ -221,12 +221,16 @@ impl WebGLFramebuffer {
Some(WebGLFramebufferAttachment::Texture { Some(WebGLFramebufferAttachment::Texture {
texture: ref att_tex, texture: ref att_tex,
level, level,
}) => { }) => match att_tex.image_info_at_face(0, level as u32) {
let info = att_tex.image_info_at_face(0, level as u32); Some(info) => (
( Some(info.internal_format().as_gl_constant()),
info.internal_format().map(|t| t.as_gl_constant()),
Some((info.width() as i32, info.height() as i32)), Some((info.width() as i32, info.height() as i32)),
) ),
None => {
self.status
.set(constants::FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
return;
},
}, },
None => (None, None), None => (None, None),
}; };

View file

@ -438,13 +438,12 @@ impl WebGLRenderingContext {
} }
let target = TexImageTarget::Texture2D; let target = TexImageTarget::Texture2D;
let info = texture.image_info_for_target(&target, 0); if let Some(info) = texture.image_info_for_target(&target, 0) {
if info.is_initialized() {
self.validate_filterable_texture( self.validate_filterable_texture(
&texture, &texture,
target, target,
0, 0,
info.internal_format().unwrap_or(TexFormat::RGBA), info.internal_format(),
Size2D::new(info.width(), info.height()), Size2D::new(info.width(), info.height()),
info.data_type().unwrap_or(TexDataType::UnsignedByte), info.data_type().unwrap_or(TexDataType::UnsignedByte),
); );
@ -746,7 +745,10 @@ impl WebGLRenderingContext {
pixels: TexPixels, pixels: TexPixels,
) { ) {
// We have already validated level // We have already validated level
let image_info = texture.image_info_for_target(&target, level); let image_info = match texture.image_info_for_target(&target, level) {
Some(info) => info,
None => return self.webgl_error(InvalidOperation),
};
// GL_INVALID_VALUE is generated if: // GL_INVALID_VALUE is generated if:
// - xoffset or yoffset is less than 0 // - xoffset or yoffset is less than 0
@ -761,9 +763,7 @@ impl WebGLRenderingContext {
} }
// NB: format and internal_format must match. // NB: format and internal_format must match.
if format != image_info.internal_format().unwrap() || if format != image_info.internal_format() || data_type != image_info.data_type().unwrap() {
data_type != image_info.data_type().unwrap()
{
return self.webgl_error(InvalidOperation); return self.webgl_error(InvalidOperation);
} }
@ -1921,9 +1921,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => { Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => {
TexFormat::from_gl_constant(rb.internal_format()) TexFormat::from_gl_constant(rb.internal_format())
}, },
Some(WebGLFramebufferAttachmentRoot::Texture(texture)) => { Some(WebGLFramebufferAttachmentRoot::Texture(texture)) => texture
texture.image_info_for_target(&target, 0).internal_format() .image_info_for_target(&target, 0)
}, .map(|info| info.internal_format()),
None => None, None => None,
}, },
None => { None => {
@ -2022,7 +2022,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Err(_) => return, Err(_) => return,
}; };
let image_info = texture.image_info_for_target(&target, level); let image_info = match texture.image_info_for_target(&target, level) {
Some(info) => info,
None => return self.webgl_error(InvalidOperation),
};
// GL_INVALID_VALUE is generated if: // GL_INVALID_VALUE is generated if:
// - xoffset or yoffset is less than 0 // - xoffset or yoffset is less than 0

View file

@ -40,7 +40,7 @@ pub struct WebGLTexture {
is_deleted: Cell<bool>, is_deleted: Cell<bool>,
/// Stores information about mipmap levels and cubemap faces. /// Stores information about mipmap levels and cubemap faces.
#[ignore_malloc_size_of = "Arrays are cumbersome"] #[ignore_malloc_size_of = "Arrays are cumbersome"]
image_info_array: DomRefCell<[ImageInfo; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>, image_info_array: DomRefCell<[Option<ImageInfo>; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>,
/// Face count can only be 1 or 6 /// Face count can only be 1 or 6
face_count: Cell<u8>, face_count: Cell<u8>,
base_mipmap_level: u32, base_mipmap_level: u32,
@ -64,7 +64,7 @@ impl WebGLTexture {
base_mipmap_level: 0, base_mipmap_level: 0,
min_filter: Cell::new(constants::NEAREST_MIPMAP_LINEAR), min_filter: Cell::new(constants::NEAREST_MIPMAP_LINEAR),
mag_filter: Cell::new(constants::LINEAR), mag_filter: Cell::new(constants::LINEAR),
image_info_array: DomRefCell::new([ImageInfo::new(); MAX_LEVEL_COUNT * MAX_FACE_COUNT]), image_info_array: DomRefCell::new([None; MAX_LEVEL_COUNT * MAX_FACE_COUNT]),
attached_to_dom: Cell::new(false), attached_to_dom: Cell::new(false),
attached_framebuffer: Default::default(), attached_framebuffer: Default::default(),
} }
@ -135,8 +135,7 @@ impl WebGLTexture {
width: width, width: width,
height: height, height: height,
depth: depth, depth: depth,
internal_format: Some(internal_format), internal_format: internal_format,
is_initialized: true,
data_type: data_type, data_type: data_type,
}; };
@ -159,10 +158,7 @@ impl WebGLTexture {
}, },
}; };
let base_image_info = self.base_image_info(); let base_image_info = self.base_image_info().ok_or(WebGLError::InvalidOperation)?;
if !base_image_info.is_initialized() {
return Err(WebGLError::InvalidOperation);
}
let is_cubic = target == constants::TEXTURE_CUBE_MAP; let is_cubic = target == constants::TEXTURE_CUBE_MAP;
if is_cubic && !self.is_cube_complete() { if is_cubic && !self.is_cube_complete() {
@ -308,10 +304,9 @@ impl WebGLTexture {
} }
pub fn populate_mip_chain(&self, first_level: u32, last_level: u32) -> WebGLResult<()> { pub fn populate_mip_chain(&self, first_level: u32, last_level: u32) -> WebGLResult<()> {
let base_image_info = self.image_info_at_face(0, first_level); let base_image_info = self
if !base_image_info.is_initialized() { .image_info_at_face(0, first_level)
return Err(WebGLError::InvalidOperation); .ok_or(WebGLError::InvalidOperation)?;
}
let mut ref_width = base_image_info.width; let mut ref_width = base_image_info.width;
let mut ref_height = base_image_info.height; let mut ref_height = base_image_info.height;
@ -333,7 +328,6 @@ impl WebGLTexture {
height: ref_height, height: ref_height,
depth: 0, depth: 0,
internal_format: base_image_info.internal_format, internal_format: base_image_info.internal_format,
is_initialized: base_image_info.is_initialized(),
data_type: base_image_info.data_type, data_type: base_image_info.data_type,
}; };
@ -345,19 +339,19 @@ impl WebGLTexture {
fn is_cube_complete(&self) -> bool { fn is_cube_complete(&self) -> bool {
debug_assert_eq!(self.face_count.get(), 6); debug_assert_eq!(self.face_count.get(), 6);
let image_info = self.base_image_info(); let image_info = match self.base_image_info() {
if !image_info.is_defined() { Some(info) => info,
return false; None => return false,
} };
let ref_width = image_info.width; let ref_width = image_info.width;
let ref_format = image_info.internal_format; let ref_format = image_info.internal_format;
for face in 0..self.face_count.get() { for face in 0..self.face_count.get() {
let current_image_info = self.image_info_at_face(face, self.base_mipmap_level); let current_image_info = match self.image_info_at_face(face, self.base_mipmap_level) {
if !current_image_info.is_defined() { Some(info) => info,
return false; None => return false,
} };
// Compares height with width to enforce square dimensions // Compares height with width to enforce square dimensions
if current_image_info.internal_format != ref_format || if current_image_info.internal_format != ref_format ||
@ -383,12 +377,12 @@ impl WebGLTexture {
} }
} }
pub fn image_info_for_target(&self, target: &TexImageTarget, level: u32) -> ImageInfo { pub fn image_info_for_target(&self, target: &TexImageTarget, level: u32) -> Option<ImageInfo> {
let face_index = self.face_index_for_target(&target); let face_index = self.face_index_for_target(&target);
self.image_info_at_face(face_index, level) self.image_info_at_face(face_index, level)
} }
pub fn image_info_at_face(&self, face: u8, level: u32) -> ImageInfo { pub fn image_info_at_face(&self, face: u8, level: u32) -> Option<ImageInfo> {
let pos = (level * self.face_count.get() as u32) + face as u32; let pos = (level * self.face_count.get() as u32) + face as u32;
self.image_info_array.borrow()[pos as usize] self.image_info_array.borrow()[pos as usize]
} }
@ -402,10 +396,10 @@ impl WebGLTexture {
fn set_image_infos_at_level_and_face(&self, level: u32, face: u8, image_info: ImageInfo) { fn set_image_infos_at_level_and_face(&self, level: u32, face: u8, image_info: ImageInfo) {
debug_assert!(face < self.face_count.get()); debug_assert!(face < self.face_count.get());
let pos = (level * self.face_count.get() as u32) + face as u32; let pos = (level * self.face_count.get() as u32) + face as u32;
self.image_info_array.borrow_mut()[pos as usize] = image_info; self.image_info_array.borrow_mut()[pos as usize] = Some(image_info);
} }
fn base_image_info(&self) -> ImageInfo { fn base_image_info(&self) -> Option<ImageInfo> {
assert!((self.base_mipmap_level as usize) < MAX_LEVEL_COUNT); assert!((self.base_mipmap_level as usize) < MAX_LEVEL_COUNT);
self.image_info_at_face(0, self.base_mipmap_level) self.image_info_at_face(0, self.base_mipmap_level)
@ -435,23 +429,11 @@ pub struct ImageInfo {
width: u32, width: u32,
height: u32, height: u32,
depth: u32, depth: u32,
internal_format: Option<TexFormat>, internal_format: TexFormat,
is_initialized: bool,
data_type: Option<TexDataType>, data_type: Option<TexDataType>,
} }
impl ImageInfo { impl ImageInfo {
fn new() -> ImageInfo {
ImageInfo {
width: 0,
height: 0,
depth: 0,
internal_format: None,
is_initialized: false,
data_type: None,
}
}
pub fn width(&self) -> u32 { pub fn width(&self) -> u32 {
self.width self.width
} }
@ -460,7 +442,7 @@ impl ImageInfo {
self.height self.height
} }
pub fn internal_format(&self) -> Option<TexFormat> { pub fn internal_format(&self) -> TexFormat {
self.internal_format self.internal_format
} }
@ -474,14 +456,6 @@ impl ImageInfo {
self.depth.is_power_of_two() self.depth.is_power_of_two()
} }
pub fn is_initialized(&self) -> bool {
self.is_initialized
}
fn is_defined(&self) -> bool {
self.internal_format.is_some()
}
fn get_max_mimap_levels(&self) -> u32 { fn get_max_mimap_levels(&self) -> u32 {
let largest = cmp::max(cmp::max(self.width, self.height), self.depth); let largest = cmp::max(cmp::max(self.width, self.height), self.depth);
if largest == 0 { if largest == 0 {
@ -492,10 +466,7 @@ impl ImageInfo {
} }
fn is_compressed_format(&self) -> bool { fn is_compressed_format(&self) -> bool {
match self.internal_format { self.internal_format.is_compressed()
Some(format) => format.is_compressed(),
None => false,
}
} }
} }