diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index 933d052561..60ba564308 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -22,7 +22,7 @@ use tiling; use renderer::BlendMode; use webrender_traits::{Epoch, ColorF, PipelineId, DeviceIntSize}; use webrender_traits::{ImageFormat, NativeFontHandle}; -use webrender_traits::{ExternalImageId, ScrollLayerId, WebGLCommand}; +use webrender_traits::{ExternalImageData, ExternalImageId, ScrollLayerId, WebGLCommand}; use webrender_traits::{ImageData}; use webrender_traits::{DeviceUintRect}; @@ -49,7 +49,7 @@ pub enum SourceTexture { Invalid, TextureCache(CacheTextureId), WebGL(u32), // Is actually a gl::GLuint - External(ExternalImageId), + External(ExternalImageData), } pub enum GLContextHandleWrapper { diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 380b56ee43..9a0281a475 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -864,8 +864,8 @@ impl PrimitiveStore { // Check if an external image that needs to be resolved // by the render thread. - match image_properties.external_id { - Some(external_id) => { + match image_properties.external_image { + Some(external_image) => { // This is an external texture - we will add it to // the deferred resolves list to be patched by // the render thread... @@ -874,7 +874,7 @@ impl PrimitiveStore { resource_address: image_uv_address, }); - (SourceTexture::External(external_id), None) + (SourceTexture::External(external_image), None) } None => { let cache_item = resource_cache.get_cached_image(image_key, image_rendering, tile_offset); diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 50903ee167..247307d657 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -48,7 +48,7 @@ use time::precise_time_ns; use thread_profiler::{register_thread_with_profiler, write_profile}; use util::TransformedRectKind; use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier, RenderDispatcher}; -use webrender_traits::{ExternalImageId, ImageData, ImageFormat, RenderApiSender}; +use webrender_traits::{ExternalImageId, ExternalImageType, ImageData, ImageFormat, RenderApiSender}; use webrender_traits::{DeviceIntRect, DevicePoint, DeviceIntPoint, DeviceIntSize, DeviceUintSize}; use webrender_traits::{ImageDescriptor, BlobImageRenderer}; use webrender_traits::channel; @@ -1038,10 +1038,10 @@ impl Renderer { fn resolve_source_texture(&mut self, texture_id: &SourceTexture) -> TextureId { match *texture_id { SourceTexture::Invalid => TextureId::invalid(), - SourceTexture::WebGL(id) => TextureId::new(id), - SourceTexture::External(ref key) => { + SourceTexture::WebGL(id) => TextureId::new(id, TextureTarget::Default), + SourceTexture::External(external_image) => { *self.external_images - .get(key) + .get(&external_image.id) .expect("BUG: External image should be resolved by now!") } SourceTexture::TextureCache(index) => { @@ -1192,24 +1192,31 @@ impl Renderer { mode, Some(raw.as_slice())); } - ImageData::ExternalBuffer(id) => { - let handler = self.external_image_handler - .as_mut() - .expect("Found external image, but no handler set!"); - - match handler.lock(id).source { - ExternalImageSource::RawData(raw) => { - self.device.init_texture(texture_id, - width, - height, - format, - filter, - mode, - Some(raw)); + ImageData::External(ext_image) => { + match ext_image.image_type { + ExternalImageType::ExternalBuffer => { + let handler = self.external_image_handler + .as_mut() + .expect("Found external image, but no handler set!"); + + match handler.lock(ext_image.id).source { + ExternalImageSource::RawData(raw) => { + self.device.init_texture(texture_id, + width, + height, + format, + filter, + mode, + Some(raw)); + } + _ => panic!("No external buffer found"), + }; + handler.unlock(ext_image.id); } - _ => panic!("No external buffer found"), - }; - handler.unlock(id); + _ => { + panic!("External texture handle should not use TextureUpdateOp::Create."); + } + } } _ => { panic!("No suitable image buffer for TextureUpdateOp::Create."); @@ -1641,16 +1648,16 @@ impl Renderer { for deferred_resolve in &frame.deferred_resolves { GpuMarker::fire(self.device.gl(), "deferred resolve"); let props = &deferred_resolve.image_properties; - let external_id = props.external_id - .expect("BUG: Deferred resolves must be external images!"); - let image = handler.lock(external_id); + let ext_image = props.external_image + .expect("BUG: Deferred resolves must be external images!"); + let image = handler.lock(ext_image.id); let texture_id = match image.source { ExternalImageSource::NativeTexture(texture_id) => TextureId::new(texture_id), _ => panic!("No native texture found."), }; - self.external_images.insert(external_id, texture_id); + self.external_images.insert(ext_image.id, texture_id); let resource_rect_index = deferred_resolve.resource_address.0 as usize; let resource_rect = &mut frame.gpu_resource_rects[resource_rect_index]; resource_rect.uv0 = DevicePoint::new(image.u0, image.v0); diff --git a/webrender/src/resource_cache.rs b/webrender/src/resource_cache.rs index 300bb6c685..156e714190 100644 --- a/webrender/src/resource_cache.rs +++ b/webrender/src/resource_cache.rs @@ -24,8 +24,9 @@ use thread_profiler::register_thread_with_profiler; use webrender_traits::{Epoch, FontKey, GlyphKey, ImageKey, ImageFormat, ImageRendering}; use webrender_traits::{FontRenderMode, ImageData, GlyphDimensions, WebGLContextId}; use webrender_traits::{DevicePoint, DeviceIntSize, DeviceUintRect, ImageDescriptor, ColorF}; -use webrender_traits::{ExternalImageId, GlyphOptions, GlyphInstance, TileOffset, TileSize}; +use webrender_traits::{GlyphOptions, GlyphInstance, TileOffset, TileSize}; use webrender_traits::{BlobImageRenderer, BlobImageDescriptor, BlobImageError}; +use webrender_traits::{ExternalImageData, ExternalImageType}; use threadpool::ThreadPool; use euclid::Point2D; @@ -94,7 +95,7 @@ impl RenderedGlyphKey { pub struct ImageProperties { pub descriptor: ImageDescriptor, - pub external_id: Option, + pub external_image: Option, pub tiling: Option, } @@ -299,12 +300,19 @@ impl ResourceCache { dirty_rect: Option) { let (next_epoch, prev_dirty_rect) = match self.image_templates.get(&image_key) { Some(image) => { - // This image should not be an external image. + // This image should not be an external handle image. match image.data { - ImageData::ExternalHandle(id) => { - panic!("Update an external image with buffer, id={} image_key={:?}", id.0, image_key); - }, - _ => {}, + ImageData::External(ext_image) => { + match ext_image.image_type { + ExternalImageType::Texture2DHandle | + ExternalImageType::TextureRectHandle => { + panic!("Update an external handle with buffer, id={:?} image_key={:?}", + ext_image.id, image_key); + } + _ => {} + } + } + _ => {} } let Epoch(current_epoch) = image.epoch; @@ -336,10 +344,16 @@ impl ResourceCache { // If the key is associated to an external image, pass the external id to renderer for cleanup. if let Some(image) = value { match image.data { - ImageData::ExternalHandle(id) => { - self.pending_external_image_update_list.push(id); - }, - _ => {}, + ImageData::External(ext_image) => { + match ext_image.image_type { + ExternalImageType::Texture2DHandle | + ExternalImageType::TextureRectHandle => { + self.pending_external_image_update_list.push(ext_image.id); + } + _ => {} + } + } + _ => {} } return; @@ -523,15 +537,24 @@ impl ResourceCache { pub fn get_image_properties(&self, image_key: ImageKey) -> ImageProperties { let image_template = &self.image_templates[&image_key]; - let external_id = match image_template.data { - ImageData::ExternalHandle(id) => Some(id), - // raw and externalBuffer are all use resource_cache. - ImageData::Raw(..) | ImageData::ExternalBuffer(..) | ImageData::Blob(..) => None, + let external_image = match image_template.data { + ImageData::External(ext_image) => { + match ext_image.image_type { + ExternalImageType::Texture2DHandle | + ExternalImageType::TextureRectHandle => { + Some(ext_image) + }, + // external buffer uses resource_cache. + ExternalImageType::ExternalBuffer => None, + } + }, + // raw and blob image are all using resource_cache. + ImageData::Raw(..) | ImageData::Blob(..) => None, }; ImageProperties { descriptor: image_template.descriptor, - external_id: external_id, + external_image: external_image, tiling: image_template.tiling, } } @@ -651,6 +674,87 @@ impl ResourceCache { } } } + fn update_texture_cache(cached_images: &mut ResourceClassCache, + texture_cache: &mut TextureCache, + current_frame_id: FrameId, + request: &ImageRequest, + image_template: &mut ImageResource, + image_data: ImageData, + texture_cache_profile: &mut TextureCacheProfileCounters) { + let descriptor = if let Some(tile) = request.tile { + let tile_size = image_template.tiling.unwrap() as u32; + let image_descriptor = &image_template.descriptor; + let stride = image_descriptor.compute_stride(); + let bpp = image_descriptor.format.bytes_per_pixel().unwrap(); + + // Storage for the tiles on the right and bottom edges is shrunk to + // fit the image data (See decompose_tiled_image in frame.rs). + let actual_width = if (tile.x as u32) < image_descriptor.width / tile_size { + tile_size + } else { + image_descriptor.width % tile_size + }; + + let actual_height = if (tile.y as u32) < image_descriptor.height / tile_size { + tile_size + } else { + image_descriptor.height % tile_size + }; + + let offset = image_descriptor.offset + tile.y as u32 * tile_size * stride + + tile.x as u32 * tile_size * bpp; + + ImageDescriptor { + width: actual_width, + height: actual_height, + stride: Some(stride), + offset: offset, + format: image_descriptor.format, + is_opaque: image_descriptor.is_opaque, + } + } else { + image_template.descriptor.clone() + }; + + match cached_images.entry(request.clone(), current_frame_id) { + Occupied(entry) => { + let image_id = entry.get().texture_cache_id; + + if entry.get().epoch != image_template.epoch { + texture_cache.update(image_id, + descriptor, + image_data, + image_template.dirty_rect); + + // Update the cached epoch + *entry.into_mut() = CachedImageInfo { + texture_cache_id: image_id, + epoch: image_template.epoch, + }; + image_template.dirty_rect = None; + } + } + Vacant(entry) => { + let image_id = texture_cache.new_item_id(); + + let filter = match request.rendering { + ImageRendering::Pixelated => TextureFilter::Nearest, + ImageRendering::Auto | ImageRendering::CrispEdges => TextureFilter::Linear, + }; + + texture_cache.insert(image_id, + descriptor, + filter, + image_data, + texture_cache_profile); + + entry.insert(CachedImageInfo { + texture_cache_id: image_id, + epoch: image_template.epoch, + }); + } + } + } fn finalize_image_request(&mut self, request: ImageRequest, @@ -662,84 +766,32 @@ impl ResourceCache { }); match image_template.data { - ImageData::ExternalHandle(..) => { - // external handle doesn't need to update the texture_cache. - } - ImageData::Raw(..) | ImageData::ExternalBuffer(..) | ImageData::Blob(..) => { - let descriptor = if let Some(tile) = request.tile { - let tile_size = image_template.tiling.unwrap() as u32; - let image_descriptor = &image_template.descriptor; - let stride = image_descriptor.compute_stride(); - let bpp = image_descriptor.format.bytes_per_pixel().unwrap(); - - // Storage for the tiles on the right and bottom edges is shrunk to - // fit the image data (See decompose_tiled_image in frame.rs). - let actual_width = if (tile.x as u32) < image_descriptor.width / tile_size { - tile_size - } else { - image_descriptor.width % tile_size - }; - - let actual_height = if (tile.y as u32) < image_descriptor.height / tile_size { - tile_size - } else { - image_descriptor.height % tile_size - }; - - let offset = image_descriptor.offset + tile.y as u32 * tile_size * stride - + tile.x as u32 * tile_size * bpp; - - ImageDescriptor { - width: actual_width, - height: actual_height, - stride: Some(stride), - offset: offset, - format: image_descriptor.format, - is_opaque: image_descriptor.is_opaque, - } - } else { - image_template.descriptor.clone() - }; - - match self.cached_images.entry(request.clone(), self.current_frame_id) { - Occupied(entry) => { - let image_id = entry.get().texture_cache_id; - - if entry.get().epoch != image_template.epoch { - self.texture_cache.update(image_id, - descriptor, - image_data, - image_template.dirty_rect); - - // Update the cached epoch - *entry.into_mut() = CachedImageInfo { - texture_cache_id: image_id, - epoch: image_template.epoch, - }; - image_template.dirty_rect = None; - } + ImageData::External(ext_image) => { + match ext_image.image_type { + ExternalImageType::Texture2DHandle | + ExternalImageType::TextureRectHandle => { + // external handle doesn't need to update the texture_cache. } - Vacant(entry) => { - let image_id = self.texture_cache.new_item_id(); - - let filter = match request.rendering { - ImageRendering::Pixelated => TextureFilter::Nearest, - ImageRendering::Auto | ImageRendering::CrispEdges => TextureFilter::Linear, - }; - - self.texture_cache.insert(image_id, - descriptor, - filter, - image_data, - texture_cache_profile); - - entry.insert(CachedImageInfo { - texture_cache_id: image_id, - epoch: image_template.epoch, - }); + ExternalImageType::ExternalBuffer => { + ResourceCache::update_texture_cache(&mut self.cached_images, + &mut self.texture_cache, + self.current_frame_id, + &request, + image_template, + image_data, + texture_cache_profile); } } } + ImageData::Raw(..) | ImageData::Blob(..) => { + ResourceCache::update_texture_cache(&mut self.cached_images, + &mut self.texture_cache, + self.current_frame_id, + &request, + image_template, + image_data, + texture_cache_profile); + } } } diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index 9a60ae2ac8..d61a4821a3 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -16,7 +16,7 @@ use std::mem; use std::slice::Iter; use time; use util; -use webrender_traits::{ImageData, ImageFormat, DevicePixel, DeviceIntPoint}; +use webrender_traits::{ExternalImageType, ImageData, ImageFormat, DevicePixel, DeviceIntPoint}; use webrender_traits::{DeviceUintRect, DeviceUintSize, DeviceUintPoint}; use webrender_traits::ImageDescriptor; @@ -715,7 +715,7 @@ impl TextureCache { debug_assert_eq!(existing_item.allocated_rect.size.height, descriptor.height); let op = match data { - ImageData::ExternalHandle(..) | ImageData::ExternalBuffer(..)=> { + ImageData::External(..) => { panic!("Doesn't support Update() for external image."); } ImageData::Blob(..) => { @@ -781,8 +781,25 @@ impl TextureCache { match result.kind { AllocationKind::TexturePage => { match data { - ImageData::ExternalHandle(..) => { - panic!("External handle should not go through texture_cache."); + ImageData::External(ext_image) => { + match ext_image.image_type { + ExternalImageType::Texture2DHandle | + ExternalImageType::TextureRectHandle => { + panic!("External texture handle should not go through texture_cache."); + } + ExternalImageType::ExternalBuffer => { + let update_op = TextureUpdate { + id: result.item.texture_id, + op: TextureUpdateOp::UpdateForExternalBuffer { + rect: result.item.allocated_rect, + id: ext_image.id, + stride: stride, + }, + }; + + self.pending_updates.push(update_op); + } + } } ImageData::Blob(..) => { panic!("The vector image should have been rasterized."); @@ -801,26 +818,34 @@ impl TextureCache { }, }; - self.pending_updates.push(update_op); - } - ImageData::ExternalBuffer(id) => { - let update_op = TextureUpdate { - id: result.item.texture_id, - op: TextureUpdateOp::UpdateForExternalBuffer { - rect: result.item.allocated_rect, - id: id, - stride: stride, - }, - }; - self.pending_updates.push(update_op); } } } AllocationKind::Standalone => { match data { - ImageData::ExternalHandle(..) => { - panic!("External handle should not go through texture_cache."); + ImageData::External(ext_image) => { + match ext_image.image_type { + ExternalImageType::Texture2DHandle | + ExternalImageType::TextureRectHandle => { + panic!("External texture handle should not go through texture_cache."); + } + ExternalImageType::ExternalBuffer => { + let update_op = TextureUpdate { + id: result.item.texture_id, + op: TextureUpdateOp::Create { + width: width, + height: height, + format: format, + filter: filter, + mode: RenderTargetMode::None, + data: Some(data), + }, + }; + + self.pending_updates.push(update_op); + } + } } _ => { let update_op = TextureUpdate { diff --git a/webrender_traits/src/image.rs b/webrender_traits/src/image.rs index 2cf49d970c..63e24c29f0 100644 --- a/webrender_traits/src/image.rs +++ b/webrender_traits/src/image.rs @@ -69,12 +69,24 @@ impl ImageDescriptor { } } +#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub enum ExternalImageType { + Texture2DHandle, // gl TEXTURE_2D handle + TextureRectHandle, // gl TEXTURE_RECT handle + ExternalBuffer, +} + +#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct ExternalImageData { + pub id: ExternalImageId, + pub image_type: ExternalImageType, +} + #[derive(Clone, Serialize, Deserialize)] pub enum ImageData { Raw(Arc>), Blob(Arc), - ExternalHandle(ExternalImageId), - ExternalBuffer(ExternalImageId), + External(ExternalImageData), } impl ImageData {