diff --git a/gfx/webrender/res/brush_image.glsl b/gfx/webrender/res/brush_image.glsl index 768c6e10c9af..aaac698978b7 100644 --- a/gfx/webrender/res/brush_image.glsl +++ b/gfx/webrender/res/brush_image.glsl @@ -26,6 +26,10 @@ flat varying vec2 vTileRepeat; #ifdef WR_VERTEX_SHADER +// Must match the AlphaType enum. +#define BLEND_MODE_ALPHA 0 +#define BLEND_MODE_PREMUL_ALPHA 1 + struct ImageBrushData { vec4 color; vec4 background_color; @@ -105,7 +109,8 @@ void brush_vs( vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size; #ifdef WR_FEATURE_ALPHA_PASS - int color_mode = user_data.x; + int color_mode = user_data.x & 0xffff; + int blend_mode = user_data.x >> 16; int raster_space = user_data.y; if (color_mode == COLOR_MODE_FROM_PASS) { @@ -146,6 +151,17 @@ void brush_vs( #ifdef WR_FEATURE_ALPHA_PASS vTileRepeat = repeat.xy; + float opacity = float(user_data.z) / 65535.0; + switch (blend_mode) { + case BLEND_MODE_ALPHA: + image_data.color.a *= opacity; + break; + case BLEND_MODE_PREMUL_ALPHA: + default: + image_data.color *= opacity; + break; + } + switch (color_mode) { case COLOR_MODE_ALPHA: case COLOR_MODE_BITMAP: diff --git a/gfx/webrender/res/brush_solid.glsl b/gfx/webrender/res/brush_solid.glsl index 5cdc1a50170d..cfd1ae3c2ab4 100644 --- a/gfx/webrender/res/brush_solid.glsl +++ b/gfx/webrender/res/brush_solid.glsl @@ -35,7 +35,9 @@ void brush_vs( vec4 unused ) { SolidBrush prim = fetch_solid_primitive(prim_address); - vColor = prim.color; + + float opacity = float(user_data.x) / 65535.0; + vColor = prim.color * opacity; #ifdef WR_FEATURE_ALPHA_PASS vLocalPos = vi.local_pos; diff --git a/gfx/webrender/src/batch.rs b/gfx/webrender/src/batch.rs index 9946896cd939..4c6bf959b165 100644 --- a/gfx/webrender/src/batch.rs +++ b/gfx/webrender/src/batch.rs @@ -566,9 +566,9 @@ impl AlphaBatchBuilder { BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)), textures, [ - ShaderColorMode::Image as i32, + ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), RasterizationSpace::Local as i32, - 0, + get_shader_opacity(1.0), ], cache_item.uv_rect_handle.as_int(gpu_cache), ) @@ -577,7 +577,7 @@ impl AlphaBatchBuilder { ( BrushBatchKind::Solid, BatchTextures::no_texture(), - [0; 3], + [get_shader_opacity(1.0), 0, 0], 0, ) } @@ -749,9 +749,9 @@ impl AlphaBatchBuilder { textures, ); let prim_header_index = prim_headers.push(&prim_header, z_id, [ - ShaderColorMode::Image as i32, + ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), RasterizationSpace::Screen as i32, - 0, + get_shader_opacity(1.0), ]); let instance = BrushInstance { @@ -814,9 +814,9 @@ impl AlphaBatchBuilder { let z_id_content = z_generator.next(); let content_prim_header_index = prim_headers.push(&prim_header, z_id_content, [ - ShaderColorMode::Image as i32, + ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), RasterizationSpace::Screen as i32, - 0, + get_shader_opacity(1.0), ]); let shadow_rect = picture.local_rect.translate(&offset); @@ -830,9 +830,9 @@ impl AlphaBatchBuilder { }; let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, z_id_shadow, [ - ShaderColorMode::Alpha as i32, + ShaderColorMode::Alpha as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), RasterizationSpace::Screen as i32, - 0, + get_shader_opacity(1.0), ]); let shadow_instance = BrushInstance { @@ -1001,9 +1001,9 @@ impl AlphaBatchBuilder { .get_texture_address(gpu_cache) .as_int(); let prim_header_index = prim_headers.push(&prim_header, z_id, [ - ShaderColorMode::Image as i32, + ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), RasterizationSpace::Screen as i32, - 0, + get_shader_opacity(1.0), ]); let instance = BrushInstance { @@ -1093,13 +1093,15 @@ impl AlphaBatchBuilder { match prim.details { PrimitiveDetails::Brush(ref brush) => { match brush.kind { - BrushKind::Image { request, ref visible_tiles, .. } if !visible_tiles.is_empty() => { + BrushKind::Image { alpha_type, request, ref opacity_binding, ref visible_tiles, .. } if !visible_tiles.is_empty() => { for tile in visible_tiles { if let Some((batch_kind, textures, user_data, uv_rect_address)) = get_image_tile_params( ctx.resource_cache, gpu_cache, deferred_resolves, request.with_tile(tile.tile_offset), + alpha_type, + get_shader_opacity(opacity_binding.current), ) { let prim_cache_address = gpu_cache.get_address(&tile.handle); let prim_header = PrimitiveHeader { @@ -1522,6 +1524,8 @@ fn get_image_tile_params( gpu_cache: &mut GpuCache, deferred_resolves: &mut Vec, request: ImageRequest, + alpha_type: AlphaType, + shader_opacity: i32, ) -> Option<(BrushBatchKind, BatchTextures, [i32; 3], GpuCacheAddress)> { let cache_item = resolve_image( @@ -1539,9 +1543,9 @@ fn get_image_tile_params( BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)), textures, [ - ShaderColorMode::Image as i32, + ShaderColorMode::Image as i32 | ((alpha_type as i32) << 16), RasterizationSpace::Local as i32, - 0, + shader_opacity, ], gpu_cache.get_address(&cache_item.uv_rect_handle), )) @@ -1609,7 +1613,7 @@ impl BrushPrimitive { prim_instance: &PrimitiveInstance, ) -> Option { match self.kind { - BrushKind::Image { request, ref source, .. } => { + BrushKind::Image { alpha_type, request, ref source, ref opacity_binding, .. } => { let cache_item = match *source { ImageSource::Default => { resolve_image( @@ -1641,9 +1645,9 @@ impl BrushPrimitive { BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)), textures, [ - ShaderColorMode::Image as i32, + ShaderColorMode::Image as i32 | ((alpha_type as i32) << 16), RasterizationSpace::Local as i32, - 0, + get_shader_opacity(opacity_binding.current), ], cache_item.uv_rect_handle.as_int(gpu_cache), )) @@ -1669,9 +1673,9 @@ impl BrushPrimitive { BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)), textures, [ - ShaderColorMode::Image as i32, + ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), RasterizationSpace::Local as i32, - 0, + get_shader_opacity(1.0), ], cache_item.uv_rect_handle.as_int(gpu_cache), )) @@ -1699,20 +1703,20 @@ impl BrushPrimitive { Some(BrushBatchParameters::instanced( BrushBatchKind::Image(ImageBufferKind::Texture2DArray), [ - ShaderColorMode::Image as i32, + ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), RasterizationSpace::Local as i32, - 0, + get_shader_opacity(1.0), ], segment_data, )) } } } - BrushKind::Solid { .. } => { + BrushKind::Solid { ref opacity_binding, .. } => { Some(BrushBatchParameters::shared( BrushBatchKind::Solid, BatchTextures::no_texture(), - [0; 3], + [get_shader_opacity(opacity_binding.current), 0, 0], 0, )) } @@ -1720,7 +1724,7 @@ impl BrushPrimitive { Some(BrushBatchParameters::shared( BrushBatchKind::Solid, BatchTextures::no_texture(), - [0; 3], + [get_shader_opacity(1.0), 0, 0], 0, )) } @@ -2143,3 +2147,7 @@ fn get_buffer_kind(texture: TextureSource) -> ImageBufferKind { _ => ImageBufferKind::Texture2DArray, } } + +fn get_shader_opacity(opacity: f32) -> i32 { + (opacity * 65535.0).round() as i32 +} diff --git a/gfx/webrender/src/prim_store.rs b/gfx/webrender/src/prim_store.rs index a17dce2fda72..57d2d4c08ed0 100644 --- a/gfx/webrender/src/prim_store.rs +++ b/gfx/webrender/src/prim_store.rs @@ -483,7 +483,7 @@ pub type PrimitiveDataInterner = intern::Interner>, - current: f32, + pub current: f32, } impl OpacityBinding { @@ -502,7 +502,7 @@ impl OpacityBinding { // Resolve the current value of each opacity binding, and // store that as a single combined opacity. Returns true // if the opacity value changed from last time. - pub fn update(&mut self, scene_properties: &SceneProperties) -> bool { + pub fn update(&mut self, scene_properties: &SceneProperties) { let mut new_opacity = 1.0; for binding in &self.bindings { @@ -510,10 +510,7 @@ impl OpacityBinding { new_opacity = new_opacity * opacity; } - let changed = new_opacity != self.current; self.current = new_opacity; - - changed } } @@ -852,8 +849,8 @@ impl BrushPrimitive { } // Images are drawn as a white color, modulated by the total // opacity coming from any collapsed property bindings. - BrushKind::Image { stretch_size, tile_spacing, color, ref opacity_binding, .. } => { - request.push(color.scale_alpha(opacity_binding.current).premultiplied()); + BrushKind::Image { stretch_size, tile_spacing, color, .. } => { + request.push(color.premultiplied()); request.push(PremultipliedColorF::WHITE); request.push([ stretch_size.width + tile_spacing.width, @@ -863,8 +860,8 @@ impl BrushPrimitive { ]); } // Solid rects also support opacity collapsing. - BrushKind::Solid { color, ref opacity_binding, .. } => { - request.push(color.scale_alpha(opacity_binding.current).premultiplied()); + BrushKind::Solid { ref color, .. } => { + request.push(color.premultiplied()); } BrushKind::Clear => { // Opaque black with operator dest out @@ -2927,12 +2924,7 @@ impl PrimitiveInstance { // Set if we need to request the source image from the cache this frame. if let Some(image_properties) = image_properties { is_tiled = image_properties.tiling.is_some(); - - // If the opacity changed, invalidate the GPU cache so that - // the new color for this primitive gets uploaded. - if opacity_binding.update(frame_context.scene_properties) { - frame_state.gpu_cache.invalidate(&mut self.gpu_location); - } + opacity_binding.update(frame_context.scene_properties); if *tile_spacing != LayoutSize::zero() && !is_tiled { *source = ImageSource::Cache { @@ -3083,7 +3075,7 @@ impl PrimitiveInstance { let mut handle = GpuCacheHandle::new(); if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) { - request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied()); + request.push(PremultipliedColorF::WHITE); request.push(PremultipliedColorF::WHITE); request.push([tile.rect.size.width, tile.rect.size.height, 0.0, 0.0]); request.write_segment(tile.rect, [0.0; 4]); @@ -3321,13 +3313,7 @@ impl PrimitiveInstance { } } BrushKind::Solid { ref color, ref mut opacity_binding, .. } => { - // If the opacity changed, invalidate the GPU cache so that - // the new color for this primitive gets uploaded. Also update - // the opacity field that controls which batches this primitive - // will be added to. - if opacity_binding.update(frame_context.scene_properties) { - frame_state.gpu_cache.invalidate(&mut self.gpu_location); - } + opacity_binding.update(frame_context.scene_properties); PrimitiveOpacity::from_alpha(opacity_binding.current * color.a) } BrushKind::Clear => PrimitiveOpacity::translucent(), diff --git a/gfx/webrender_bindings/revision.txt b/gfx/webrender_bindings/revision.txt index 7e7fe6a056af..b7d34b6c31ac 100644 --- a/gfx/webrender_bindings/revision.txt +++ b/gfx/webrender_bindings/revision.txt @@ -1 +1 @@ -b658a833f3c7d90808acc53ee3cb7741016ba17e +340c25fa718146a5c278d59ccc5194a23dfd7996