diff --git a/webrender/src/debug_render.rs b/webrender/src/debug_render.rs index e78da817ec..651bcf3654 100644 --- a/webrender/src/debug_render.rs +++ b/webrender/src/debug_render.rs @@ -116,12 +116,11 @@ impl DebugRenderer { let line_vao = device.create_vao(&DESC_COLOR); let tri_vao = device.create_vao(&DESC_COLOR); - let mut font_texture = device.create_texture(TextureTarget::Array); + let mut font_texture = device.create_texture(TextureTarget::Array, ImageFormat::R8); device.init_texture( &mut font_texture, debug_font_data::BMP_WIDTH, debug_font_data::BMP_HEIGHT, - ImageFormat::R8, TextureFilter::Linear, None, 1, diff --git a/webrender/src/device.rs b/webrender/src/device.rs index 963981994f..3046583f3a 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -20,10 +20,6 @@ use std::ptr; use std::rc::Rc; use std::thread; -// Apparently, in some cases calling `glTexImage3D` with -// similar parameters that the texture already has confuses -// Angle when running with optimizations. -const WORK_AROUND_TEX_IMAGE: bool = cfg!(windows); #[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)] #[cfg_attr(feature = "capture", derive(Deserialize, Serialize))] @@ -130,10 +126,8 @@ pub enum UploadMethod { #[derive(Clone, Copy, Debug, PartialEq)] pub enum ReadPixelsFormat { - R8, + Standard(ImageFormat), Rgba8, - Bgra8, - Rgba32F, } pub fn get_gl_format_bgra(gl: &gl::Gl) -> gl::GLuint { @@ -472,16 +466,6 @@ impl Texture { self.render_target.clone() } - pub fn get_bpp(&self) -> u32 { - match self.format { - ImageFormat::R8 => 1, - ImageFormat::BGRA8 => 4, - ImageFormat::RG8 => 2, - ImageFormat::RGBAF32 => 16, - ImageFormat::Invalid => unreachable!(), - } - } - pub fn has_depth(&self) -> bool { self.depth_rb.is_some() } @@ -941,14 +925,16 @@ impl Device { } } - pub fn create_texture(&mut self, target: TextureTarget) -> Texture { + pub fn create_texture( + &mut self, target: TextureTarget, format: ImageFormat, + ) -> Texture { Texture { id: self.gl.gen_textures(1)[0], target: target.to_gl_target(), width: 0, height: 0, layer_count: 0, - format: ImageFormat::Invalid, + format, filter: TextureFilter::Nearest, render_target: None, fbo_ids: vec![], @@ -994,7 +980,7 @@ impl Device { self.bind_texture(DEFAULT_TEXTURE, texture); self.set_texture_parameters(texture.target, texture.filter); - self.update_target_storage(texture, &rt_info, true, false, None); + self.update_target_storage(texture, &rt_info, true, None); let rect = DeviceIntRect::new(DeviceIntPoint::zero(), old_size.to_i32()); for (read_fbo, &draw_fbo) in old_fbos.into_iter().zip(&texture.fbo_ids) { @@ -1012,19 +998,15 @@ impl Device { texture: &mut Texture, width: u32, height: u32, - format: ImageFormat, filter: TextureFilter, render_target: Option, layer_count: i32, - pixels: Option<&[u8]>, ) { debug_assert!(self.inside_frame); let is_resized = texture.width != width || texture.height != height; - let is_format_changed = texture.format != format; - texture.format = format; texture.width = width; texture.height = height; texture.filter = filter; @@ -1036,7 +1018,7 @@ impl Device { match render_target { Some(info) => { - self.update_target_storage(texture, &info, is_resized, is_format_changed, pixels); + self.update_target_storage(texture, &info, is_resized, pixels); } None => { self.update_texture_storage(texture, pixels); @@ -1050,32 +1032,17 @@ impl Device { texture: &mut Texture, rt_info: &RenderTargetInfo, is_resized: bool, - is_format_changed: bool, pixels: Option<&[u8]>, ) { - assert!(texture.layer_count > 0); + assert!(texture.layer_count > 0 || texture.width + texture.height == 0); let needed_layer_count = texture.layer_count - texture.fbo_ids.len() as i32; - let allocate_color = needed_layer_count != 0 || - is_resized || is_format_changed || pixels.is_some(); + let allocate_color = needed_layer_count != 0 || is_resized || pixels.is_some(); if allocate_color { let desc = gl_describe_format(self.gl(), texture.format); match texture.target { gl::TEXTURE_2D_ARRAY => { - if WORK_AROUND_TEX_IMAGE { - // reset the contents before resizing - self.gl.tex_image_3d( - texture.target, - 0, - gl::RGBA32F as _, - 2, 2, 1, - 0, - gl::RGBA, - gl::FLOAT, - None, - ) - } self.gl.tex_image_3d( texture.target, 0, @@ -1269,7 +1236,7 @@ impl Device { pub fn free_texture_storage(&mut self, texture: &mut Texture) { debug_assert!(self.inside_frame); - if texture.format == ImageFormat::Invalid { + if texture.width + texture.height == 0 { return; } @@ -1291,7 +1258,6 @@ impl Device { self.gl.delete_framebuffers(&fbo_ids[..]); } - texture.format = ImageFormat::Invalid; texture.width = 0; texture.height = 0; texture.layer_count = 0; @@ -1552,13 +1518,19 @@ impl Device { format: ReadPixelsFormat, output: &mut [u8], ) { - let (gl_format, gl_type, pixel_size) = match format { - ReadPixelsFormat::R8 => (gl::RED, gl::UNSIGNED_BYTE, 1), - ReadPixelsFormat::Rgba8 => (gl::RGBA, gl::UNSIGNED_BYTE, 4), - ReadPixelsFormat::Bgra8 => (get_gl_format_bgra(self.gl()), gl::UNSIGNED_BYTE, 4), - ReadPixelsFormat::Rgba32F => (gl::RGBA, gl::FLOAT, 16), + let (bytes_per_pixel, desc) = match format { + ReadPixelsFormat::Standard(imf) => { + (imf.bytes_per_pixel(), gl_describe_format(self.gl(), imf)) + } + ReadPixelsFormat::Rgba8 => { + (4, FormatDesc { + external: gl::RGBA, + internal: gl::RGBA8 as _, + pixel_type: gl::UNSIGNED_BYTE, + }) + } }; - let size_in_bytes = (pixel_size * rect.size.width * rect.size.height) as usize; + let size_in_bytes = (bytes_per_pixel * rect.size.width * rect.size.height) as usize; assert_eq!(output.len(), size_in_bytes); self.gl.flush(); @@ -1567,8 +1539,8 @@ impl Device { rect.origin.y as _, rect.size.width as _, rect.size.height as _, - gl_format, - gl_type, + desc.external, + desc.pixel_type, output, ); } @@ -2066,7 +2038,6 @@ fn gl_describe_format(gl: &gl::Gl, format: ImageFormat) -> FormatDesc { external: gl::RG, pixel_type: gl::UNSIGNED_BYTE, }, - ImageFormat::Invalid => unreachable!(), } } @@ -2180,7 +2151,6 @@ impl<'a> UploadTarget<'a> { ImageFormat::BGRA8 => (get_gl_format_bgra(self.gl), 4, gl::UNSIGNED_BYTE), ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE), ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT), - ImageFormat::Invalid => unreachable!(), }; let row_length = match chunk.stride { diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 70d2f2e368..946b5b18ef 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -607,12 +607,12 @@ struct SourceTextureResolver { impl SourceTextureResolver { fn new(device: &mut Device) -> SourceTextureResolver { - let mut dummy_cache_texture = device.create_texture(TextureTarget::Array); + let mut dummy_cache_texture = device + .create_texture(TextureTarget::Array, ImageFormat::BGRA8); device.init_texture( &mut dummy_cache_texture, 1, 1, - ImageFormat::BGRA8, TextureFilter::Linear, None, 1, @@ -821,7 +821,7 @@ struct CacheTexture { impl CacheTexture { fn new(device: &mut Device, use_scatter: bool) -> Result { - let texture = device.create_texture(TextureTarget::Default); + let texture = device.create_texture(TextureTarget::Default, ImageFormat::RGBAF32); let bus = if use_scatter { let program = device @@ -894,7 +894,6 @@ impl CacheTexture { &mut self.texture, new_size.width, new_size.height, - ImageFormat::RGBAF32, TextureFilter::Nearest, None, 1, @@ -929,7 +928,6 @@ impl CacheTexture { &mut self.texture, new_size.width, new_size.height, - ImageFormat::RGBAF32, TextureFilter::Nearest, Some(RenderTargetInfo { has_depth: false, @@ -1074,7 +1072,7 @@ struct VertexDataTexture { impl VertexDataTexture { fn new(device: &mut Device) -> VertexDataTexture { - let texture = device.create_texture(TextureTarget::Default); + let texture = device.create_texture(TextureTarget::Default, ImageFormat::RGBAF32); let pbo = device.create_pbo(); VertexDataTexture { texture, pbo } @@ -1112,7 +1110,6 @@ impl VertexDataTexture { &mut self.texture, width, new_height, - ImageFormat::RGBAF32, TextureFilter::Nearest, None, 1, @@ -2109,12 +2106,12 @@ impl Renderer { 21, ]; - let mut texture = device.create_texture(TextureTarget::Default); + let mut texture = device + .create_texture(TextureTarget::Default, ImageFormat::R8); device.init_texture( &mut texture, 8, 8, - ImageFormat::R8, TextureFilter::Nearest, None, 1, @@ -2987,11 +2984,12 @@ impl Renderer { let CacheTextureId(cache_texture_index) = update.id; if self.texture_resolver.cache_texture_map.len() == cache_texture_index { // Create a new native texture, as requested by the texture cache. - let texture = self.device.create_texture(TextureTarget::Array); + let texture = self.device.create_texture(TextureTarget::Array, format); self.texture_resolver.cache_texture_map.push(texture); } let texture = &mut self.texture_resolver.cache_texture_map[cache_texture_index]; + assert_eq!(texture.get_format(), format); // Ensure no PBO is bound when creating the texture storage, // or GL will attempt to read data from there. @@ -2999,7 +2997,6 @@ impl Renderer { texture, width, height, - format, filter, render_target, layer_count, @@ -3040,7 +3037,7 @@ impl Renderer { } ExternalImageSource::Invalid => { // Create a local buffer to fill the pbo. - let bpp = texture.get_bpp(); + let bpp = texture.get_format().bytes_per_pixel(); let width = stride.unwrap_or(rect.size.width * bpp); let total_size = width * rect.size.height; // WR haven't support RGBAF32 format in texture_cache, so @@ -4132,9 +4129,12 @@ impl Renderer { list.check_ready(); return } - match self.texture_resolver.render_target_pool.pop() { - Some(texture) => texture, - None => self.device.create_texture(TextureTarget::Array), + let index = self.texture_resolver.render_target_pool + .iter() + .position(|texture| texture.get_format() == list.format); + match index { + Some(pos) => self.texture_resolver.render_target_pool.swap_remove(pos), + None => self.device.create_texture(TextureTarget::Array, list.format), } }; @@ -4142,7 +4142,6 @@ impl Renderer { &mut texture, list.max_size.width, list.max_size.height, - list.format, TextureFilter::Linear, Some(RenderTargetInfo { has_depth: list.needs_depth(), @@ -4549,7 +4548,7 @@ impl Renderer { self.device.bind_read_target(Some((&self.gpu_cache_texture.texture, 0))); self.device.read_pixels_into( DeviceUintRect::new(DeviceUintPoint::zero(), size), - ReadPixelsFormat::Rgba32F, + ReadPixelsFormat::Standard(ImageFormat::RGBAF32), &mut texels, ); self.device.bind_read_target(None); @@ -4827,12 +4826,8 @@ impl Renderer { let short_path = format!("textures/{}.raw", name); - let (read_format, bytes_per_pixel) = match texture.get_format() { - ImageFormat::R8 => (ReadPixelsFormat::R8, 1u32), - ImageFormat::BGRA8 => (ReadPixelsFormat::Bgra8, 4u32), - ImageFormat::RGBAF32 => (ReadPixelsFormat::Rgba32F, 16u32), - _ => unimplemented!() - }; + let bytes_per_pixel = texture.get_format().bytes_per_pixel(); + let read_format = ReadPixelsFormat::Standard(texture.get_format()); let rect = DeviceUintRect::new( DeviceUintPoint::zero(), texture.get_dimensions(), @@ -4864,6 +4859,7 @@ impl Renderer { use std::io::Read; let mut texels = Vec::new(); + assert_eq!(plain.format, texture.get_format()); File::open(root.join(&plain.data)) .unwrap() .read_to_end(&mut texels) @@ -4871,7 +4867,7 @@ impl Renderer { device.init_texture( texture, plain.size.0, plain.size.1, - plain.format, plain.filter, plain.render_target, + plain.filter, plain.render_target, plain.size.2, Some(texels.as_slice()), ); @@ -4962,7 +4958,7 @@ impl Renderer { } for texture in renderer.textures { info!("\t{}", texture.data); - let mut t = self.device.create_texture(TextureTarget::Array); + let mut t = self.device.create_texture(TextureTarget::Array, texture.format); Self::load_texture(&mut t, &texture, &root, &mut self.device); self.texture_resolver.cache_texture_map.push(t); } @@ -4989,7 +4985,10 @@ impl Renderer { }; for ExternalCaptureImage { short_path, external, descriptor } in renderer.external_images { - let target = get_external_image_target(external.image_type).unwrap(); + let target = match get_external_image_target(external.image_type) { + Some(target) => target, + None => continue, + }; //TODO: provide a way to query both the layer count and the filter from external images let (layer_count, filter) = (1, TextureFilter::Linear); let plain = PlainTexture { @@ -5000,7 +4999,7 @@ impl Renderer { render_target: None, }; - let mut t = self.device.create_texture(target); + let mut t = self.device.create_texture(target, plain.format); let data = Self::load_texture(&mut t, &plain, &root, &mut self.device); let key = (external.id, external.channel_index); self.capture.owned_external_images.insert(key, t.into_external()); diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index 9a98d9f8d0..5c6d35b567 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -9,7 +9,7 @@ use device::TextureFilter; use frame::FrameId; use freelist::{FreeList, FreeListHandle, UpsertResult, WeakFreeListHandle}; use gpu_cache::{GpuCache, GpuCacheHandle}; -use internal_types::{CacheTextureId, TextureUpdateList, TextureUpdateSource}; +use internal_types::{CacheTextureId, FastHashMap, TextureUpdateList, TextureUpdateSource}; use internal_types::{RenderTargetInfo, SourceTexture, TextureUpdate, TextureUpdateOp}; use profiler::{ResourceProfileCounter, TextureCacheProfileCounters}; use resource_cache::CacheItem; @@ -31,7 +31,7 @@ const TEXTURE_REGION_DIMENSIONS: u32 = 512; // to real API-specific texture IDs in the renderer. #[cfg_attr(feature = "capture", derive(Deserialize, Serialize))] struct CacheTextureIdList { - free_list: Vec, + free_lists: FastHashMap>, next_id: usize, } @@ -39,25 +39,26 @@ impl CacheTextureIdList { fn new() -> Self { CacheTextureIdList { next_id: 0, - free_list: Vec::new(), + free_lists: FastHashMap::default(), } } - fn allocate(&mut self) -> CacheTextureId { + fn allocate(&mut self, format: ImageFormat) -> CacheTextureId { // If nothing on the free list of texture IDs, // allocate a new one. - match self.free_list.pop() { - Some(id) => id, - None => { - let id = CacheTextureId(self.next_id); + self.free_lists.get_mut(&format) + .and_then(|fl| fl.pop()) + .unwrap_or_else(|| { self.next_id += 1; - id - } - } + CacheTextureId(self.next_id - 1) + }) } - fn free(&mut self, id: CacheTextureId) { - self.free_list.push(id); + fn free(&mut self, id: CacheTextureId, format: ImageFormat) { + self.free_lists + .entry(format) + .or_insert(Vec::new()) + .push(id); } } @@ -376,7 +377,6 @@ impl TextureCache { (ImageFormat::R8, TextureFilter::Linear) => &mut self.array_a8_linear, (ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear, (ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest, - (ImageFormat::Invalid, _) | (ImageFormat::RGBAF32, _) | (ImageFormat::RG8, _) | (ImageFormat::R8, TextureFilter::Nearest) => unreachable!(), @@ -554,7 +554,7 @@ impl TextureCache { id: entry.texture_id, op: TextureUpdateOp::Free, }); - self.cache_textures.free(entry.texture_id); + self.cache_textures.free(entry.texture_id, entry.format); None } EntryKind::Cache { @@ -586,7 +586,6 @@ impl TextureCache { (ImageFormat::R8, TextureFilter::Linear) => &mut self.array_a8_linear, (ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear, (ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest, - (ImageFormat::Invalid, _) | (ImageFormat::RGBAF32, _) | (ImageFormat::R8, TextureFilter::Nearest) | (ImageFormat::RG8, _) => unreachable!(), @@ -594,7 +593,7 @@ impl TextureCache { // Lazy initialize this texture array if required. if texture_array.texture_id.is_none() { - let texture_id = self.cache_textures.allocate(); + let texture_id = self.cache_textures.allocate(descriptor.format); let update_op = TextureUpdate { id: texture_id, @@ -688,7 +687,7 @@ impl TextureCache { // will just have to be in a unique texture. This hurts batching but should // only occur on a small number of images (or pathological test cases!). if new_cache_entry.is_none() { - let texture_id = self.cache_textures.allocate(); + let texture_id = self.cache_textures.allocate(descriptor.format); // Create an update operation to allocate device storage // of the right size / format. diff --git a/webrender_api/src/image.rs b/webrender_api/src/image.rs index c3e184e5f0..b70e3a57b1 100644 --- a/webrender_api/src/image.rs +++ b/webrender_api/src/image.rs @@ -50,7 +50,6 @@ pub struct ExternalImageData { #[repr(u32)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub enum ImageFormat { - Invalid = 0, R8 = 1, BGRA8 = 3, RGBAF32 = 4, @@ -64,7 +63,6 @@ impl ImageFormat { ImageFormat::BGRA8 => 4, ImageFormat::RGBAF32 => 16, ImageFormat::RG8 => 2, - ImageFormat::Invalid => 0, } } } diff --git a/wrench/src/yaml_frame_reader.rs b/wrench/src/yaml_frame_reader.rs index 93443ad482..a3637b9f3e 100644 --- a/wrench/src/yaml_frame_reader.rs +++ b/wrench/src/yaml_frame_reader.rs @@ -170,7 +170,7 @@ fn is_image_opaque(format: ImageFormat, bytes: &[u8]) -> bool { } ImageFormat::RG8 => true, ImageFormat::R8 => false, - ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(), + ImageFormat::RGBAF32 => unreachable!(), } }