Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use brush_image for blurs, instead of 2d hardware composite. #2509

Merged
merged 2 commits into from Mar 13, 2018
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

Use brush_image for blurs, instead of 2d hardware composite.

Once this lands, we can fix drop-shadows by making use of this
functionality, and port the other remaining uses of ps_hardware_composite
to use brush_image. Then, ps_hardware_composite can be removed,
and everything except 3d plane-splits will then be drawn as
normal primitives.

Incidentally, this fixes the way we handle blurs when the source
picture is clipped by either the screen bounds or a clip-chain.
The code will now inflate the rendered portion of the source
render task correctly, so include enough pixels to get a correct
blur result at the edges.
  • Loading branch information
gw3583 committed Mar 13, 2018
commit d2f0b6fdd2fcb2c9661546d4ac78371c238b36fc
@@ -16,6 +16,7 @@ flat varying vec4 vColor;

#ifdef WR_FEATURE_ALPHA_PASS
flat varying vec2 vSelect;
flat varying vec4 vUvClipBounds;
#endif

#ifdef WR_VERTEX_SHADER
@@ -26,6 +27,17 @@ flat varying vec2 vSelect;
#define IMAGE_SOURCE_MASK_FROM_COLOR 2
#endif

struct ImageBrush {
RectWithSize rendered_task_rect;
};

ImageBrush fetch_image_primitive(int address) {
vec4 data = fetch_from_resource_cache_1(address);
RectWithSize rendered_task_rect = RectWithSize(data.xy, data.zw);
ImageBrush brush = ImageBrush(rendered_task_rect);
return brush;
}

void brush_vs(
VertexInfo vi,
int prim_address,
@@ -48,17 +60,51 @@ void brush_vs(
vUv.z = res.layer;
vColor = res.color;

vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
vUv.xy = mix(uv0, uv1, f);
vUv.xy /= texture_size;

// Handle case where the UV coords are inverted (e.g. from an
// external image).
vec2 min_uv = min(uv0, uv1);
vec2 max_uv = max(uv0, uv1);

vUvBounds = vec4(
min(uv0, uv1) + vec2(0.5),
max(uv0, uv1) - vec2(0.5)
min_uv + vec2(0.5),
max_uv - vec2(0.5)
) / texture_size.xyxy;

vec2 f;

#ifdef WR_FEATURE_ALPHA_PASS
// Derive the texture coordinates for this image, based on
// whether the source image is a local-space or screen-space
// image.
switch (user_data.z) {
case RASTER_SCREEN: {
ImageBrush image = fetch_image_primitive(prim_address);

f = (vi.snapped_device_pos - image.rendered_task_rect.p0) / image.rendered_task_rect.size;

vUvClipBounds = vec4(
min_uv,
max_uv
) / texture_size.xyxy;
break;
}
case RASTER_LOCAL:
default: {
f = (vi.local_pos - local_rect.p0) / local_rect.size;

// Set the clip bounds to a value that won't have any
// effect for local space images.
vUvClipBounds = vec4(0.0, 0.0, 1.0, 1.0);
break;
}
}
#else
f = (vi.local_pos - local_rect.p0) / local_rect.size;
#endif

vUv.xy = mix(uv0, uv1, f);
vUv.xy /= texture_size;

#ifdef WR_FEATURE_ALPHA_PASS
switch (user_data.y) {
case IMAGE_SOURCE_COLOR:
@@ -86,6 +132,10 @@ vec4 brush_fs() {
#ifdef WR_FEATURE_ALPHA_PASS
vec4 mask = mix(texel.rrrr, texel.aaaa, vSelect.x);
vec4 color = mix(texel, vColor * mask, vSelect.y) * init_transform_fs(vLocalPos);

// Fail-safe to ensure that we don't sample outside the rendered
// portion of a picture source.
color.a *= point_inside_rect(vUv.xy, vUvClipBounds.xy, vUvClipBounds.zw);
#else
vec4 color = texel;
#endif
@@ -16,6 +16,9 @@
#define SUBPX_DIR_HORIZONTAL 1
#define SUBPX_DIR_VERTICAL 2

#define RASTER_LOCAL 0
#define RASTER_SCREEN 1

#define EPSILON 0.0001

uniform sampler2DArray sCacheA8;
@@ -13,7 +13,7 @@ use euclid::{TypedTransform3D, vec3};
use glyph_rasterizer::GlyphFormat;
use gpu_cache::{GpuCache, GpuCacheAddress};
use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex};
use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex};
use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, RasterizationSpace};
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive};
@@ -919,7 +919,7 @@ impl AlphaBatchBuilder {
user_data: [
uv_rect_address,
BrushImageSourceKind::Color as i32,
0,
RasterizationSpace::Local as i32,
],
};
batch.push(PrimitiveInstance::from(instance));
@@ -966,25 +966,32 @@ impl AlphaBatchBuilder {
PictureCompositeMode::Filter(filter) => {
match filter {
FilterOp::Blur(..) => {
let src_task_address = render_tasks.get_task_address(source_id);
let key = BatchKey::new(
BatchKind::HardwareComposite,
BlendMode::PremultipliedAlpha,
BatchTextures::render_target_cache(),
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
let key = BatchKey::new(kind, non_segmented_blend_mode, textures);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let item_bounding_rect = prim_metadata.screen_rect.expect("bug!!").clipped;
let instance = CompositePrimitiveInstance::new(
task_address,
src_task_address,
RenderTaskAddress(0),
item_bounding_rect.origin.x,
item_bounding_rect.origin.y,
z,
item_bounding_rect.size.width,
item_bounding_rect.size.height,
);

let uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);

let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
uv_rect_address,
BrushImageSourceKind::Color as i32,
RasterizationSpace::Screen as i32,
],
};
batch.push(PrimitiveInstance::from(instance));
}
FilterOp::DropShadow(offset, _, _) => {
@@ -1010,7 +1017,11 @@ impl AlphaBatchBuilder {
user_data: [
uv_rect_address,
BrushImageSourceKind::ColorAlphaMask as i32,
0,
// TODO(gw): This is totally wrong, but the drop-shadow code itself
// is completely wrong, and doesn't work correctly with
// transformed Picture sources. I'm leaving this as is for
// now, and will fix drop-shadows properly, as a follow up.
RasterizationSpace::Local as i32,
],
};

@@ -1309,7 +1320,7 @@ impl BrushPrimitive {
[
cache_item.uv_rect_handle.as_int(gpu_cache),
BrushImageSourceKind::Color as i32,
0,
RasterizationSpace::Local as i32,
],
))
}
@@ -12,7 +12,7 @@ use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState};
use gpu_cache::{GpuCacheHandle, GpuDataRequest};
use gpu_types::{PictureType};
use prim_store::{BrushKind, BrushPrimitive, PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
use prim_store::ScrollNodeAndClipChain;
use prim_store::{PrimitiveMetadata, ScrollNodeAndClipChain};
use render_task::{ClearMode, RenderTask};
use render_task::{RenderTaskId, RenderTaskLocation, to_cache_size};
use scene::{FilterOpHelpers, SceneProperties};
@@ -85,6 +85,9 @@ pub enum PictureKind {
// in the GPU cache, depending on the type of
// picture.
extra_gpu_data_handle: GpuCacheHandle,
// The current screen-space rect of the rendered
// portion of this picture.
task_rect: DeviceIntRect,
},
}

@@ -177,6 +180,7 @@ impl PicturePrimitive {
reference_frame_index,
real_local_rect: LayerRect::zero(),
extra_gpu_data_handle: GpuCacheHandle::new(),
task_rect: DeviceIntRect::zero(),
},
pipeline_id,
cull_children: true,
@@ -248,27 +252,58 @@ impl PicturePrimitive {
pub fn prepare_for_render(
&mut self,
prim_index: PrimitiveIndex,
prim_screen_rect: &DeviceIntRect,
prim_local_rect: &LayerRect,
prim_metadata: &mut PrimitiveMetadata,
pic_state_for_children: PictureState,
pic_state: &mut PictureState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) {
let content_scale = LayerToWorldScale::new(1.0) * frame_context.device_pixel_scale;
let prim_screen_rect = prim_metadata
.screen_rect
.as_ref()
.expect("bug: trying to draw an off-screen picture!?");

match self.kind {
PictureKind::Image {
ref mut secondary_render_task_id,
ref mut extra_gpu_data_handle,
ref mut task_rect,
composite_mode,
..
} => {
let content_origin = ContentOrigin::Screen(prim_screen_rect.origin);
match composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;

// The clipped field is the part of the picture that is visible
// on screen. The unclipped field is the screen-space rect of
// the complete picture, if no screen / clip-chain was applied
// (this includes the extra space for blur region). To ensure
// that we draw a large enough part of the picture to get correct
// blur results, inflate that clipped area by the blur range, and
// then intersect with the total screen rect, to minimize the
// allocation size.
let device_rect = prim_screen_rect
.clipped
.inflate(blur_range, blur_range)
.intersection(&prim_screen_rect.unclipped)
.unwrap();

// If scrolling or property animation has resulted in the task
// rect being different than last time, invalidate the GPU
// cache entry for this picture to ensure that the correct
// task rect is provided to the image shader.
if *task_rect != device_rect {
frame_state.gpu_cache.invalidate(&prim_metadata.gpu_location);
*task_rect = device_rect;
}

let content_origin = ContentOrigin::Screen(device_rect.origin);

let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.size),
RenderTaskLocation::Dynamic(None, device_rect.size),
prim_index,
RenderTargetKind::Color,
content_origin,
@@ -278,7 +313,6 @@ impl PicturePrimitive {
PictureType::Image,
);

let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let picture_task_id = frame_state.render_tasks.add(picture_task);

let blur_render_task = RenderTask::new_blur(
@@ -295,7 +329,9 @@ impl PicturePrimitive {
self.surface = Some(render_task_id);
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
let rect = (prim_local_rect.translate(&-offset) * content_scale).round().to_i32();
// TODO(gw): This is totally wrong and can never work with
// transformed drop-shadow elements. Fix me!
let rect = (prim_metadata.local_rect.translate(&-offset) * content_scale).round().to_i32();
let mut picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, rect.size),
prim_index,
@@ -327,8 +363,10 @@ impl PicturePrimitive {
self.surface = Some(render_task_id);
}
Some(PictureCompositeMode::MixBlend(..)) => {
let content_origin = ContentOrigin::Screen(prim_screen_rect.clipped.origin);

let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.size),
RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
prim_index,
RenderTargetKind::Color,
content_origin,
@@ -338,7 +376,9 @@ impl PicturePrimitive {
PictureType::Image,
);

let readback_task_id = frame_state.render_tasks.add(RenderTask::new_readback(*prim_screen_rect));
let readback_task_id = frame_state.render_tasks.add(
RenderTask::new_readback(prim_screen_rect.clipped)
);

*secondary_render_task_id = Some(readback_task_id);
pic_state.tasks.push(readback_task_id);
@@ -348,6 +388,8 @@ impl PicturePrimitive {
self.surface = Some(render_task_id);
}
Some(PictureCompositeMode::Filter(filter)) => {
let content_origin = ContentOrigin::Screen(prim_screen_rect.clipped.origin);

// If this filter is not currently going to affect
// the picture, just collapse this picture into the
// current render task. This most commonly occurs
@@ -367,7 +409,7 @@ impl PicturePrimitive {
}

let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.size),
RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
prim_index,
RenderTargetKind::Color,
content_origin,
@@ -383,8 +425,10 @@ impl PicturePrimitive {
}
}
Some(PictureCompositeMode::Blit) => {
let content_origin = ContentOrigin::Screen(prim_screen_rect.clipped.origin);

let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.size),
RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
prim_index,
RenderTargetKind::Color,
content_origin,
@@ -456,7 +500,7 @@ impl PicturePrimitive {
PictureKind::TextShadow { .. } => {
request.push([0.0; 4]);
}
PictureKind::Image { composite_mode, .. } => {
PictureKind::Image { composite_mode, task_rect, .. } => {
match composite_mode {
Some(PictureCompositeMode::Filter(filter)) => {
let amount = match filter {
@@ -472,7 +516,17 @@ impl PicturePrimitive {
// Go through different paths
FilterOp::Blur(..) |
FilterOp::DropShadow(..) |
FilterOp::ColorMatrix(_) => 0.0,
FilterOp::ColorMatrix(_) => {
// TODO(gw): The data for blur (and drop-shadows in the future)
// doesn't match how the brush_blend shader uses this
// data for other filter types (see below). We should
// update the brush_blend and brush_mix_blend shaders
// to do screen-space UV calculation the same way that
// the brush_image shader does, and move the amount
// storage into the extra gpu data or instance data.
request.push(task_rect.to_f32());
return;
}
};

request.push([amount, 1.0 - amount, 0.0, 0.0]);
@@ -1062,10 +1062,7 @@ impl PrimitiveStore {
self.cpu_pictures[metadata.cpu_prim_index.0]
.prepare_for_render(
prim_index,
&metadata.screen_rect
.expect("bug: trying to draw an off-screen picture!?")
.clipped,
&metadata.local_rect,
metadata,
pic_state_for_children,
pic_state,
frame_context,
Binary file not shown.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.