Bug 1439565 - Update webrender to commit 8a19316a733a484bf9bafb8257e3008b1418bfe4. r=jrmuizel

MozReview-Commit-ID: BZIK3GEG0ER

--HG--
extra : rebase_source : c24dbf123fe1732917e9fc57ee0ddfe2042892c4
This commit is contained in:
Kartikaya Gupta 2018-02-23 09:29:44 -05:00
Родитель 17ab2350ee
Коммит f22ca7ca1e
25 изменённых файлов: 651 добавлений и 661 удалений

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
#define VECS_PER_SPECIFIC_BRUSH 5
#define VECS_PER_SPECIFIC_BRUSH 1
#define FORCE_NO_PERSPECTIVE
#include shared,prim_shared,brush
@ -83,9 +83,10 @@ void brush_vs(
}
case 10: {
// Color Matrix
vec4 data[4] = fetch_from_resource_cache_4(prim_address + 1);
vColorMat = mat4(amount, data[0], data[1], data[2]);
vColorOffset = data[3];
vec4 mat_data[4] = fetch_from_resource_cache_4(user_data.z);
vec4 offset_data = fetch_from_resource_cache_1(user_data.z + 4);
vColorMat = mat4(mat_data[0], mat_data[1], mat_data[2], mat_data[3]);
vColorOffset = offset_data;
break;
}
default: break;

Просмотреть файл

@ -40,7 +40,12 @@ void brush_vs(
vUv.xy = mix(uv0, uv1, f);
vUv.xy /= texture_size;
vUvBounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) / texture_size.xyxy;
// Handle case where the UV coords are inverted (e.g. from an
// external image).
vUvBounds = vec4(
min(uv0, uv1) + vec2(0.5),
max(uv0, uv1) - vec2(0.5)
) / texture_size.xyxy;
#ifdef WR_FEATURE_ALPHA_PASS
vLocalPos = vi.local_pos;

Просмотреть файл

@ -119,38 +119,7 @@ void brush_vs(
#ifdef WR_FRAGMENT_SHADER
#define MAGIC_WAVY_LINE_AA_SNAP 0.7
float det(vec2 a, vec2 b) {
return a.x * b.y - b.x * a.y;
}
// From: http://research.microsoft.com/en-us/um/people/hoppe/ravg.pdf
vec2 get_distance_vector(vec2 b0, vec2 b1, vec2 b2) {
float a = det(b0, b2);
float b = 2.0 * det(b1, b0);
float d = 2.0 * det(b2, b1);
float f = b * d - a * a;
vec2 d21 = b2 - b1;
vec2 d10 = b1 - b0;
vec2 d20 = b2 - b0;
vec2 gf = 2.0 * (b *d21 + d * d10 + a * d20);
gf = vec2(gf.y,-gf.x);
vec2 pp = -f * gf / dot(gf, gf);
vec2 d0p = b0 - pp;
float ap = det(d0p, d20);
float bp = 2.0 * det(d10, d0p);
float t = clamp((ap + bp) / (2.0 * a + b + d), 0.0, 1.0);
return mix(mix(b0, b1, t), mix(b1,b2,t), t);
}
// Approximate distance from point to quadratic bezier.
float approx_distance(vec2 p, vec2 b0, vec2 b1, vec2 b2) {
return length(get_distance_vector(b0 - p, b1 - p, b2 - p));
}
#define MAGIC_WAVY_LINE_AA_SNAP 0.5
vec4 brush_fs() {
// Find the appropriate distance to apply the step over.

Просмотреть файл

@ -0,0 +1,76 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
#define VECS_PER_SPECIFIC_BRUSH 2
#include shared,prim_shared,brush
flat varying int vGradientAddress;
flat varying float vGradientRepeat;
flat varying vec2 vScaledDir;
flat varying vec2 vStartPoint;
varying vec2 vPos;
#ifdef WR_FEATURE_ALPHA_PASS
varying vec2 vLocalPos;
#endif
#ifdef WR_VERTEX_SHADER
struct Gradient {
vec4 start_end_point;
vec4 extend_mode;
};
Gradient fetch_gradient(int address) {
vec4 data[2] = fetch_from_resource_cache_2(address);
return Gradient(data[0], data[1]);
}
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
ivec3 user_data,
PictureTask pic_task
) {
Gradient gradient = fetch_gradient(prim_address);
vPos = vi.local_pos - local_rect.p0;
vec2 start_point = gradient.start_end_point.xy;
vec2 end_point = gradient.start_end_point.zw;
vec2 dir = end_point - start_point;
vStartPoint = start_point;
vScaledDir = dir / dot(dir, dir);
vGradientAddress = user_data.x;
// Whether to repeat the gradient instead of clamping.
vGradientRepeat = float(int(gradient.extend_mode.x) != EXTEND_MODE_CLAMP);
#ifdef WR_FEATURE_ALPHA_PASS
vLocalPos = vi.local_pos;
#endif
}
#endif
#ifdef WR_FRAGMENT_SHADER
vec4 brush_fs() {
float offset = dot(vPos - vStartPoint, vScaledDir);
vec4 color = sample_gradient(vGradientAddress,
offset,
vGradientRepeat);
#ifdef WR_FEATURE_ALPHA_PASS
color *= init_transform_fs(vLocalPos);
#endif
return color;
}
#endif

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
#define VECS_PER_SPECIFIC_BRUSH 5
#define VECS_PER_SPECIFIC_BRUSH 1
#include shared,prim_shared,brush

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
#define VECS_PER_SPECIFIC_BRUSH 5
#define VECS_PER_SPECIFIC_BRUSH 1
#include shared,prim_shared,brush

Просмотреть файл

@ -41,6 +41,12 @@ varying vec2 vLocalPos;
flat varying vec4 vUvBounds_YUV;
#endif
#ifdef WR_FEATURE_TEXTURE_RECT
#define TEX_SIZE(sampler) vec2(1.0)
#else
#define TEX_SIZE(sampler) vec2(textureSize(sampler, 0).xy)
#endif
#ifdef WR_VERTEX_SHADER
void write_uv_rect(
int resource_id,
@ -78,14 +84,14 @@ void brush_vs(
#endif
#if defined (WR_FEATURE_YUV_PLANAR)
write_uv_rect(user_data.x, f, vec2(textureSize(sColor0, 0).xy), vUv_Y, vUvBounds_Y);
write_uv_rect(user_data.y, f, vec2(textureSize(sColor1, 0).xy), vUv_U, vUvBounds_U);
write_uv_rect(user_data.z, f, vec2(textureSize(sColor2, 0).xy), vUv_V, vUvBounds_V);
write_uv_rect(user_data.x, f, TEX_SIZE(sColor0), vUv_Y, vUvBounds_Y);
write_uv_rect(user_data.y, f, TEX_SIZE(sColor1), vUv_U, vUvBounds_U);
write_uv_rect(user_data.z, f, TEX_SIZE(sColor2), vUv_V, vUvBounds_V);
#elif defined (WR_FEATURE_YUV_NV12)
write_uv_rect(user_data.x, f, vec2(textureSize(sColor0, 0).xy), vUv_Y, vUvBounds_Y);
write_uv_rect(user_data.y, f, vec2(textureSize(sColor1, 0).xy), vUv_UV, vUvBounds_UV);
write_uv_rect(user_data.x, f, TEX_SIZE(sColor0), vUv_Y, vUvBounds_Y);
write_uv_rect(user_data.y, f, TEX_SIZE(sColor1), vUv_UV, vUvBounds_UV);
#elif defined (WR_FEATURE_YUV_INTERLEAVED)
write_uv_rect(user_data.x, f, vec2(textureSize(sColor0, 0).xy), vUv_YUV, vUvBounds_YUV);
write_uv_rect(user_data.x, f, TEX_SIZE(sColor0), vUv_YUV, vUvBounds_YUV);
#endif //WR_FEATURE_YUV_*
}
#endif

Просмотреть файл

@ -16,6 +16,8 @@
#define SUBPX_DIR_HORIZONTAL 1
#define SUBPX_DIR_VERTICAL 2
#define EPSILON 0.0001
uniform sampler2DArray sCacheA8;
uniform sampler2DArray sCacheRGBA8;
@ -74,7 +76,6 @@ vec4[2] fetch_from_resource_cache_2(int address) {
#define VECS_PER_RENDER_TASK 3
#define VECS_PER_PRIM_HEADER 2
#define VECS_PER_TEXT_RUN 3
#define VECS_PER_GRADIENT 3
#define VECS_PER_GRADIENT_STOP 2
uniform HIGHP_SAMPLER_FLOAT sampler2D sClipScrollNodes;
@ -304,17 +305,6 @@ ClipArea fetch_clip_area(int index) {
return area;
}
struct Gradient {
vec4 start_end_point;
vec4 tile_size_repeat;
vec4 extend_mode;
};
Gradient fetch_gradient(int address) {
vec4 data[3] = fetch_from_resource_cache_3(address);
return Gradient(data[0], data[1], data[2]);
}
struct Glyph {
vec2 offset;
};
@ -748,7 +738,7 @@ void write_clip(vec2 global_pos, ClipArea area) {
#ifdef WR_FRAGMENT_SHADER
/// Find the appropriate half range to apply the AA smoothstep over.
/// Find the appropriate half range to apply the AA approximation over.
/// This range represents a coefficient to go from one CSS pixel to half a device pixel.
float compute_aa_range(vec2 position) {
// The constant factor is chosen to compensate for the fact that length(fw) is equal
@ -759,22 +749,41 @@ float compute_aa_range(vec2 position) {
// such a pixel (axis aligned) is fully inside the border). We need this so that antialiased
// curves properly connect with non-antialiased vertical or horizontal lines, among other things.
//
// Using larger aa steps is quite common when rendering shapes with distance fields.
// It gives a smoother (although blurrier look) by extending the range that is smoothed
// to produce the anti aliasing. In our case, however, extending the range inside of
// the shape causes noticeable artifacts at the junction between an antialiased corner
// and a straight edge.
// Lines over a half-pixel away from the pixel center *can* intersect with the pixel square;
// indeed, unless they are horizontal or vertical, they are guaranteed to. However, choosing
// a nonzero area for such pixels causes noticeable artifacts at the junction between an anti-
// aliased corner and a straight edge.
//
// We may want to adjust this constant in specific scenarios (for example keep the principled
// value for straight edges where we want pixel-perfect equivalence with non antialiased lines
// when axis aligned, while selecting a larger and smoother aa range on curves).
return 0.35355 * length(fwidth(position));
}
/// Return the blending coefficient to for distance antialiasing.
/// Return the blending coefficient for distance antialiasing.
///
/// 0.0 means inside the shape, 1.0 means outside.
///
/// This cubic polynomial approximates the area of a 1x1 pixel square under a
/// line, given the signed Euclidean distance from the center of the square to
/// that line. Calculating the *exact* area would require taking into account
/// not only this distance but also the angle of the line. However, in
/// practice, this complexity is not required, as the area is roughly the same
/// regardless of the angle.
///
/// The coefficients of this polynomial were determined through least-squares
/// regression and are accurate to within 2.16% of the total area of the pixel
/// square 95% of the time, with a maximum error of 3.53%.
///
/// See the comments in `compute_aa_range()` for more information on the
/// cutoff values of -0.5 and 0.5.
float distance_aa(float aa_range, float signed_distance) {
return 1.0 - smoothstep(-aa_range, aa_range, signed_distance);
float dist = 0.5 * signed_distance / aa_range;
if (dist <= -0.5 + EPSILON)
return 1.0;
if (dist >= 0.5 - EPSILON)
return 0.0;
return 0.5 + dist * (0.8431027 * dist * dist - 1.14453603);
}
float signed_distance_rect(vec2 pos, vec2 p0, vec2 p1) {

Просмотреть файл

@ -1,68 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
#include shared,prim_shared
flat varying int vGradientAddress;
flat varying float vGradientRepeat;
flat varying vec2 vScaledDir;
flat varying vec2 vStartPoint;
flat varying vec2 vTileSize;
flat varying vec2 vTileRepeat;
varying vec2 vPos;
#ifdef WR_VERTEX_SHADER
void main(void) {
Primitive prim = load_primitive();
Gradient gradient = fetch_gradient(prim.specific_prim_address);
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.scroll_node,
prim.task,
prim.local_rect);
vPos = vi.local_pos - prim.local_rect.p0;
vec2 start_point = gradient.start_end_point.xy;
vec2 end_point = gradient.start_end_point.zw;
vec2 dir = end_point - start_point;
vStartPoint = start_point;
vScaledDir = dir / dot(dir, dir);
vTileSize = gradient.tile_size_repeat.xy;
vTileRepeat = gradient.tile_size_repeat.zw;
vGradientAddress = prim.specific_prim_address + VECS_PER_GRADIENT;
// Whether to repeat the gradient instead of clamping.
vGradientRepeat = float(int(gradient.extend_mode.x) != EXTEND_MODE_CLAMP);
write_clip(vi.screen_pos, prim.clip_area);
}
#endif
#ifdef WR_FRAGMENT_SHADER
void main(void) {
vec2 pos = mod(vPos, vTileRepeat);
if (pos.x >= vTileSize.x ||
pos.y >= vTileSize.y) {
discard;
}
float offset = dot(pos - vStartPoint, vScaledDir);
vec4 color = sample_gradient(vGradientAddress,
offset,
vGradientRepeat);
oFragColor = color * do_clip();
}
#endif

Просмотреть файл

@ -1,119 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
#include shared,prim_shared
varying vec4 vColor;
varying vec2 vLocalPos;
#ifdef WR_VERTEX_SHADER
struct GradientStop {
vec4 color;
vec4 offset;
};
GradientStop fetch_gradient_stop(int address) {
vec4 data[2] = fetch_from_resource_cache_2(address);
return GradientStop(data[0], data[1]);
}
void main(void) {
Primitive prim = load_primitive();
Gradient gradient = fetch_gradient(prim.specific_prim_address);
vec4 abs_start_end_point = gradient.start_end_point + prim.local_rect.p0.xyxy;
int stop_address = prim.specific_prim_address +
VECS_PER_GRADIENT +
VECS_PER_GRADIENT_STOP * prim.user_data0;
GradientStop g0 = fetch_gradient_stop(stop_address);
GradientStop g1 = fetch_gradient_stop(stop_address + VECS_PER_GRADIENT_STOP);
RectWithSize segment_rect;
vec2 axis;
vec4 adjusted_color_g0 = g0.color;
vec4 adjusted_color_g1 = g1.color;
if (abs_start_end_point.y == abs_start_end_point.w) {
// Calculate the x coord of the gradient stops
vec2 g01_x = mix(abs_start_end_point.xx, abs_start_end_point.zz,
vec2(g0.offset.x, g1.offset.x));
// The gradient stops might exceed the geometry rect so clamp them
vec2 g01_x_clamped = clamp(g01_x,
prim.local_rect.p0.xx,
prim.local_rect.p0.xx + prim.local_rect.size.xx);
// Calculate the segment rect using the clamped coords
segment_rect.p0 = vec2(g01_x_clamped.x, prim.local_rect.p0.y);
segment_rect.size = vec2(g01_x_clamped.y - g01_x_clamped.x, prim.local_rect.size.y);
axis = vec2(1.0, 0.0);
// Adjust the stop colors by how much they were clamped
vec2 adjusted_offset = (g01_x_clamped - g01_x.xx) / (g01_x.y - g01_x.x);
adjusted_color_g0 = mix(g0.color, g1.color, adjusted_offset.x);
adjusted_color_g1 = mix(g0.color, g1.color, adjusted_offset.y);
} else {
// Calculate the y coord of the gradient stops
vec2 g01_y = mix(abs_start_end_point.yy, abs_start_end_point.ww,
vec2(g0.offset.x, g1.offset.x));
// The gradient stops might exceed the geometry rect so clamp them
vec2 g01_y_clamped = clamp(g01_y,
prim.local_rect.p0.yy,
prim.local_rect.p0.yy + prim.local_rect.size.yy);
// Calculate the segment rect using the clamped coords
segment_rect.p0 = vec2(prim.local_rect.p0.x, g01_y_clamped.x);
segment_rect.size = vec2(prim.local_rect.size.x, g01_y_clamped.y - g01_y_clamped.x);
axis = vec2(0.0, 1.0);
// Adjust the stop colors by how much they were clamped
vec2 adjusted_offset = (g01_y_clamped - g01_y.xx) / (g01_y.y - g01_y.x);
adjusted_color_g0 = mix(g0.color, g1.color, adjusted_offset.x);
adjusted_color_g1 = mix(g0.color, g1.color, adjusted_offset.y);
}
#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex(segment_rect,
prim.local_rect,
prim.local_clip_rect,
vec4(1.0),
prim.z,
prim.scroll_node,
prim.task,
true);
vLocalPos = vi.local_pos;
vec2 f = (vi.local_pos.xy - prim.local_rect.p0) / prim.local_rect.size;
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,
prim.z,
prim.scroll_node,
prim.task,
prim.local_rect);
vec2 f = (vi.local_pos - segment_rect.p0) / segment_rect.size;
vLocalPos = vi.local_pos;
#endif
write_clip(vi.screen_pos, prim.clip_area);
vColor = mix(adjusted_color_g0, adjusted_color_g1, dot(f, axis));
}
#endif
#ifdef WR_FRAGMENT_SHADER
void main(void) {
#ifdef WR_FEATURE_TRANSFORM
float alpha = init_transform_fs(vLocalPos);
#else
float alpha = 1.0;
#endif
alpha *= do_clip();
oFragColor = dither(vColor * alpha);
}
#endif

Просмотреть файл

@ -14,16 +14,9 @@
#include base
// The textureLod() doesn't support samplerExternalOES for WR_FEATURE_TEXTURE_EXTERNAL.
// https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external_essl3.txt
//
// The textureLod() doesn't support sampler2DRect for WR_FEATURE_TEXTURE_RECT, too.
//
// Use texture() instead.
#if defined(WR_FEATURE_TEXTURE_EXTERNAL) || defined(WR_FEATURE_TEXTURE_RECT) || defined(WR_FEATURE_TEXTURE_2D)
#define TEX_SAMPLE(sampler, tex_coord) texture(sampler, tex_coord.xy)
#else
// In normal case, we use textureLod(). We haven't used the lod yet. So, we always pass 0.0 now.
#define TEX_SAMPLE(sampler, tex_coord) texture(sampler, tex_coord)
#endif

Просмотреть файл

@ -18,7 +18,7 @@ use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveIn
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
use prim_store::{CachedGradient, ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PrimitiveRun};
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
use renderer::{BlendMode, ImageBufferKind};
@ -38,8 +38,6 @@ const OPAQUE_TASK_ADDRESS: RenderTaskAddress = RenderTaskAddress(0x7fff);
pub enum TransformBatchKind {
TextRun(GlyphFormat),
Image(ImageBufferKind),
AlignedGradient,
AngleGradient,
BorderCorner,
BorderEdge,
}
@ -78,6 +76,7 @@ pub enum BrushBatchKind {
},
YuvImage(ImageBufferKind, YuvFormat, YuvColorSpace),
RadialGradient,
LinearGradient,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -682,6 +681,7 @@ impl AlphaBatchBuilder {
ctx.resource_cache,
gpu_cache,
deferred_resolves,
&ctx.cached_gradients,
) {
self.add_brush_to_batch(
brush,
@ -811,7 +811,7 @@ impl AlphaBatchBuilder {
let font_transform = if is_shadow {
None
} else {
Some(&scroll_node.transform)
Some(scroll_node.transform)
};
let font = text_cpu.get_font(
@ -969,6 +969,7 @@ impl AlphaBatchBuilder {
is_in_3d_context,
reference_frame_id,
real_local_rect,
ref extra_gpu_data_handle,
..
} => {
// If this picture is participating in a 3D rendering context,
@ -977,8 +978,10 @@ impl AlphaBatchBuilder {
if is_in_3d_context {
// Push into parent plane splitter.
let real_xf = &ctx.clip_scroll_tree.nodes[&reference_frame_id].world_content_transform;
let real_xf = &ctx.clip_scroll_tree
.nodes[&reference_frame_id]
.world_content_transform
.into();
let polygon = make_polygon(
real_local_rect,
&real_xf,
@ -1093,18 +1096,20 @@ impl AlphaBatchBuilder {
BatchTextures::render_target_cache(),
);
let filter_mode = match filter {
FilterOp::Blur(..) => 0,
FilterOp::Contrast(..) => 1,
FilterOp::Grayscale(..) => 2,
FilterOp::HueRotate(..) => 3,
FilterOp::Invert(..) => 4,
FilterOp::Saturate(..) => 5,
FilterOp::Sepia(..) => 6,
FilterOp::Brightness(..) => 7,
FilterOp::Opacity(..) => 8,
FilterOp::DropShadow(..) => 9,
FilterOp::ColorMatrix(..) => 10,
let (filter_mode, extra_cache_address) = match filter {
FilterOp::Blur(..) => (0, 0),
FilterOp::Contrast(..) => (1, 0),
FilterOp::Grayscale(..) => (2, 0),
FilterOp::HueRotate(..) => (3, 0),
FilterOp::Invert(..) => (4, 0),
FilterOp::Saturate(..) => (5, 0),
FilterOp::Sepia(..) => (6, 0),
FilterOp::Brightness(..) => (7, 0),
FilterOp::Opacity(..) => (8, 0),
FilterOp::DropShadow(..) => (9, 0),
FilterOp::ColorMatrix(..) => {
(10, extra_gpu_data_handle.as_int(gpu_cache))
}
};
let instance = BrushInstance {
@ -1120,7 +1125,7 @@ impl AlphaBatchBuilder {
user_data: [
cache_task_address.0 as i32,
filter_mode,
0,
extra_cache_address,
],
};
@ -1206,28 +1211,6 @@ impl AlphaBatchBuilder {
}
}
}
PrimitiveKind::AlignedGradient => {
let gradient_cpu =
&ctx.prim_store.cpu_gradients[prim_metadata.cpu_prim_index.0];
let kind = BatchKind::Transformable(
transform_kind,
TransformBatchKind::AlignedGradient,
);
let key = BatchKey::new(kind, non_segmented_blend_mode, no_textures);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
for part_index in 0 .. (gradient_cpu.stops_count - 1) {
batch.push(base_instance.build(part_index as i32, 0, 0));
}
}
PrimitiveKind::AngleGradient => {
let kind = BatchKind::Transformable(
transform_kind,
TransformBatchKind::AngleGradient,
);
let key = BatchKey::new(kind, non_segmented_blend_mode, no_textures);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
batch.push(base_instance.build(0, 0, 0));
}
}
}
@ -1330,6 +1313,7 @@ impl BrushPrimitive {
resource_cache: &ResourceCache,
gpu_cache: &mut GpuCache,
deferred_resolves: &mut Vec<DeferredResolve>,
cached_gradients: &[CachedGradient],
) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> {
match self.kind {
BrushKind::Line { .. } => {
@ -1376,7 +1360,8 @@ impl BrushPrimitive {
[0; 3],
))
}
BrushKind::RadialGradient { ref stops_handle, .. } => {
BrushKind::RadialGradient { gradient_index, .. } => {
let stops_handle = &cached_gradients[gradient_index.0].handle;
Some((
BrushBatchKind::RadialGradient,
BatchTextures::no_texture(),
@ -1387,6 +1372,18 @@ impl BrushPrimitive {
],
))
}
BrushKind::LinearGradient { gradient_index, .. } => {
let stops_handle = &cached_gradients[gradient_index.0].handle;
Some((
BrushBatchKind::LinearGradient,
BatchTextures::no_texture(),
[
stops_handle.as_int(gpu_cache),
0,
0,
],
))
}
BrushKind::YuvImage { format, yuv_key, image_rendering, color_space } => {
let mut textures = BatchTextures::no_texture();
let mut uv_rect_addresses = [0; 3];
@ -1464,8 +1461,6 @@ impl AlphaBatchHelpers for PrimitiveStore {
}
PrimitiveKind::Border |
PrimitiveKind::AlignedGradient |
PrimitiveKind::AngleGradient |
PrimitiveKind::Picture => {
BlendMode::PremultipliedAlpha
}
@ -1487,6 +1482,7 @@ impl AlphaBatchHelpers for PrimitiveStore {
BrushKind::Line { .. } |
BrushKind::YuvImage { .. } |
BrushKind::RadialGradient { .. } |
BrushKind::LinearGradient { .. } |
BrushKind::Picture => {
BlendMode::PremultipliedAlpha
}

Просмотреть файл

@ -3,8 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelScale, ImageMask};
use api::{ImageRendering, LayerRect, LayerToWorldTransform, LayoutPoint, LayoutVector2D};
use api::LocalClip;
use api::{ImageRendering, LayerRect, LayoutPoint, LayoutVector2D, LocalClip};
use border::{BorderCornerClipSource, ensure_no_corner_overlap};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId};
use ellipse::Ellipse;
@ -13,7 +12,8 @@ use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
use gpu_types::ClipScrollNodeIndex;
use prim_store::{ClipData, ImageMaskData};
use resource_cache::{ImageRequest, ResourceCache};
use util::{MaxRect, MatrixHelpers, calculate_screen_bounding_rect, extract_inner_rect_safe};
use util::{LayerToWorldFastTransform, MaxRect, calculate_screen_bounding_rect};
use util::extract_inner_rect_safe;
use std::rc::Rc;
pub type ClipStore = FreeList<ClipSources>;
@ -252,7 +252,7 @@ impl ClipSources {
pub fn get_screen_bounds(
&self,
transform: &LayerToWorldTransform,
transform: &LayerToWorldFastTransform,
device_pixel_scale: DevicePixelScale,
) -> (DeviceIntRect, Option<DeviceIntRect>) {
// If this translation isn't axis aligned or has a perspective component, don't try to

Просмотреть файл

@ -3,9 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ClipId, DevicePixelScale, ExternalScrollId, LayerPixel, LayerPoint, LayerRect};
use api::{LayerSize, LayerToWorldTransform, LayerTransform, LayerVector2D, LayoutTransform};
use api::{LayoutVector2D, PipelineId, PropertyBinding, ScrollClamping, ScrollEventPhase};
use api::{ScrollLocation, ScrollSensitivity, StickyOffsetBounds, WorldPoint};
use api::{LayerSize, LayerVector2D, LayoutTransform, LayoutVector2D, PipelineId, PropertyBinding};
use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollSensitivity, StickyOffsetBounds};
use api::WorldPoint;
use clip::{ClipChain, ClipSourcesHandle, ClipStore, ClipWorkItem};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, TransformUpdateState};
use euclid::SideOffsets2D;
@ -15,7 +15,8 @@ use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use resource_cache::ResourceCache;
use scene::SceneProperties;
use spring::{DAMPING, STIFFNESS, Spring};
use util::{MatrixHelpers, TransformOrOffset, TransformedRectKind};
use util::{LayerToWorldFastTransform, LayerFastTransform, LayoutFastTransform};
use util::{TransformedRectKind};
#[cfg(target_os = "macos")]
const CAN_OVERSCROLL: bool = true;
@ -91,10 +92,10 @@ pub struct ClipScrollNode {
/// between our reference frame and this node. For reference frames, we also include
/// whatever local transformation this reference frame provides. This can be combined
/// with the local_viewport_rect to get its position in world space.
pub world_viewport_transform: LayerToWorldTransform,
pub world_viewport_transform: LayerToWorldFastTransform,
/// World transform for content transformed by this node.
pub world_content_transform: LayerToWorldTransform,
pub world_content_transform: LayerToWorldFastTransform,
/// Pipeline that this layer belongs to
pub pipeline_id: PipelineId,
@ -119,7 +120,7 @@ pub struct ClipScrollNode {
/// The transformation from the coordinate system which established our compatible coordinate
/// system (same coordinate system id) and us. This can change via scroll offsets and via new
/// reference frame transforms.
pub coordinate_system_relative_transform: TransformOrOffset,
pub coordinate_system_relative_transform: LayerFastTransform,
/// A linear ID / index of this clip-scroll node. Used as a reference to
/// pass to shaders, to allow them to fetch a given clip-scroll node.
@ -135,15 +136,15 @@ impl ClipScrollNode {
) -> Self {
ClipScrollNode {
local_viewport_rect: *rect,
world_viewport_transform: LayerToWorldTransform::identity(),
world_content_transform: LayerToWorldTransform::identity(),
world_viewport_transform: LayerToWorldFastTransform::identity(),
world_content_transform: LayerToWorldFastTransform::identity(),
parent: parent_id,
children: Vec::new(),
pipeline_id,
node_type: node_type,
invertible: true,
coordinate_system_id: CoordinateSystemId(0),
coordinate_system_relative_transform: TransformOrOffset::zero(),
coordinate_system_relative_transform: LayerFastTransform::identity(),
node_data_index: ClipScrollNodeIndex(0),
}
}
@ -177,10 +178,12 @@ impl ClipScrollNode {
pipeline_id: PipelineId,
) -> Self {
let identity = LayoutTransform::identity();
let source_perspective = source_perspective.map_or_else(
LayoutFastTransform::identity, |perspective| perspective.into());
let info = ReferenceFrameInfo {
resolved_transform: LayerTransform::identity(),
resolved_transform: LayerFastTransform::identity(),
source_transform: source_transform.unwrap_or(PropertyBinding::Value(identity)),
source_perspective: source_perspective.unwrap_or(identity),
source_perspective: source_perspective,
origin_in_parent_reference_frame,
invertible: true,
};
@ -258,8 +261,8 @@ impl ClipScrollNode {
pub fn mark_uninvertible(&mut self) {
self.invertible = false;
self.world_content_transform = LayerToWorldTransform::identity();
self.world_viewport_transform = LayerToWorldTransform::identity();
self.world_content_transform = LayerToWorldFastTransform::identity();
self.world_viewport_transform = LayerToWorldFastTransform::identity();
}
pub fn push_gpu_node_data(&mut self, node_data: &mut Vec<ClipScrollNodeData>) {
@ -274,7 +277,7 @@ impl ClipScrollNode {
TransformedRectKind::Complex
};
let data = ClipScrollNodeData {
transform: self.world_content_transform,
transform: self.world_content_transform.into(),
transform_kind: transform_kind as u32 as f32,
padding: [0.0; 3],
};
@ -303,9 +306,9 @@ impl ClipScrollNode {
self.update_transform(state, next_coordinate_system_id, scene_properties);
// If this node is a reference frame, we check if the determinant is 0, which means it
// has a non-invertible matrix. For non-reference-frames we assume that they will
// produce only additional translations which should be invertible.
// If this node is a reference frame, we check if it has a non-invertible matrix.
// For non-reference-frames we assume that they will produce only additional
// translations which should be invertible.
match self.node_type {
NodeType::ReferenceFrame(info) if !info.invertible => {
self.mark_uninvertible();
@ -362,7 +365,7 @@ impl ClipScrollNode {
let mut clip_chain = clip_chains[state.parent_clip_chain_index.0].new_with_added_node(
work_item,
self.coordinate_system_relative_transform.apply(&local_outer_rect),
self.coordinate_system_relative_transform.transform_rect(&local_outer_rect),
screen_outer_rect,
screen_inner_rect,
);
@ -398,7 +401,7 @@ impl ClipScrollNode {
// provided by our own sticky positioning.
let accumulated_offset = state.parent_accumulated_scroll_offset + sticky_offset;
self.world_viewport_transform = if accumulated_offset != LayerVector2D::zero() {
state.parent_reference_frame_transform.pre_translate(accumulated_offset.to_3d())
state.parent_reference_frame_transform.pre_translate(&accumulated_offset)
} else {
state.parent_reference_frame_transform
};
@ -407,7 +410,7 @@ impl ClipScrollNode {
// whatever scrolling offset we supply as well.
let scroll_offset = self.scroll_offset();
self.world_content_transform = if scroll_offset != LayerVector2D::zero() {
self.world_viewport_transform.pre_translate(scroll_offset.to_3d())
self.world_viewport_transform.pre_translate(&scroll_offset)
} else {
self.world_viewport_transform
};
@ -437,12 +440,10 @@ impl ClipScrollNode {
// Resolve the transform against any property bindings.
let source_transform = scene_properties.resolve_layout_transform(&info.source_transform);
info.resolved_transform = LayerTransform::create_translation(
info.origin_in_parent_reference_frame.x,
info.origin_in_parent_reference_frame.y,
0.0
).pre_mul(&source_transform)
.pre_mul(&info.source_perspective);
info.resolved_transform =
LayerFastTransform::with_vector(info.origin_in_parent_reference_frame)
.pre_mul(&source_transform.into())
.pre_mul(&info.source_perspective);
// The transformation for this viewport in world coordinates is the transformation for
// our parent reference frame, plus any accumulated scrolling offsets from nodes
@ -450,12 +451,14 @@ impl ClipScrollNode {
// whatever local transformation this reference frame provides. This can be combined
// with the local_viewport_rect to get its position in world space.
let relative_transform = info.resolved_transform
.post_translate(state.parent_accumulated_scroll_offset.to_3d());
self.world_viewport_transform = state.parent_reference_frame_transform
.pre_mul(&relative_transform.with_destination::<LayerPixel>());
.post_translate(state.parent_accumulated_scroll_offset)
.to_transform()
.with_destination::<LayerPixel>();
self.world_viewport_transform =
state.parent_reference_frame_transform.pre_mul(&relative_transform.into());
self.world_content_transform = self.world_viewport_transform;
info.invertible = relative_transform.determinant() != 0.0;
info.invertible = self.world_viewport_transform.is_invertible();
if !info.invertible {
return;
}
@ -465,7 +468,7 @@ impl ClipScrollNode {
match state.coordinate_system_relative_transform.update(relative_transform) {
Some(offset) => self.coordinate_system_relative_transform = offset,
None => {
self.coordinate_system_relative_transform = TransformOrOffset::zero();
self.coordinate_system_relative_transform = LayerFastTransform::identity();
state.current_coordinate_system_id = *next_coordinate_system_id;
next_coordinate_system_id.advance();
}
@ -844,14 +847,14 @@ impl ScrollFrameInfo {
pub struct ReferenceFrameInfo {
/// The transformation that establishes this reference frame, relative to the parent
/// reference frame. The origin of the reference frame is included in the transformation.
pub resolved_transform: LayerTransform,
pub resolved_transform: LayerFastTransform,
/// The source transform and perspective matrices provided by the stacking context
/// that forms this reference frame. We maintain the property binding information
/// here so that we can resolve the animated transform and update the tree each
/// frame.
pub source_transform: PropertyBinding<LayoutTransform>,
pub source_perspective: LayoutTransform,
pub source_perspective: LayoutFastTransform,
/// The original, not including the transform and relative to the parent reference frame,
/// origin of this reference frame. This is already rolled into the `transform' property, but

Просмотреть файл

@ -3,8 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ClipId, DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint, LayerRect};
use api::{LayerToWorldTransform, LayerVector2D, PipelineId, ScrollClamping, ScrollEventPhase};
use api::{ScrollLocation, ScrollNodeState, WorldPoint};
use api::{LayerVector2D, PipelineId, ScrollClamping, ScrollEventPhase, ScrollLocation};
use api::{ScrollNodeState, WorldPoint};
use clip::{ClipChain, ClipSourcesHandle, ClipStore};
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollFrameInfo, StickyFrameInfo};
use gpu_cache::GpuCache;
@ -13,7 +13,7 @@ use internal_types::{FastHashMap, FastHashSet};
use print_tree::{PrintTree, PrintTreePrinter};
use resource_cache::ResourceCache;
use scene::SceneProperties;
use util::TransformOrOffset;
use util::{LayerFastTransform, LayerToWorldFastTransform};
pub type ScrollStates = FastHashMap<ExternalScrollId, ScrollFrameInfo>;
@ -88,7 +88,7 @@ pub struct ClipScrollTree {
#[derive(Clone)]
pub struct TransformUpdateState {
pub parent_reference_frame_transform: LayerToWorldTransform,
pub parent_reference_frame_transform: LayerToWorldFastTransform,
pub parent_accumulated_scroll_offset: LayerVector2D,
pub nearest_scrolling_ancestor_offset: LayerVector2D,
pub nearest_scrolling_ancestor_viewport: LayerRect,
@ -103,7 +103,7 @@ pub struct TransformUpdateState {
pub current_coordinate_system_id: CoordinateSystemId,
/// Transform from the coordinate system that started this compatible coordinate system.
pub coordinate_system_relative_transform: TransformOrOffset,
pub coordinate_system_relative_transform: LayerFastTransform,
/// True if this node is transformed by an invertible transform. If not, display items
/// transformed by this node will not be displayed and display items not transformed by this
@ -329,17 +329,13 @@ impl ClipScrollTree {
let root_reference_frame_id = self.root_reference_frame_id();
let mut state = TransformUpdateState {
parent_reference_frame_transform: LayerToWorldTransform::create_translation(
pan.x,
pan.y,
0.0,
),
parent_reference_frame_transform: LayerVector2D::new(pan.x, pan.y).into(),
parent_accumulated_scroll_offset: LayerVector2D::zero(),
nearest_scrolling_ancestor_offset: LayerVector2D::zero(),
nearest_scrolling_ancestor_viewport: LayerRect::zero(),
parent_clip_chain_index: ClipChainIndex(0),
current_coordinate_system_id: CoordinateSystemId::root(),
coordinate_system_relative_transform: TransformOrOffset::zero(),
coordinate_system_relative_transform: LayerFastTransform::identity(),
invertible: true,
};
let mut next_coordinate_system_id = state.current_coordinate_system_id.next();

Просмотреть файл

@ -6,11 +6,10 @@ use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipId,
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale, DeviceUintPoint};
use api::{DeviceUintRect, DeviceUintSize, DocumentLayer, Epoch, ExtendMode, ExternalScrollId};
use api::{FontRenderMode, GlyphInstance, GlyphOptions, GradientStop, ImageKey, ImageRendering};
use api::{ItemRange, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize, LayerTransform};
use api::{LayerVector2D, LayoutTransform, LayoutVector2D, LineOrientation, LineStyle, LocalClip};
use api::{PipelineId, PremultipliedColorF, PropertyBinding, RepeatMode, ScrollSensitivity, Shadow};
use api::{TexelRect, TileOffset, TransformStyle, WorldPoint, WorldToLayerTransform, YuvColorSpace};
use api::YuvData;
use api::{ItemRange, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize, LayerVector2D};
use api::{LayoutTransform, LayoutVector2D, LineOrientation, LineStyle, LocalClip, PipelineId};
use api::{PremultipliedColorF, PropertyBinding, RepeatMode, ScrollSensitivity, Shadow, TexelRect};
use api::{TileOffset, TransformStyle, WorldPoint, YuvColorSpace, YuvData};
use app_units::Au;
use border::ImageBorderSegment;
use clip::{ClipChain, ClipRegion, ClipSource, ClipSources, ClipStore};
@ -19,12 +18,12 @@ use clip_scroll_tree::{ClipScrollTree, ClipChainIndex};
use euclid::{SideOffsets2D, vec2};
use frame::{FrameId, ClipIdToIndexMapper};
use glyph_rasterizer::FontInstance;
use gpu_cache::{GpuCache, GpuCacheHandle};
use gpu_cache::GpuCache;
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, PictureType};
use hit_test::{HitTester, HitTestingItem, HitTestingRun};
use internal_types::{FastHashMap, FastHashSet};
use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface};
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, GradientPrimitiveCpu};
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient, CachedGradientIndex};
use prim_store::{ImageCacheKey, ImagePrimitiveCpu, ImageSource, PrimitiveContainer};
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveRun, PrimitiveStore};
use prim_store::{ScrollNodeAndClipChain, TextRunPrimitiveCpu};
@ -35,7 +34,7 @@ use scene::{ScenePipeline, SceneProperties};
use std::{mem, usize, f32};
use tiling::{CompositeOps, Frame, RenderPass, RenderTargetKind};
use tiling::{RenderPassKind, RenderTargetContext, ScrollbarPrimitive};
use util::{self, MaxRect, pack_as_float, RectHelpers, recycle_vec};
use util::{self, MaxRect, RectHelpers, WorldToLayerFastTransform, recycle_vec};
#[derive(Debug)]
pub struct ScrollbarInfo(pub ClipId, pub LayerRect);
@ -86,6 +85,7 @@ pub struct FrameBuilder {
pub clip_store: ClipStore,
hit_testing_runs: Vec<HitTestingRun>,
pub config: FrameBuilderConfig,
pub cached_gradients: Vec<CachedGradient>,
// A stack of the current shadow primitives.
// The sub-Vec stores a buffer of fast-path primitives to be appended on pop.
@ -124,6 +124,7 @@ pub struct FrameState<'a> {
pub local_clip_rects: &'a mut Vec<LayerRect>,
pub resource_cache: &'a mut ResourceCache,
pub gpu_cache: &'a mut GpuCache,
pub cached_gradients: &'a mut [CachedGradient],
}
pub struct PictureContext<'a> {
@ -133,7 +134,7 @@ pub struct PictureContext<'a> {
pub original_reference_frame_id: Option<ClipId>,
pub display_list: &'a BuiltDisplayList,
pub draw_text_transformed: bool,
pub inv_world_transform: Option<WorldToLayerTransform>,
pub inv_world_transform: Option<WorldToLayerFastTransform>,
}
pub struct PictureState {
@ -173,6 +174,7 @@ impl FrameBuilder {
FrameBuilder {
hit_testing_runs: Vec::new(),
shadow_prim_stack: Vec::new(),
cached_gradients: Vec::new(),
pending_shadow_contents: Vec::new(),
scrollbar_prims: Vec::new(),
reference_frame_stack: Vec::new(),
@ -201,6 +203,7 @@ impl FrameBuilder {
FrameBuilder {
hit_testing_runs: recycle_vec(self.hit_testing_runs),
shadow_prim_stack: recycle_vec(self.shadow_prim_stack),
cached_gradients: recycle_vec(self.cached_gradients),
pending_shadow_contents: recycle_vec(self.pending_shadow_contents),
scrollbar_prims: recycle_vec(self.scrollbar_prims),
reference_frame_stack: recycle_vec(self.reference_frame_stack),
@ -673,11 +676,8 @@ impl FrameBuilder {
let root_id = clip_scroll_tree.root_reference_frame_id();
if let Some(root_node) = clip_scroll_tree.nodes.get_mut(&root_id) {
if let NodeType::ReferenceFrame(ref mut info) = root_node.node_type {
info.resolved_transform = LayerTransform::create_translation(
viewport_offset.x,
viewport_offset.y,
0.0,
);
info.resolved_transform =
LayerVector2D::new(viewport_offset.x, viewport_offset.y).into();
}
}
}
@ -1236,6 +1236,53 @@ impl FrameBuilder {
}
}
fn add_gradient_impl(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
start_point: LayerPoint,
end_point: LayerPoint,
stops: ItemRange<GradientStop>,
stops_count: usize,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
) {
// Try to ensure that if the gradient is specified in reverse, then so long as the stops
// are also supplied in reverse that the rendered result will be equivalent. To do this,
// a reference orientation for the gradient line must be chosen, somewhat arbitrarily, so
// just designate the reference orientation as start < end. Aligned gradient rendering
// manages to produce the same result regardless of orientation, so don't worry about
// reversing in that case.
let reverse_stops = start_point.x > end_point.x ||
(start_point.x == end_point.x && start_point.y > end_point.y);
// To get reftests exactly matching with reverse start/end
// points, it's necessary to reverse the gradient
// line in some cases.
let (sp, ep) = if reverse_stops {
(end_point, start_point)
} else {
(start_point, end_point)
};
let prim = BrushPrimitive::new(
BrushKind::LinearGradient {
stops_range: stops,
stops_count,
extend_mode,
reverse_stops,
start_point: sp,
end_point: ep,
gradient_index,
},
None,
);
let prim = PrimitiveContainer::Brush(prim);
self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
}
pub fn add_gradient(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
@ -1248,62 +1295,40 @@ impl FrameBuilder {
tile_size: LayerSize,
tile_spacing: LayerSize,
) {
let tile_repeat = tile_size + tile_spacing;
let is_not_tiled = tile_repeat.width >= info.rect.size.width &&
tile_repeat.height >= info.rect.size.height;
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());
let aligned_and_fills_rect = (start_point.x == end_point.x &&
start_point.y.min(end_point.y) <= 0.0 &&
start_point.y.max(end_point.y) >= info.rect.size.height) ||
(start_point.y == end_point.y && start_point.x.min(end_point.x) <= 0.0 &&
start_point.x.max(end_point.x) >= info.rect.size.width);
let prim_infos = info.decompose(
tile_size,
tile_spacing,
64 * 64,
);
// Fast path for clamped, axis-aligned gradients, with gradient lines intersecting all of rect:
let aligned = extend_mode == ExtendMode::Clamp && is_not_tiled && aligned_and_fills_rect;
// Try to ensure that if the gradient is specified in reverse, then so long as the stops
// are also supplied in reverse that the rendered result will be equivalent. To do this,
// a reference orientation for the gradient line must be chosen, somewhat arbitrarily, so
// just designate the reference orientation as start < end. Aligned gradient rendering
// manages to produce the same result regardless of orientation, so don't worry about
// reversing in that case.
let reverse_stops = !aligned &&
(start_point.x > end_point.x ||
(start_point.x == end_point.x && start_point.y > end_point.y));
// To get reftests exactly matching with reverse start/end
// points, it's necessary to reverse the gradient
// line in some cases.
let (sp, ep) = if reverse_stops {
(end_point, start_point)
if prim_infos.is_empty() {
self.add_gradient_impl(
clip_and_scroll,
info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
);
} else {
(start_point, end_point)
};
let gradient_cpu = GradientPrimitiveCpu {
stops_range: stops,
stops_count,
extend_mode,
reverse_stops,
gpu_blocks: [
[sp.x, sp.y, ep.x, ep.y].into(),
[
tile_size.width,
tile_size.height,
tile_repeat.width,
tile_repeat.height,
].into(),
[pack_as_float(extend_mode as u32), 0.0, 0.0, 0.0].into(),
],
};
let prim = if aligned {
PrimitiveContainer::AlignedGradient(gradient_cpu)
} else {
PrimitiveContainer::AngleGradient(gradient_cpu)
};
self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
for prim_info in prim_infos {
self.add_gradient_impl(
clip_and_scroll,
&prim_info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
);
}
}
}
fn add_radial_gradient_impl(
@ -1317,17 +1342,18 @@ impl FrameBuilder {
ratio_xy: f32,
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
) {
let prim = BrushPrimitive::new(
BrushKind::RadialGradient {
stops_range: stops,
extend_mode,
stops_handle: GpuCacheHandle::new(),
start_center,
end_center,
start_radius,
end_radius,
ratio_xy,
gradient_index,
},
None,
);
@ -1354,6 +1380,9 @@ impl FrameBuilder {
tile_size: LayerSize,
tile_spacing: LayerSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());
let prim_infos = info.decompose(
tile_size,
tile_spacing,
@ -1371,6 +1400,7 @@ impl FrameBuilder {
ratio_xy,
stops,
extend_mode,
gradient_index,
);
} else {
for prim_info in prim_infos {
@ -1384,6 +1414,7 @@ impl FrameBuilder {
ratio_xy,
stops,
extend_mode,
gradient_index,
);
}
}
@ -1703,6 +1734,7 @@ impl FrameBuilder {
local_clip_rects,
resource_cache,
gpu_cache,
cached_gradients: &mut self.cached_gradients,
};
let pic_context = PictureContext {
@ -1871,6 +1903,7 @@ impl FrameBuilder {
clip_scroll_tree,
use_dual_source_blending,
node_data: &node_data,
cached_gradients: &self.cached_gradients,
};
pass.build(

Просмотреть файл

@ -3,13 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{BorderRadius, ClipId, ClipMode, HitTestFlags, HitTestItem, HitTestResult, ItemTag};
use api::{LayerPoint, LayerPrimitiveInfo, LayerRect, LayerToWorldTransform, LocalClip, PipelineId};
use api::WorldPoint;
use api::{LayerPoint, LayerPrimitiveInfo, LayerRect, LocalClip, PipelineId, WorldPoint};
use clip::{ClipSource, ClipStore, Contains, rounded_rectangle_contains_point};
use clip_scroll_node::{ClipScrollNode, NodeType};
use clip_scroll_tree::{ClipChainIndex, ClipScrollTree};
use internal_types::FastHashMap;
use prim_store::ScrollNodeAndClipChain;
use util::LayerToWorldFastTransform;
/// A copy of important clip scroll node data to use during hit testing. This a copy of
/// data from the ClipScrollTree that will persist as a new frame is under construction,
@ -20,10 +20,10 @@ pub struct HitTestClipScrollNode {
regions: Vec<HitTestRegion>,
/// World transform for content transformed by this node.
world_content_transform: LayerToWorldTransform,
world_content_transform: LayerToWorldFastTransform,
/// World viewport transform for content transformed by this node.
world_viewport_transform: LayerToWorldTransform,
world_viewport_transform: LayerToWorldFastTransform,
/// Origin of the viewport of the node, used to calculate node-relative positions.
node_origin: LayerPoint,

Просмотреть файл

@ -7,7 +7,7 @@ use api::{LayerRect, LayerToWorldScale, LayerVector2D, MixBlendMode, PipelineId}
use api::{PremultipliedColorF, Shadow};
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowCacheKey};
use frame_builder::{FrameContext, FrameState, PictureState};
use gpu_cache::GpuDataRequest;
use gpu_cache::{GpuCacheHandle, GpuDataRequest};
use gpu_types::{BrushImageKind, PictureType};
use prim_store::{BrushKind, BrushPrimitive, PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
use prim_store::ScrollNodeAndClipChain;
@ -88,6 +88,10 @@ pub enum PictureKind {
// rendering context.
reference_frame_id: ClipId,
real_local_rect: LayerRect,
// An optional cache handle for storing extra data
// in the GPU cache, depending on the type of
// picture.
extra_gpu_data_handle: GpuCacheHandle,
},
}
@ -217,6 +221,7 @@ impl PicturePrimitive {
frame_output_pipeline_id,
reference_frame_id,
real_local_rect: LayerRect::zero(),
extra_gpu_data_handle: GpuCacheHandle::new(),
},
pipeline_id,
cull_children: true,
@ -333,6 +338,7 @@ impl PicturePrimitive {
match self.kind {
PictureKind::Image {
ref mut secondary_render_task_id,
ref mut extra_gpu_data_handle,
composite_mode,
..
} => {
@ -429,6 +435,15 @@ impl PicturePrimitive {
pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
} else {
if let FilterOp::ColorMatrix(m) = filter {
if let Some(mut request) = frame_state.gpu_cache.request(extra_gpu_data_handle) {
for i in 0..5 {
request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
}
}
}
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.size),
prim_index,
@ -594,17 +609,10 @@ impl PicturePrimitive {
// making this more efficient for the common case.
match self.kind {
PictureKind::TextShadow { .. } => {
for _ in 0 .. 5 {
request.push([0.0; 4]);
}
request.push([0.0; 4]);
}
PictureKind::Image { composite_mode, .. } => {
match composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::ColorMatrix(m))) => {
for i in 0..5 {
request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
}
}
Some(PictureCompositeMode::Filter(filter)) => {
let amount = match filter {
FilterOp::Contrast(amount) => amount,
@ -623,23 +631,14 @@ impl PicturePrimitive {
};
request.push([amount, 1.0 - amount, 0.0, 0.0]);
for _ in 0 .. 4 {
request.push([0.0; 4]);
}
}
_ => {
for _ in 0 .. 5 {
request.push([0.0; 4]);
}
request.push([0.0; 4]);
}
}
}
PictureKind::BoxShadow { color, .. } => {
request.push(color.premultiplied());
for _ in 0 .. 4 {
request.push([0.0; 4]);
}
}
}
}

Просмотреть файл

@ -6,7 +6,7 @@ use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipId, ClipMode, ColorF, C
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode};
use api::{GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag};
use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D, LineOrientation};
use api::{LineStyle, PremultipliedColorF, WorldToLayerTransform, YuvColorSpace, YuvFormat};
use api::{LineStyle, PremultipliedColorF, YuvColorSpace, YuvFormat};
use border::{BorderCornerInstance, BorderEdgeKind};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId};
use clip_scroll_node::ClipScrollNode;
@ -25,11 +25,11 @@ use resource_cache::{CacheItem, ImageProperties, ImageRequest, ResourceCache};
use segment::SegmentBuilder;
use std::{mem, usize};
use std::rc::Rc;
use util::{MatrixHelpers, calculate_screen_bounding_rect, pack_as_float};
use util::recycle_vec;
use util::{MatrixHelpers, WorldToLayerFastTransform, calculate_screen_bounding_rect};
use util::{pack_as_float, recycle_vec};
const MIN_BRUSH_SPLIT_AREA: f32 = 128.0 * 128.0;
const MIN_BRUSH_SPLIT_AREA: f32 = 256.0 * 256.0;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ScrollNodeAndClipChain {
@ -69,9 +69,20 @@ impl PrimitiveOpacity {
is_opaque: alpha == 1.0,
}
}
}
pub fn accumulate(&mut self, alpha: f32) {
self.is_opaque = self.is_opaque && alpha == 1.0;
#[derive(Debug, Copy, Clone)]
pub struct CachedGradientIndex(pub usize);
pub struct CachedGradient {
pub handle: GpuCacheHandle,
}
impl CachedGradient {
pub fn new() -> CachedGradient {
CachedGradient {
handle: GpuCacheHandle::new(),
}
}
}
@ -124,8 +135,6 @@ pub enum PrimitiveKind {
TextRun,
Image,
Border,
AlignedGradient,
AngleGradient,
Picture,
Brush,
}
@ -211,14 +220,23 @@ pub enum BrushKind {
image_rendering: ImageRendering,
},
RadialGradient {
gradient_index: CachedGradientIndex,
stops_range: ItemRange<GradientStop>,
extend_mode: ExtendMode,
stops_handle: GpuCacheHandle,
start_center: LayerPoint,
end_center: LayerPoint,
start_radius: f32,
end_radius: f32,
ratio_xy: f32,
},
LinearGradient {
gradient_index: CachedGradientIndex,
stops_range: ItemRange<GradientStop>,
stops_count: usize,
extend_mode: ExtendMode,
reverse_stops: bool,
start_point: LayerPoint,
end_point: LayerPoint,
}
}
@ -229,7 +247,8 @@ impl BrushKind {
BrushKind::Picture |
BrushKind::Image { .. } |
BrushKind::YuvImage { .. } |
BrushKind::RadialGradient { .. } => true,
BrushKind::RadialGradient { .. } |
BrushKind::LinearGradient { .. } => true,
BrushKind::Mask { .. } |
BrushKind::Clear |
@ -359,6 +378,20 @@ impl BrushPrimitive {
0.0,
]);
}
BrushKind::LinearGradient { start_point, end_point, extend_mode, .. } => {
request.push([
start_point.x,
start_point.y,
end_point.x,
end_point.y,
]);
request.push([
pack_as_float(extend_mode as u32),
0.0,
0.0,
0.0,
]);
}
BrushKind::RadialGradient { start_center, end_center, start_radius, end_radius, ratio_xy, extend_mode, .. } => {
request.push([
start_center.x,
@ -432,46 +465,6 @@ impl ToGpuBlocks for BorderPrimitiveCpu {
}
}
#[derive(Debug)]
pub struct GradientPrimitiveCpu {
pub stops_range: ItemRange<GradientStop>,
pub stops_count: usize,
pub extend_mode: ExtendMode,
pub reverse_stops: bool,
pub gpu_blocks: [GpuBlockData; 3],
}
impl GradientPrimitiveCpu {
fn build_gpu_blocks_for_aligned(
&self,
display_list: &BuiltDisplayList,
mut request: GpuDataRequest,
) -> PrimitiveOpacity {
let mut opacity = PrimitiveOpacity::opaque();
request.extend_from_slice(&self.gpu_blocks);
let src_stops = display_list.get(self.stops_range);
for src in src_stops {
request.push(src.color.premultiplied());
request.push([src.offset, 0.0, 0.0, 0.0]);
opacity.accumulate(src.color.a);
}
opacity
}
fn build_gpu_blocks_for_angle_radial(
&self,
display_list: &BuiltDisplayList,
mut request: GpuDataRequest,
) {
request.extend_from_slice(&self.gpu_blocks);
let gradient_builder = GradientGpuBlockBuilder::new(self.stops_range, display_list);
gradient_builder.build(self.reverse_stops, &mut request);
}
}
// The gradient entry index for the first color stop
pub const GRADIENT_DATA_FIRST_STOP: usize = 0;
// The gradient entry index for the last color stop
@ -670,7 +663,7 @@ impl TextRunPrimitiveCpu {
pub fn get_font(
&self,
device_pixel_scale: DevicePixelScale,
transform: Option<&LayerToWorldTransform>,
transform: Option<LayerToWorldTransform>,
) -> FontInstance {
let mut font = self.font.clone();
font.size = font.size.scale_by(device_pixel_scale.0);
@ -678,7 +671,7 @@ impl TextRunPrimitiveCpu {
if transform.has_perspective_component() || !transform.has_2d_inverse() {
font.render_mode = font.render_mode.limit_by(FontRenderMode::Alpha);
} else {
font.transform = FontTransform::from(transform).quantize();
font.transform = FontTransform::from(&transform).quantize();
}
}
font
@ -688,7 +681,7 @@ impl TextRunPrimitiveCpu {
&mut self,
resource_cache: &mut ResourceCache,
device_pixel_scale: DevicePixelScale,
transform: Option<&LayerToWorldTransform>,
transform: Option<LayerToWorldTransform>,
display_list: &BuiltDisplayList,
gpu_cache: &mut GpuCache,
) {
@ -937,8 +930,6 @@ pub enum PrimitiveContainer {
TextRun(TextRunPrimitiveCpu),
Image(ImagePrimitiveCpu),
Border(BorderPrimitiveCpu),
AlignedGradient(GradientPrimitiveCpu),
AngleGradient(GradientPrimitiveCpu),
Picture(PicturePrimitive),
Brush(BrushPrimitive),
}
@ -949,7 +940,6 @@ pub struct PrimitiveStore {
pub cpu_text_runs: Vec<TextRunPrimitiveCpu>,
pub cpu_pictures: Vec<PicturePrimitive>,
pub cpu_images: Vec<ImagePrimitiveCpu>,
pub cpu_gradients: Vec<GradientPrimitiveCpu>,
pub cpu_metadata: Vec<PrimitiveMetadata>,
pub cpu_borders: Vec<BorderPrimitiveCpu>,
}
@ -962,7 +952,6 @@ impl PrimitiveStore {
cpu_text_runs: Vec::new(),
cpu_pictures: Vec::new(),
cpu_images: Vec::new(),
cpu_gradients: Vec::new(),
cpu_borders: Vec::new(),
}
}
@ -974,7 +963,6 @@ impl PrimitiveStore {
cpu_text_runs: recycle_vec(self.cpu_text_runs),
cpu_pictures: recycle_vec(self.cpu_pictures),
cpu_images: recycle_vec(self.cpu_images),
cpu_gradients: recycle_vec(self.cpu_gradients),
cpu_borders: recycle_vec(self.cpu_borders),
}
}
@ -1015,6 +1003,7 @@ impl PrimitiveStore {
BrushKind::Image { .. } => PrimitiveOpacity::translucent(),
BrushKind::YuvImage { .. } => PrimitiveOpacity::opaque(),
BrushKind::RadialGradient { .. } => PrimitiveOpacity::translucent(),
BrushKind::LinearGradient { .. } => PrimitiveOpacity::translucent(),
BrushKind::Picture => {
// TODO(gw): This is not currently used. In the future
// we should detect opaque pictures.
@ -1077,29 +1066,6 @@ impl PrimitiveStore {
self.cpu_borders.push(border_cpu);
metadata
}
PrimitiveContainer::AlignedGradient(gradient_cpu) => {
let metadata = PrimitiveMetadata {
opacity: PrimitiveOpacity::translucent(),
prim_kind: PrimitiveKind::AlignedGradient,
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_gradients.len()),
..base_metadata
};
self.cpu_gradients.push(gradient_cpu);
metadata
}
PrimitiveContainer::AngleGradient(gradient_cpu) => {
let metadata = PrimitiveMetadata {
// TODO: calculate if the gradient is actually opaque
opacity: PrimitiveOpacity::translucent(),
prim_kind: PrimitiveKind::AngleGradient,
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_gradients.len()),
..base_metadata
};
self.cpu_gradients.push(gradient_cpu);
metadata
}
};
self.cpu_metadata.push(metadata);
@ -1146,7 +1112,7 @@ impl PrimitiveStore {
let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0];
// The transform only makes sense for screen space rasterization
let transform = if pic_context.draw_text_transformed {
Some(&prim_run_context.scroll_node.world_content_transform)
Some(prim_run_context.scroll_node.world_content_transform.into())
} else {
None
};
@ -1304,7 +1270,8 @@ impl PrimitiveStore {
);
}
}
BrushKind::RadialGradient { ref mut stops_handle, stops_range, .. } => {
BrushKind::RadialGradient { gradient_index, stops_range, .. } => {
let stops_handle = &mut frame_state.cached_gradients[gradient_index.0].handle;
if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
let gradient_builder = GradientGpuBlockBuilder::new(
stops_range,
@ -1316,6 +1283,19 @@ impl PrimitiveStore {
);
}
}
BrushKind::LinearGradient { gradient_index, stops_range, reverse_stops, .. } => {
let stops_handle = &mut frame_state.cached_gradients[gradient_index.0].handle;
if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
let gradient_builder = GradientGpuBlockBuilder::new(
stops_range,
pic_context.display_list,
);
gradient_builder.build(
reverse_stops,
&mut request,
);
}
}
BrushKind::Mask { .. } |
BrushKind::Solid { .. } |
BrushKind::Clear |
@ -1323,8 +1303,6 @@ impl PrimitiveStore {
BrushKind::Picture { .. } => {}
}
}
PrimitiveKind::AlignedGradient |
PrimitiveKind::AngleGradient => {}
}
// Mark this GPU resource as required for this frame.
@ -1342,20 +1320,6 @@ impl PrimitiveStore {
let image = &self.cpu_images[metadata.cpu_prim_index.0];
image.write_gpu_blocks(request);
}
PrimitiveKind::AlignedGradient => {
let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0];
metadata.opacity = gradient.build_gpu_blocks_for_aligned(
pic_context.display_list,
request,
);
}
PrimitiveKind::AngleGradient => {
let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0];
gradient.build_gpu_blocks_for_angle_radial(
pic_context.display_list,
request,
);
}
PrimitiveKind::TextRun => {
let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
text.write_gpu_blocks(&mut request);
@ -1471,14 +1435,14 @@ impl PrimitiveStore {
let local_clip_rect = if clip_item.scroll_node_data_index == prim_run_context.scroll_node.node_data_index {
local_clip_rect
} else {
let clip_transform_data = &frame_context
.node_data[clip_item.scroll_node_data_index.0 as usize];
let clip_transform = frame_context
.node_data[clip_item.scroll_node_data_index.0 as usize]
.transform;
let prim_transform = &prim_run_context.scroll_node.world_content_transform;
let relative_transform = prim_transform
.inverse()
.unwrap_or(WorldToLayerTransform::identity())
.pre_mul(&clip_transform_data.transform);
.unwrap_or(WorldToLayerFastTransform::identity())
.pre_mul(&clip_transform.into());
relative_transform.transform_rect(&local_clip_rect)
};
@ -2061,8 +2025,7 @@ fn get_local_clip_rect_for_nodes(
);
match local_rect {
Some(local_rect) =>
Some(scroll_node.coordinate_system_relative_transform.unapply(&local_rect)),
Some(local_rect) => scroll_node.coordinate_system_relative_transform.unapply(&local_rect),
None => None,
}
}

Просмотреть файл

@ -1007,6 +1007,9 @@ impl RenderBackend {
}
};
let msg_update = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates());
self.result_tx.send(msg_update).unwrap();
let msg_publish = ResultMsg::PublishDocument(
id,
render_doc,

Просмотреть файл

@ -83,6 +83,10 @@ const GPU_CACHE_RESIZE_TEST: bool = false;
/// Number of GPU blocks per UV rectangle provided for an image.
pub const BLOCKS_PER_UV_RECT: usize = 2;
const GPU_TAG_BRUSH_LINEAR_GRADIENT: GpuProfileTag = GpuProfileTag {
label: "B_LinearGradient",
color: debug_colors::POWDERBLUE,
};
const GPU_TAG_BRUSH_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag {
label: "B_RadialGradient",
color: debug_colors::LIGHTPINK,
@ -151,14 +155,6 @@ const GPU_TAG_PRIM_TEXT_RUN: GpuProfileTag = GpuProfileTag {
label: "TextRun",
color: debug_colors::BLUE,
};
const GPU_TAG_PRIM_GRADIENT: GpuProfileTag = GpuProfileTag {
label: "Gradient",
color: debug_colors::YELLOW,
};
const GPU_TAG_PRIM_ANGLE_GRADIENT: GpuProfileTag = GpuProfileTag {
label: "AngleGradient",
color: debug_colors::POWDERBLUE,
};
const GPU_TAG_PRIM_BORDER_CORNER: GpuProfileTag = GpuProfileTag {
label: "BorderCorner",
color: debug_colors::DARKSLATEGREY,
@ -200,8 +196,6 @@ impl TransformBatchKind {
ImageBufferKind::TextureExternal => "Image (External)",
ImageBufferKind::Texture2DArray => "Image (Array)",
},
TransformBatchKind::AlignedGradient => "AlignedGradient",
TransformBatchKind::AngleGradient => "AngleGradient",
TransformBatchKind::BorderCorner => "BorderCorner",
TransformBatchKind::BorderEdge => "BorderEdge",
}
@ -213,8 +207,6 @@ impl TransformBatchKind {
TransformBatchKind::Image(..) => GPU_TAG_PRIM_IMAGE,
TransformBatchKind::BorderCorner => GPU_TAG_PRIM_BORDER_CORNER,
TransformBatchKind::BorderEdge => GPU_TAG_PRIM_BORDER_EDGE,
TransformBatchKind::AlignedGradient => GPU_TAG_PRIM_GRADIENT,
TransformBatchKind::AngleGradient => GPU_TAG_PRIM_ANGLE_GRADIENT,
}
}
}
@ -235,6 +227,7 @@ impl BatchKind {
BrushBatchKind::MixBlend { .. } => "Brush (Composite)",
BrushBatchKind::YuvImage(..) => "Brush (YuvImage)",
BrushBatchKind::RadialGradient => "Brush (RadialGradient)",
BrushBatchKind::LinearGradient => "Brush (LinearGradient)",
}
}
BatchKind::Transformable(_, batch_kind) => batch_kind.debug_name(),
@ -255,6 +248,7 @@ impl BatchKind {
BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND,
BrushBatchKind::YuvImage(..) => GPU_TAG_BRUSH_YUV_IMAGE,
BrushBatchKind::RadialGradient => GPU_TAG_BRUSH_RADIAL_GRADIENT,
BrushBatchKind::LinearGradient => GPU_TAG_BRUSH_LINEAR_GRADIENT,
}
}
BatchKind::Transformable(_, batch_kind) => batch_kind.gpu_sampler_tag(),
@ -1618,6 +1612,7 @@ pub struct Renderer {
brush_mix_blend: BrushShader,
brush_yuv_image: Vec<Option<BrushShader>>,
brush_radial_gradient: BrushShader,
brush_linear_gradient: BrushShader,
/// These are "cache clip shaders". These shaders are used to
/// draw clip instances into the cached clip mask. The results
@ -1638,8 +1633,6 @@ pub struct Renderer {
ps_image: Vec<Option<PrimitiveShader>>,
ps_border_corner: PrimitiveShader,
ps_border_edge: PrimitiveShader,
ps_gradient: PrimitiveShader,
ps_angle_gradient: PrimitiveShader,
ps_hw_composite: LazilyCompiledShader,
ps_split_composite: LazilyCompiledShader,
@ -1884,6 +1877,17 @@ impl Renderer {
options.precache_shaders)
};
let brush_linear_gradient = try!{
BrushShader::new("brush_linear_gradient",
&mut device,
if options.enable_dithering {
&dithering_feature
} else {
&[]
},
options.precache_shaders)
};
let cs_blur_a8 = try!{
LazilyCompiledShader::new(ShaderKind::Cache(VertexArrayKind::Blur),
"cs_blur",
@ -2030,28 +2034,6 @@ impl Renderer {
options.precache_shaders)
};
let ps_gradient = try!{
PrimitiveShader::new("ps_gradient",
&mut device,
if options.enable_dithering {
&dithering_feature
} else {
&[]
},
options.precache_shaders)
};
let ps_angle_gradient = try!{
PrimitiveShader::new("ps_angle_gradient",
&mut device,
if options.enable_dithering {
&dithering_feature
} else {
&[]
},
options.precache_shaders)
};
let ps_hw_composite = try!{
LazilyCompiledShader::new(ShaderKind::Primitive,
"ps_hardware_composite",
@ -2303,6 +2285,7 @@ impl Renderer {
brush_mix_blend,
brush_yuv_image,
brush_radial_gradient,
brush_linear_gradient,
cs_clip_rectangle,
cs_clip_border,
cs_clip_image,
@ -2311,8 +2294,6 @@ impl Renderer {
ps_image,
ps_border_corner,
ps_border_edge,
ps_gradient,
ps_angle_gradient,
ps_hw_composite,
ps_split_composite,
debug: debug_renderer,
@ -2892,7 +2873,9 @@ impl Renderer {
for &mut (_, RenderedDocument { ref mut frame, .. }) in &mut active_documents {
frame.profile_counters.reset_targets();
self.prepare_gpu_cache(frame);
assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id);
assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id,
"Received frame depends on a later GPU cache epoch ({:?}) than one we received last via `UpdateGpuCache` ({:?})",
frame.gpu_cache_frame_id, self.gpu_cache_frame_id);
self.draw_tile_frame(
frame,
@ -3272,6 +3255,15 @@ impl Renderer {
&mut self.renderer_errors,
);
}
BrushBatchKind::LinearGradient => {
self.brush_linear_gradient.bind(
&mut self.device,
key.blend_mode,
projection,
0,
&mut self.renderer_errors,
);
}
BrushBatchKind::YuvImage(image_buffer_kind, format, color_space) => {
let shader_index =
Renderer::get_yuv_shader_index(image_buffer_kind, format, color_space);
@ -3322,24 +3314,6 @@ impl Renderer {
&mut self.renderer_errors,
);
}
TransformBatchKind::AlignedGradient => {
self.ps_gradient.bind(
&mut self.device,
transform_kind,
projection,
0,
&mut self.renderer_errors,
);
}
TransformBatchKind::AngleGradient => {
self.ps_angle_gradient.bind(
&mut self.device,
transform_kind,
projection,
0,
&mut self.renderer_errors,
);
}
},
};
@ -4741,6 +4715,7 @@ impl Renderer {
self.brush_blend.deinit(&mut self.device);
self.brush_mix_blend.deinit(&mut self.device);
self.brush_radial_gradient.deinit(&mut self.device);
self.brush_linear_gradient.deinit(&mut self.device);
self.cs_clip_rectangle.deinit(&mut self.device);
self.cs_clip_image.deinit(&mut self.device);
self.cs_clip_border.deinit(&mut self.device);
@ -4766,8 +4741,6 @@ impl Renderer {
}
self.ps_border_corner.deinit(&mut self.device);
self.ps_border_edge.deinit(&mut self.device);
self.ps_gradient.deinit(&mut self.device);
self.ps_angle_gradient.deinit(&mut self.device);
self.ps_hw_composite.deinit(&mut self.device);
self.ps_split_composite.deinit(&mut self.device);
#[cfg(feature = "capture")]

Просмотреть файл

@ -16,7 +16,7 @@ use gpu_types::{ClipScrollNodeData, ClipScrollNodeIndex};
use gpu_types::{PrimitiveInstance};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{PictureKind};
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveStore};
use prim_store::{CachedGradient, PrimitiveIndex, PrimitiveKind, PrimitiveStore};
use prim_store::{BrushMaskKind, BrushKind, DeferredResolve, EdgeAaSegmentMask};
use profiler::FrameProfileCounters;
use render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind};
@ -46,6 +46,7 @@ pub struct RenderTargetContext<'a> {
pub clip_scroll_tree: &'a ClipScrollTree,
pub use_dual_source_blending: bool,
pub node_data: &'a [ClipScrollNodeData],
pub cached_gradients: &'a [CachedGradient],
}
#[cfg_attr(feature = "capture", derive(Serialize))]
@ -599,6 +600,7 @@ impl RenderTarget for AlphaRenderTarget {
BrushKind::Line { .. } |
BrushKind::YuvImage { .. } |
BrushKind::RadialGradient { .. } |
BrushKind::LinearGradient { .. } |
BrushKind::Image { .. } => {
unreachable!("bug: unexpected brush here");
}

Просмотреть файл

@ -3,10 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{BorderRadius, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
use api::{DevicePoint, DeviceRect, DeviceSize, LayerPoint, LayerRect, LayerSize};
use api::{LayerToWorldTransform, LayerTransform, LayerVector2D, WorldRect};
use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D};
use euclid::TypedTransform3D;
use api::{DevicePoint, DeviceRect, DeviceSize, LayerPixel, LayerPoint, LayerRect, LayerSize};
use api::{LayoutPixel, WorldPixel, WorldRect};
use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedPoint3D, TypedRect, TypedSize2D};
use euclid::{TypedTransform2D, TypedTransform3D, TypedVector2D};
use num_traits::Zero;
use std::{i32, f32};
@ -22,6 +22,7 @@ pub trait MatrixHelpers<Src, Dst> {
fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src>;
fn transform_kind(&self) -> TransformedRectKind;
fn is_simple_translation(&self) -> bool;
fn is_simple_2d_translation(&self) -> bool;
}
impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
@ -105,6 +106,14 @@ impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
self.m31.abs() < NEARLY_ZERO && self.m32.abs() < NEARLY_ZERO &&
self.m34.abs() < NEARLY_ZERO
}
fn is_simple_2d_translation(&self) -> bool {
if !self.is_simple_translation() {
return false;
}
self.m43.abs() < NEARLY_ZERO
}
}
pub trait RectHelpers<U>
@ -145,7 +154,7 @@ pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
}
pub fn calculate_screen_bounding_rect(
transform: &LayerToWorldTransform,
transform: &LayerToWorldFastTransform,
rect: &LayerRect,
device_pixel_scale: DevicePixelScale,
) -> DeviceIntRect {
@ -334,67 +343,189 @@ impl MaxRect for DeviceRect {
/// An enum that tries to avoid expensive transformation matrix calculations
/// when possible when dealing with non-perspective axis-aligned transformations.
#[derive(Debug, Clone)]
pub enum TransformOrOffset {
#[derive(Debug, Clone, Copy)]
pub enum FastTransform<Src, Dst> {
/// A simple offset, which can be used without doing any matrix math.
Offset(LayerVector2D),
Offset(TypedVector2D<f32, Src>),
/// A transformation with an inverse. If the inverse isn't present, this isn't a 2D
/// transformation, which means we need to fall back to using inverse_rect_footprint.
/// Since this operation is so expensive, we avoid it for the 2D case.
/// A 2D transformation with an inverse.
Transform {
transform: LayerTransform,
inverse: Option<LayerTransform>,
}
transform: TypedTransform3D<f32, Src, Dst>,
inverse: Option<TypedTransform3D<f32, Dst, Src>>,
is_2d: bool,
},
}
impl TransformOrOffset {
pub fn zero() -> TransformOrOffset {
TransformOrOffset::Offset(LayerVector2D::zero())
impl<Src, Dst> FastTransform<Src, Dst> {
pub fn identity() -> Self {
FastTransform::Offset(TypedVector2D::zero())
}
fn new_transform(transform: LayerTransform) -> TransformOrOffset {
if transform.is_2d() {
TransformOrOffset::Transform {
transform,
inverse: Some(transform.inverse().expect("Expected invertible matrix."))
pub fn with_vector(offset: TypedVector2D<f32, Src>) -> Self {
FastTransform::Offset(offset)
}
#[inline(always)]
pub fn with_transform(transform: TypedTransform3D<f32, Src, Dst>) -> Self {
if transform.is_simple_2d_translation() {
return FastTransform::Offset(TypedVector2D::new(transform.m41, transform.m42));
}
let inverse = transform.inverse();
let is_2d = transform.is_2d();
FastTransform::Transform { transform, inverse, is_2d}
}
pub fn to_transform(&self) -> TypedTransform3D<f32, Src, Dst> {
match *self {
FastTransform::Offset(offset) =>
TypedTransform3D::create_translation(offset.x, offset.y, 0.0),
FastTransform::Transform { transform, .. } => transform
}
}
pub fn is_invertible(&self) -> bool {
match *self {
FastTransform::Offset(..) => true,
FastTransform::Transform { ref inverse, .. } => inverse.is_some(),
}
}
#[inline(always)]
pub fn pre_mul<NewSrc>(
&self,
other: &FastTransform<NewSrc, Src>
) -> FastTransform<NewSrc, Dst> {
match (self, other) {
(&FastTransform::Offset(ref offset), &FastTransform::Offset(ref other_offset)) => {
let offset = TypedVector2D::from_untyped(&offset.to_untyped());
FastTransform::Offset((offset + *other_offset))
}
_ => {
let new_transform = self.to_transform().pre_mul(&other.to_transform());
FastTransform::with_transform(new_transform)
}
} else {
TransformOrOffset::Transform { transform, inverse: None }
}
}
pub fn apply(&self, rect: &LayerRect) -> LayerRect {
match *self {
TransformOrOffset::Offset(offset) => rect.translate(&offset),
TransformOrOffset::Transform {transform, .. } => transform.transform_rect(&rect),
#[inline(always)]
pub fn pre_translate(&self, other_offset: &TypedVector2D<f32, Src>) -> Self {
match self {
&FastTransform::Offset(ref offset) =>
return FastTransform::Offset(*offset + *other_offset),
&FastTransform::Transform { transform, .. } =>
FastTransform::with_transform(transform.pre_translate(other_offset.to_3d()))
}
}
pub fn unapply(&self, rect: &LayerRect) -> LayerRect {
#[inline(always)]
pub fn preserves_2d_axis_alignment(&self) -> bool {
match *self {
TransformOrOffset::Offset(offset) => rect.translate(&-offset),
TransformOrOffset::Transform { inverse: Some(inverse), .. } =>
inverse.transform_rect(&rect),
TransformOrOffset::Transform { transform, inverse: None } =>
transform.inverse_rect_footprint(rect),
FastTransform::Offset(..) => true,
FastTransform::Transform { ref transform, .. } =>
transform.preserves_2d_axis_alignment(),
}
}
pub fn offset(&self, new_offset: LayerVector2D) -> TransformOrOffset {
#[inline(always)]
pub fn has_perspective_component(&self) -> bool {
match *self {
TransformOrOffset::Offset(offset) => TransformOrOffset::Offset(offset + new_offset),
TransformOrOffset::Transform { transform, .. } => {
FastTransform::Offset(..) => false,
FastTransform::Transform { ref transform, .. } => transform.has_perspective_component(),
}
}
#[inline(always)]
pub fn is_backface_visible(&self) -> bool {
match *self {
FastTransform::Offset(..) => false,
FastTransform::Transform { ref transform, .. } => transform.is_backface_visible(),
}
}
#[inline(always)]
pub fn transform_point2d(&self, point: &TypedPoint2D<f32, Src>) -> TypedPoint2D<f32, Dst> {
match *self {
FastTransform::Offset(offset) => {
let new_point = *point + offset;
TypedPoint2D::from_untyped(&new_point.to_untyped())
}
FastTransform::Transform { ref transform, .. } => transform.transform_point2d(point),
}
}
#[inline(always)]
pub fn transform_point3d(&self, point: &TypedPoint3D<f32, Src>) -> TypedPoint3D<f32, Dst> {
match *self {
FastTransform::Offset(offset) =>
TypedPoint3D::new(point.x + offset.x, point.y + offset.y, point.z),
FastTransform::Transform { ref transform, .. } => transform.transform_point3d(point),
}
}
#[inline(always)]
pub fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst> {
match *self {
FastTransform::Offset(offset) =>
TypedRect::from_untyped(&rect.to_untyped().translate(&offset.to_untyped())),
FastTransform::Transform { ref transform, .. } => transform.transform_rect(rect),
}
}
pub fn unapply(&self, rect: &TypedRect<f32, Dst>) -> Option<TypedRect<f32, Src>> {
match *self {
FastTransform::Offset(offset) =>
Some(TypedRect::from_untyped(&rect.to_untyped().translate(&-offset.to_untyped()))),
FastTransform::Transform { inverse: Some(ref inverse), is_2d: true, .. } =>
Some(inverse.transform_rect(&rect)),
FastTransform::Transform { ref transform, is_2d: false, .. } =>
Some(transform.inverse_rect_footprint(rect)),
FastTransform::Transform { inverse: None, .. } => None,
}
}
#[inline(always)]
pub fn offset(&self, new_offset: TypedVector2D<f32, Src>) -> Self {
match *self {
FastTransform::Offset(offset) => FastTransform::Offset(offset + new_offset),
FastTransform::Transform { ref transform, .. } => {
let transform = transform.pre_translate(new_offset.to_3d());
TransformOrOffset::new_transform(transform)
FastTransform::with_transform(transform)
}
}
}
pub fn update(&self, transform: LayerTransform) -> Option<TransformOrOffset> {
if transform.is_simple_translation() {
let offset = LayerVector2D::new(transform.m41, transform.m42);
Some(self.offset(offset))
pub fn post_translate(&self, new_offset: TypedVector2D<f32, Dst>) -> Self {
match *self {
FastTransform::Offset(offset) => {
let offset = offset.to_untyped() + new_offset.to_untyped();
FastTransform::Offset(TypedVector2D::from_untyped(&offset))
}
FastTransform::Transform { ref transform, .. } => {
let transform = transform.post_translate(new_offset.to_3d());
FastTransform::with_transform(transform)
}
}
}
#[inline(always)]
pub fn inverse(&self) -> Option<FastTransform<Dst, Src>> {
match *self {
FastTransform::Offset(offset) =>
Some(FastTransform::Offset(TypedVector2D::new(-offset.x, -offset.y))),
FastTransform::Transform { transform, inverse: Some(inverse), is_2d, } =>
Some(FastTransform::Transform {
transform: inverse,
inverse: Some(transform),
is_2d
}),
FastTransform::Transform { inverse: None, .. } => None,
}
}
pub fn update(&self, transform: TypedTransform3D<f32, Src, Dst>) -> Option<Self> {
if transform.is_simple_2d_translation() {
Some(self.offset(TypedVector2D::new(transform.m41, transform.m42)))
} else {
// If we break 2D axis alignment or have a perspective component, we need to start a
// new incompatible coordinate system with which we cannot share clips without masking.
@ -402,3 +533,26 @@ impl TransformOrOffset {
}
}
}
impl<Src, Dst> From<TypedTransform3D<f32, Src, Dst>> for FastTransform<Src, Dst> {
fn from(transform: TypedTransform3D<f32, Src, Dst>) -> FastTransform<Src, Dst> {
FastTransform::with_transform(transform)
}
}
impl<Src, Dst> Into<TypedTransform3D<f32, Src, Dst>> for FastTransform<Src, Dst> {
fn into(self) -> TypedTransform3D<f32, Src, Dst> {
self.to_transform()
}
}
impl<Src, Dst> From<TypedVector2D<f32, Src>> for FastTransform<Src, Dst> {
fn from(vector: TypedVector2D<f32, Src>) -> FastTransform<Src, Dst> {
FastTransform::with_vector(vector)
}
}
pub type LayoutFastTransform = FastTransform<LayoutPixel, LayoutPixel>;
pub type LayerFastTransform = FastTransform<LayerPixel, LayerPixel>;
pub type LayerToWorldFastTransform = FastTransform<LayerPixel, WorldPixel>;
pub type WorldToLayerFastTransform = FastTransform<WorldPixel, LayerPixel>;

Просмотреть файл

@ -54,14 +54,6 @@ const SHADERS: &[Shader] = &[
name: "ps_border_edge",
features: PRIM_FEATURES,
},
Shader {
name: "ps_gradient",
features: PRIM_FEATURES,
},
Shader {
name: "ps_angle_gradient",
features: PRIM_FEATURES,
},
Shader {
name: "ps_hardware_composite",
features: PRIM_FEATURES,
@ -81,7 +73,7 @@ const SHADERS: &[Shader] = &[
// Brush shaders
Shader {
name: "brush_yuv_image",
features: &["", "YUV_NV12", "YUV_PLANAR", "YUV_INTERLEAVED"],
features: &["", "YUV_NV12", "YUV_PLANAR", "YUV_INTERLEAVED", "YUV_NV12,TEXTURE_RECT"],
},
Shader {
name: "brush_mask",
@ -109,6 +101,10 @@ const SHADERS: &[Shader] = &[
},
Shader {
name: "brush_radial_gradient",
features: &[ "DITHERING" ],
},
Shader {
name: "brush_linear_gradient",
features: &[],
},
];

Просмотреть файл

@ -1 +1 @@
e8d2ffb404a85651fe08a6d09abbece9bd2b9182
8a19316a733a484bf9bafb8257e3008b1418bfe4