From 86b00a743f3295a9e69631c4c31579bf0a86939a Mon Sep 17 00:00:00 2001 From: JerryShih Date: Tue, 21 Mar 2017 10:33:29 +0800 Subject: [PATCH 1/4] Use struct ExternalImageData to present the different external texture handle type. --- webrender/src/internal_types.rs | 4 +- webrender/src/prim_store.rs | 6 +- webrender/src/renderer.rs | 57 +++++---- webrender/src/resource_cache.rs | 202 ++++++++++++++++++-------------- webrender/src/texture_cache.rs | 61 +++++++--- webrender_traits/src/image.rs | 16 ++- 6 files changed, 211 insertions(+), 135 deletions(-) diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index 0ab245c9e4..9c0d32928c 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -17,7 +17,7 @@ use tiling; use renderer::BlendMode; use webrender_traits::{Epoch, ColorF, PipelineId}; use webrender_traits::{ImageFormat, NativeFontHandle}; -use webrender_traits::{ExternalImageId, ScrollLayerId}; +use webrender_traits::{ExternalImageData, ExternalImageId, ScrollLayerId}; use webrender_traits::{ImageData}; use webrender_traits::{DeviceUintRect}; @@ -43,7 +43,7 @@ pub struct CacheTextureId(pub usize); pub enum SourceTexture { Invalid, TextureCache(CacheTextureId), - External(ExternalImageId), + External(ExternalImageData), #[cfg_attr(not(feature = "webgl"), allow(dead_code))] /// This is actually a gl::GLuint, with the shared texture id between the /// main context and the WebGL context. diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 1041ad8a33..dbfa1c5682 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -868,8 +868,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... @@ -878,7 +878,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 b6378cb7c3..c48df7784b 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -49,7 +49,7 @@ use thread_profiler::{register_thread_with_profiler, write_profile}; use util::TransformedRectKind; use webgl_types::GLContextHandleWrapper; 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; @@ -1039,10 +1039,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) => { @@ -1193,24 +1193,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."); @@ -1665,16 +1672,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 e2b4481ed8..3b2dad3c60 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; @@ -96,7 +97,7 @@ impl RenderedGlyphKey { pub struct ImageProperties { pub descriptor: ImageDescriptor, - pub external_id: Option, + pub external_image: Option, pub tiling: Option, } @@ -260,8 +261,7 @@ impl ResourceCache { let limit = self.max_texture_size(); return match data { // Tiled external images are not implemented. - &ImageData::ExternalHandle(_) => false, - &ImageData::ExternalBuffer(_) => false, + &ImageData::External(_) => false, _ => { descriptor.width > limit || descriptor.height > limit } }; } @@ -309,7 +309,6 @@ impl ResourceCache { descriptor: ImageDescriptor, data: ImageData, dirty_rect: Option) { - let resource = if let Some(image) = self.image_templates.get(&image_key) { assert!(image.descriptor.width == descriptor.width); assert!(image.descriptor.height == descriptor.height); @@ -346,10 +345,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; @@ -534,15 +539,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, } } @@ -663,94 +677,112 @@ impl ResourceCache { } } - fn finalize_image_request(&mut self, - request: ImageRequest, - image_data: Option, - texture_cache_profile: &mut TextureCacheProfileCounters) { + fn update_texture_cache(&mut self, + request: &ImageRequest, + image_data: Option, + texture_cache_profile: &mut TextureCacheProfileCounters) { let image_template = self.image_templates.get_mut(&request.key).unwrap(); let image_data = image_data.unwrap_or_else(||{ image_template.data.clone() }); - match image_template.data { - ImageData::ExternalHandle(..) => { - // external handle doesn't need to update the texture_cache. + 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, } - 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 - }; + } else { + image_template.descriptor.clone() + }; - let actual_height = if (tile.y as u32) < image_descriptor.height / tile_size { - tile_size - } else { - image_descriptor.height % tile_size - }; + match self.cached_images.entry(request.clone(), self.current_frame_id) { + Occupied(entry) => { + let image_id = entry.get().texture_cache_id; - let offset = image_descriptor.offset + tile.y as u32 * tile_size * stride - + tile.x as u32 * tile_size * bpp; + if entry.get().epoch != image_template.epoch { + self.texture_cache.update(image_id, + descriptor, + image_data, + image_template.dirty_rect); - 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() - }; + // 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 = self.texture_cache.new_item_id(); - 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; - } - } - 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, + }; - 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); - self.texture_cache.insert(image_id, - descriptor, - filter, + entry.insert(CachedImageInfo { + texture_cache_id: image_id, + epoch: image_template.epoch, + }); + } + } + } + fn finalize_image_request(&mut self, + request: ImageRequest, + image_data: Option, + texture_cache_profile: &mut TextureCacheProfileCounters) { + match self.image_templates.get(&request.key).unwrap().data { + ImageData::External(ext_image) => { + match ext_image.image_type { + ExternalImageType::Texture2DHandle | + ExternalImageType::TextureRectHandle => { + // external handle doesn't need to update the texture_cache. + } + ExternalImageType::ExternalBuffer => { + self.update_texture_cache(&request, image_data, texture_cache_profile); - - entry.insert(CachedImageInfo { - texture_cache_id: image_id, - epoch: image_template.epoch, - }); } } } + ImageData::Raw(..) | ImageData::Blob(..) => { + self.update_texture_cache(&request, + image_data, + texture_cache_profile); + } } } diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index 33414a9aa5..ea7f847bb5 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(..) => { @@ -784,8 +784,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."); @@ -804,26 +821,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 486fe240df..05f74e2aa2 100644 --- a/webrender_traits/src/image.rs +++ b/webrender_traits/src/image.rs @@ -70,12 +70,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 { From 1305f38cbff082e07f9a015e2812237cfa4cda9f Mon Sep 17 00:00:00 2001 From: JerryShih Date: Tue, 21 Mar 2017 10:36:52 +0800 Subject: [PATCH 2/4] Add new TextureTarget::Rect texture target type for external image TextureRectHandle. --- webrender/src/device.rs | 22 ++++++++++++++-------- webrender/src/renderer.rs | 10 +++++++++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/webrender/src/device.rs b/webrender/src/device.rs index f34b31f119..fc9c1df50b 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -51,6 +51,17 @@ pub enum DepthFunction { pub enum TextureTarget { Default, Array, + Rect, +} + +impl TextureTarget { + pub fn to_gl_target(&self) -> gl::GLuint { + match *self { + TextureTarget::Default => gl::TEXTURE_2D, + TextureTarget::Array => gl::TEXTURE_2D_ARRAY, + TextureTarget::Rect => gl::TEXTURE_RECTANGLE, + } + } } #[derive(Copy, Clone, Debug, PartialEq)] @@ -304,10 +315,10 @@ impl TextureId { gl.bind_texture(self.target, self.name); } - pub fn new(name: gl::GLuint) -> TextureId { + pub fn new(name: gl::GLuint, texture_target: TextureTarget) -> TextureId { TextureId { name: name, - target: gl::TEXTURE_2D, + target: texture_target.to_gl_target(), } } @@ -1090,15 +1101,10 @@ impl Device { let id_list = self.gl.gen_textures(count); let mut texture_ids = Vec::new(); - let target = match target { - TextureTarget::Default => gl::TEXTURE_2D, - TextureTarget::Array => gl::TEXTURE_2D_ARRAY, - }; - for id in id_list { let texture_id = TextureId { name: id, - target: target, + target: target.to_gl_target(), }; let texture = Texture { diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index c48df7784b..8e49f029e7 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -1675,9 +1675,17 @@ impl Renderer { let ext_image = props.external_image .expect("BUG: Deferred resolves must be external images!"); let image = handler.lock(ext_image.id); + let texture_target = match ext_image.image_type { + ExternalImageType::Texture2DHandle => TextureTarget::Default, + ExternalImageType::TextureRectHandle => TextureTarget::Rect, + _ => { + panic!("{:?} is not a suitable image type in update_deferred_resolves().", + ext_image.image_type); + } + }; let texture_id = match image.source { - ExternalImageSource::NativeTexture(texture_id) => TextureId::new(texture_id), + ExternalImageSource::NativeTexture(texture_id) => TextureId::new(texture_id, texture_target), _ => panic!("No native texture found."), }; From dec3102d50d3fe339190748b3407338cebb56d8e Mon Sep 17 00:00:00 2001 From: JerryShih Date: Tue, 21 Mar 2017 11:34:40 +0800 Subject: [PATCH 3/4] Add a new TEXTURE_RECT_FEATURE feature in image shader for external image TextureRectHandle. --- webrender/res/ps_image.fs.glsl | 7 +++++-- webrender/res/ps_image.glsl | 5 ++++- webrender/res/ps_image.vs.glsl | 20 ++++++++++++++++---- webrender/res/shared.glsl | 6 ++++++ webrender/src/renderer.rs | 15 +++++++++++++++ webrender/src/tiling.rs | 25 +++++++++++++++++++++++-- 6 files changed, 69 insertions(+), 9 deletions(-) diff --git a/webrender/res/ps_image.fs.glsl b/webrender/res/ps_image.fs.glsl index 64619314c8..b1cb97b60f 100644 --- a/webrender/res/ps_image.fs.glsl +++ b/webrender/res/ps_image.fs.glsl @@ -24,12 +24,15 @@ void main(void) { // account the spacing in between tiles. We only paint if our fragment does // not fall into that spacing. vec2 position_in_tile = mod(relative_pos_in_rect, vStretchSize + vTileSpacing); - // We clamp the texture coordinates to the half-pixel offset from the borders - // in order to avoid sampling outside of the texture area. vec2 st = vTextureOffset + ((position_in_tile / vStretchSize) * vTextureSize); st = clamp(st, vStRect.xy, vStRect.zw); alpha = alpha * float(all(bvec2(step(position_in_tile, vStretchSize)))); +#ifdef WR_FEATURE_TEXTURE_RECT + // textureLod doesn't support sampler2DRect. Use texture() instead. + oFragColor = vec4(alpha) * texture(sColor0, st); +#else oFragColor = vec4(alpha) * textureLod(sColor0, st, 0.0); +#endif } diff --git a/webrender/res/ps_image.glsl b/webrender/res/ps_image.glsl index 18a01d863a..6152c160af 100644 --- a/webrender/res/ps_image.glsl +++ b/webrender/res/ps_image.glsl @@ -2,10 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use non-normalized +// texture coordinates. Otherwise, it uses normalized texture coordinates. Please +// check GL_TEXTURE_RECTANGLE. flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas. flat varying vec2 vTextureSize; // Size of the image in the texture atlas. flat varying vec2 vTileSpacing; // Amount of space between tiled instances of this image. -flat varying vec4 vStRect; // Rectangle of valid texture rect, in st-space. +flat varying vec4 vStRect; // Rectangle of valid texture rect. #ifdef WR_FEATURE_TRANSFORM varying vec3 vLocalPos; diff --git a/webrender/res/ps_image.vs.glsl b/webrender/res/ps_image.vs.glsl index ba6cdb6cba..530f80682a 100644 --- a/webrender/res/ps_image.vs.glsl +++ b/webrender/res/ps_image.vs.glsl @@ -27,16 +27,28 @@ void main(void) { write_clip(vi.screen_pos, prim.clip_area); + vTileSpacing = image.stretch_size_and_tile_spacing.zw; + vStretchSize = image.stretch_size_and_tile_spacing.xy; + + // If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use + // non-normalized texture coordinates. +#ifdef WR_FEATURE_TEXTURE_RECT + vec2 texture_size_normalization_factor = vec2(1, 1); +#else + vec2 texture_size_normalization_factor = vec2(textureSize(sColor0, 0)); +#endif + // vUv will contain how many times this image has wrapped around the image size. - vec2 texture_size = vec2(textureSize(sColor0, 0)); - vec2 st0 = res.uv_rect.xy / texture_size; - vec2 st1 = res.uv_rect.zw / texture_size; + vec2 st0 = res.uv_rect.xy / texture_size_normalization_factor; + vec2 st1 = res.uv_rect.zw / texture_size_normalization_factor; vTextureSize = st1 - st0; vTextureOffset = st0; vTileSpacing = image.stretch_size_and_tile_spacing.zw; vStretchSize = image.stretch_size_and_tile_spacing.xy; - vec2 half_texel = vec2(0.5) / texture_size; + // We clamp the texture coordinates to the half-pixel offset from the borders + // in order to avoid sampling outside of the texture area. + vec2 half_texel = vec2(0.5) / texture_size_normalization_factor; vStRect = vec4(min(st0, st1) + half_texel, max(st0, st1) - half_texel); } diff --git a/webrender/res/shared.glsl b/webrender/res/shared.glsl index f0784f6c74..c6d70055f1 100644 --- a/webrender/res/shared.glsl +++ b/webrender/res/shared.glsl @@ -33,9 +33,15 @@ //====================================================================================== // Shared shader uniforms //====================================================================================== +#ifndef WR_FEATURE_TEXTURE_RECT uniform sampler2D sColor0; uniform sampler2D sColor1; uniform sampler2D sColor2; +#else +uniform sampler2DRect sColor0; +uniform sampler2DRect sColor1; +uniform sampler2DRect sColor2; +#endif uniform sampler2D sDither; uniform sampler2D sMask; diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 8e49f029e7..ada776c124 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -65,6 +65,7 @@ const GPU_TAG_INIT: GpuProfileTag = GpuProfileTag { label: "Init", color: debug_ const GPU_TAG_SETUP_TARGET: GpuProfileTag = GpuProfileTag { label: "Target", color: debug_colors::SLATEGREY }; const GPU_TAG_PRIM_RECT: GpuProfileTag = GpuProfileTag { label: "Rect", color: debug_colors::RED }; const GPU_TAG_PRIM_IMAGE: GpuProfileTag = GpuProfileTag { label: "Image", color: debug_colors::GREEN }; +const GPU_TAG_PRIM_IMAGE_RECT: GpuProfileTag = GpuProfileTag { label: "ImageRect", color: debug_colors::GREENYELLOW }; const GPU_TAG_PRIM_YUV_IMAGE: GpuProfileTag = GpuProfileTag { label: "YuvImage", color: debug_colors::DARKGREEN }; const GPU_TAG_PRIM_BLEND: GpuProfileTag = GpuProfileTag { label: "Blend", color: debug_colors::LIGHTBLUE }; const GPU_TAG_PRIM_HW_COMPOSITE: GpuProfileTag = GpuProfileTag { label: "HwComposite", color: debug_colors::DODGERBLUE }; @@ -223,6 +224,7 @@ pub type GradientDataStore = GpuStore; const TRANSFORM_FEATURE: &'static str = "TRANSFORM"; const SUBPIXEL_AA_FEATURE: &'static str = "SUBPIXEL_AA"; const CLIP_FEATURE: &'static str = "CLIP"; +const TEXTURE_RECT_FEATURE: &'static str = "TEXTURE_RECT"; enum ShaderKind { Primitive, @@ -465,6 +467,7 @@ pub struct Renderer { ps_text_run: PrimitiveShader, ps_text_run_subpixel: PrimitiveShader, ps_image: PrimitiveShader, + ps_image_rect: PrimitiveShader, ps_yuv_image: PrimitiveShader, ps_border: PrimitiveShader, ps_gradient: PrimitiveShader, @@ -670,6 +673,13 @@ impl Renderer { options.precache_shaders) }; + let ps_image_rect = try!{ + PrimitiveShader::new("ps_image", + &mut device, + &[ TEXTURE_RECT_FEATURE ], + options.precache_shaders) + }; + let ps_yuv_image = try!{ PrimitiveShader::new("ps_yuv_image", &mut device, @@ -912,6 +922,7 @@ impl Renderer { ps_text_run: ps_text_run, ps_text_run_subpixel: ps_text_run_subpixel, ps_image: ps_image, + ps_image_rect: ps_image_rect, ps_yuv_image: ps_yuv_image, ps_border: ps_border, ps_box_shadow: ps_box_shadow, @@ -1346,6 +1357,10 @@ impl Renderer { let shader = self.ps_image.get(&mut self.device, transform_kind); (GPU_TAG_PRIM_IMAGE, shader) } + AlphaBatchKind::ImageRect => { + let shader = self.ps_image_rect.get(&mut self.device, transform_kind); + (GPU_TAG_PRIM_IMAGE_RECT, shader) + } AlphaBatchKind::YuvImage => { let shader = self.ps_yuv_image.get(&mut self.device, transform_kind); (GPU_TAG_PRIM_YUV_IMAGE, shader) diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index a884586232..abef6f6adf 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -28,6 +28,7 @@ use webrender_traits::{DeviceIntSize, DeviceUintPoint}; use webrender_traits::{DeviceUintSize, FontRenderMode, ImageRendering, LayerPoint, LayerRect}; use webrender_traits::{LayerToWorldTransform, MixBlendMode, PipelineId, ScrollLayerId}; use webrender_traits::{WorldPoint4D, WorldToLayerTransform}; +use webrender_traits::{ExternalImageType}; // Special sentinel value recognized by the shader. It is considered to be // a dummy task that doesn't mask out anything. @@ -70,7 +71,24 @@ impl AlphaBatchHelpers for PrimitiveStore { let batch_kind = match metadata.prim_kind { PrimitiveKind::Border => AlphaBatchKind::Border, PrimitiveKind::BoxShadow => AlphaBatchKind::BoxShadow, - PrimitiveKind::Image => AlphaBatchKind::Image, + PrimitiveKind::Image => { + let image_cpu = &self.cpu_images[metadata.cpu_prim_index.0]; + + match image_cpu.color_texture_id { + SourceTexture::External(ext_image) => { + match ext_image.image_type { + ExternalImageType::Texture2DHandle => AlphaBatchKind::Image, + ExternalImageType::TextureRectHandle => AlphaBatchKind::ImageRect, + _ => { + panic!("Non-texture handle type should be handled in other way."); + } + } + } + _ => { + AlphaBatchKind::Image + } + } + } PrimitiveKind::YuvImage => AlphaBatchKind::YuvImage, PrimitiveKind::Rectangle => AlphaBatchKind::Rectangle, PrimitiveKind::AlignedGradient => AlphaBatchKind::AlignedGradient, @@ -274,7 +292,8 @@ impl AlphaBatchHelpers for PrimitiveStore { }); } } - AlphaBatchKind::Image => { + AlphaBatchKind::Image | + AlphaBatchKind::ImageRect => { let image_cpu = &self.cpu_images[metadata.cpu_prim_index.0]; data.push(PrimitiveInstance { @@ -1311,6 +1330,7 @@ pub enum AlphaBatchKind { Rectangle, TextRun, Image, + ImageRect, YuvImage, Border, AlignedGradient, @@ -1441,6 +1461,7 @@ impl PrimitiveBatch { AlphaBatchKind::Rectangle | AlphaBatchKind::TextRun | AlphaBatchKind::Image | + AlphaBatchKind::ImageRect | AlphaBatchKind::YuvImage | AlphaBatchKind::Border | AlphaBatchKind::AlignedGradient | From bbfefccfba56a360e2e7f2c808f7b5609c0c1a67 Mon Sep 17 00:00:00 2001 From: JerryShih Date: Tue, 21 Mar 2017 15:46:47 +0800 Subject: [PATCH 4/4] Update ImageData type in wrench. --- wrench/src/json_frame_writer.rs | 3 +-- wrench/src/yaml_frame_writer.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/wrench/src/json_frame_writer.rs b/wrench/src/json_frame_writer.rs index 4f48b8d079..fe44f659f0 100644 --- a/wrench/src/json_frame_writer.rs +++ b/wrench/src/json_frame_writer.rs @@ -220,8 +220,7 @@ impl webrender::ApiRecordingReceiver for JsonFrameWriter { ); let bytes = match data { &ImageData::Raw(ref v) => { (**v).clone() } - &ImageData::ExternalHandle(_) => { return; } - &ImageData::ExternalBuffer(_) => { return; } + &ImageData::External(_) => { return; } &ImageData::Blob(_) => { return; } }; self.images.insert(*key, CachedImage { diff --git a/wrench/src/yaml_frame_writer.rs b/wrench/src/yaml_frame_writer.rs index 23cd0bdf1a..6ca32b57f7 100644 --- a/wrench/src/yaml_frame_writer.rs +++ b/wrench/src/yaml_frame_writer.rs @@ -782,8 +782,7 @@ impl webrender::ApiRecordingReceiver for YamlFrameWriterReceiver { ); let bytes = match data { &ImageData::Raw(ref v) => { (**v).clone() } - &ImageData::ExternalHandle(_) => { return; } - &ImageData::ExternalBuffer(_) => { return; } + &ImageData::External(_) => { return; } &ImageData::Blob(_) => { return; } }; self.frame_writer.images.insert(*key, CachedImage {