Bug 1438892 - Update webrender to e8d2ffb404a85651fe08a6d09abbece9bd2b9182. r=jrmuizel

MozReview-Commit-ID: hO7HCOnrIz

--HG--
extra : rebase_source : e3da8bc05044ab29348c230be819467f90f581bd
This commit is contained in:
Kartikaya Gupta 2018-02-20 09:02:40 -05:00
Родитель 7bff6906cb
Коммит 63b1e24e3d
40 изменённых файлов: 1493 добавлений и 1264 удалений

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

@ -25,7 +25,7 @@ lazy_static = "1"
log = "0.4"
num-traits = "0.1.32"
time = "0.1"
rayon = "0.8"
rayon = "1"
webrender_api = {path = "../webrender_api"}
bitflags = "1.0"
thread_profiler = "0.1.1"

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

@ -11,7 +11,7 @@ extern crate webrender;
mod boilerplate;
use boilerplate::{Example, HandyDandyRectBuilder};
use rayon::{Configuration as ThreadPoolConfig, ThreadPool};
use rayon::{ThreadPool, ThreadPoolBuilder};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::sync::Arc;
@ -282,10 +282,11 @@ impl Example for App {
}
fn main() {
let worker_config =
ThreadPoolConfig::new().thread_name(|idx| format!("WebRender:Worker#{}", idx));
let workers =
ThreadPoolBuilder::new().thread_name(|idx| format!("WebRender:Worker#{}", idx))
.build();
let workers = Arc::new(ThreadPool::new(worker_config).unwrap());
let workers = Arc::new(workers.unwrap());
let opts = webrender::RendererOptions {
workers: Some(Arc::clone(&workers)),

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

@ -15,6 +15,8 @@ void brush_vs(
#define VECS_PER_BRUSH_PRIM 2
#define VECS_PER_SEGMENT 2
#define BRUSH_FLAG_PERSPECTIVE_INTERPOLATION 1
struct BrushInstance {
int picture_address;
int prim_address;
@ -24,6 +26,7 @@ struct BrushInstance {
int z;
int segment_index;
int edge_mask;
int flags;
ivec3 user_data;
};
@ -37,7 +40,8 @@ BrushInstance load_brush() {
bi.scroll_node_id = aData0.z & 0xffff;
bi.z = aData0.w;
bi.segment_index = aData1.x & 0xffff;
bi.edge_mask = aData1.x >> 16;
bi.edge_mask = (aData1.x >> 16) & 0xff;
bi.flags = (aData1.x >> 24);
bi.user_data = aData1.yzw;
return bi;
@ -135,6 +139,8 @@ void main(void) {
#endif
} else {
bvec4 edge_mask = notEqual(brush.edge_mask & ivec4(1, 2, 4, 8), ivec4(0));
bool do_perspective_interpolation = (brush.flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0;
vi = write_transform_vertex(
local_segment_rect,
brush_prim.local_rect,
@ -142,7 +148,8 @@ void main(void) {
mix(vec4(0.0), vec4(1.0), edge_mask),
float(brush.z),
scroll_node,
pic_task
pic_task,
do_perspective_interpolation
);
}

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

@ -3,11 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define VECS_PER_SPECIFIC_BRUSH 5
#define FORCE_NO_PERSPECTIVE
#include shared,prim_shared,brush
varying vec3 vUv;
varying float vW;
flat varying float vAmount;
flat varying int vOp;
@ -25,10 +25,9 @@ void brush_vs(
) {
PictureTask src_task = fetch_picture_task(user_data.x);
vec2 texture_size = vec2(textureSize(sColor0, 0).xy);
vec2 uv = (vi.snapped_device_pos +
src_task.common_data.task_rect.p0 -
src_task.content_origin) * vi.w;
vW = vi.w;
vec2 uv = vi.snapped_device_pos +
src_task.common_data.task_rect.p0 -
src_task.content_origin;
vUv = vec3(uv / texture_size, src_task.common_data.texture_layer_index);
vOp = user_data.y;
@ -115,8 +114,7 @@ vec4 Opacity(vec4 Cs, float amount) {
}
vec4 brush_fs() {
vec2 uv = vUv.xy / vW;
vec4 Cs = texture(sColor0, vec3(uv, vUv.z));
vec4 Cs = texture(sColor0, vUv);
// Un-premultiply the input.
Cs.rgb /= Cs.a;

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

@ -6,9 +6,6 @@
#include shared,prim_shared,brush
varying vec3 vUv;
varying float vW;
varying vec3 vSrcUv;
varying vec3 vBackdropUv;
flat varying int vOp;
@ -24,18 +21,17 @@ void brush_vs(
) {
vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
vOp = user_data.x;
vW = vi.w;
PictureTask src_task = fetch_picture_task(user_data.z);
vec2 src_uv = (vi.snapped_device_pos +
src_task.common_data.task_rect.p0 -
src_task.content_origin) * vi.w;
vec2 src_uv = vi.snapped_device_pos +
src_task.common_data.task_rect.p0 -
src_task.content_origin;
vSrcUv = vec3(src_uv / texture_size, src_task.common_data.texture_layer_index);
RenderTaskCommonData backdrop_task = fetch_render_task_common_data(user_data.y);
vec2 backdrop_uv = (vi.snapped_device_pos +
backdrop_task.task_rect.p0 -
src_task.content_origin) * vi.w;
vec2 backdrop_uv = vi.snapped_device_pos +
backdrop_task.task_rect.p0 -
src_task.content_origin;
vBackdropUv = vec3(backdrop_uv / texture_size, backdrop_task.texture_layer_index);
}
#endif
@ -205,10 +201,8 @@ const int MixBlendMode_Color = 14;
const int MixBlendMode_Luminosity = 15;
vec4 brush_fs() {
vec2 uv = vUv.xy / vW;
vec4 Cb = texture(sCacheRGBA8, vBackdropUv);
vec4 Cs = texture(sCacheRGBA8, vSrcUv);
vec4 Cb = textureLod(sCacheRGBA8, vBackdropUv, 0.0);
vec4 Cs = textureLod(sCacheRGBA8, vSrcUv, 0.0);
if (Cb.a == 0.0) {
return Cs;

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

@ -2,7 +2,9 @@
* 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
#define VECS_PER_SPECIFIC_BRUSH 2
#include shared,prim_shared,brush
flat varying int vGradientAddress;
flat varying float vGradientRepeat;
@ -12,24 +14,34 @@ flat varying vec2 vEndCenter;
flat varying float vStartRadius;
flat varying float vEndRadius;
flat varying vec2 vTileSize;
flat varying vec2 vTileRepeat;
varying vec2 vPos;
#ifdef WR_FEATURE_ALPHA_PASS
varying vec2 vLocalPos;
#endif
#ifdef WR_VERTEX_SHADER
void main(void) {
Primitive prim = load_primitive();
RadialGradient gradient = fetch_radial_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);
struct RadialGradient {
vec4 start_end_center;
vec4 start_end_radius_ratio_xy_extend_mode;
};
vPos = vi.local_pos - prim.local_rect.p0;
RadialGradient fetch_radial_gradient(int address) {
vec4 data[2] = fetch_from_resource_cache_2(address);
return RadialGradient(data[0], data[1]);
}
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
ivec3 user_data,
PictureTask pic_task
) {
RadialGradient gradient = fetch_radial_gradient(prim_address);
vPos = vi.local_pos - local_rect.p0;
vStartCenter = gradient.start_end_center.xy;
vEndCenter = gradient.start_end_center.zw;
@ -37,38 +49,28 @@ void main(void) {
vStartRadius = gradient.start_end_radius_ratio_xy_extend_mode.x;
vEndRadius = gradient.start_end_radius_ratio_xy_extend_mode.y;
vTileSize = gradient.tile_size_repeat.xy;
vTileRepeat = gradient.tile_size_repeat.zw;
// Transform all coordinates by the y scale so the
// fragment shader can work with circles
float ratio_xy = gradient.start_end_radius_ratio_xy_extend_mode.z;
vPos.y *= ratio_xy;
vStartCenter.y *= ratio_xy;
vEndCenter.y *= ratio_xy;
vTileSize.y *= ratio_xy;
vTileRepeat.y *= ratio_xy;
vGradientAddress = prim.specific_prim_address + VECS_PER_GRADIENT;
vGradientAddress = user_data.x;
// Whether to repeat the gradient instead of clamping.
vGradientRepeat = float(int(gradient.start_end_radius_ratio_xy_extend_mode.w) != EXTEND_MODE_CLAMP);
write_clip(vi.screen_pos, prim.clip_area);
#ifdef WR_FEATURE_ALPHA_PASS
vLocalPos = vi.local_pos;
#endif
}
#endif
#ifdef WR_FRAGMENT_SHADER
void main(void) {
vec2 pos = mod(vPos, vTileRepeat);
if (pos.x >= vTileSize.x ||
pos.y >= vTileSize.y) {
discard;
}
vec4 brush_fs() {
vec2 cd = vEndCenter - vStartCenter;
vec2 pd = pos - vStartCenter;
vec2 pd = vPos - vStartCenter;
float rd = vEndRadius - vStartRadius;
// Solve for t in length(t * cd - pd) = vStartRadius + t * rd
@ -110,6 +112,10 @@ void main(void) {
offset,
vGradientRepeat);
oFragColor = color * do_clip();
#ifdef WR_FEATURE_ALPHA_PASS
color *= init_transform_fs(vLocalPos);
#endif
return color;
}
#endif

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

@ -0,0 +1,166 @@
/* 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 0
#include shared,prim_shared,brush
// TODO(gw): Consider whether we should even have separate shader compilations
// for the various YUV modes. To save on the number of shaders we
// need to compile, it might be worth just doing this as an
// uber-shader instead.
// TODO(gw): Regardless of the above, we should remove the separate shader
// compilations for the different color space matrix below. That
// can be provided by a branch in the VS and pushed through the
// interpolators, or even as a uniform that breaks batches, rather
// that needing to compile to / select a different shader when
// there is a different color space.
#ifdef WR_FEATURE_ALPHA_PASS
varying vec2 vLocalPos;
#endif
#if defined (WR_FEATURE_YUV_PLANAR)
varying vec3 vUv_Y;
flat varying vec4 vUvBounds_Y;
varying vec3 vUv_U;
flat varying vec4 vUvBounds_U;
varying vec3 vUv_V;
flat varying vec4 vUvBounds_V;
#elif defined (WR_FEATURE_YUV_NV12)
varying vec3 vUv_Y;
flat varying vec4 vUvBounds_Y;
varying vec3 vUv_UV;
flat varying vec4 vUvBounds_UV;
#elif defined (WR_FEATURE_YUV_INTERLEAVED)
varying vec3 vUv_YUV;
flat varying vec4 vUvBounds_YUV;
#endif
#ifdef WR_VERTEX_SHADER
void write_uv_rect(
int resource_id,
vec2 f,
vec2 texture_size,
out vec3 uv,
out vec4 uv_bounds
) {
ImageResource res = fetch_image_resource(resource_id);
vec2 uv0 = res.uv_rect.p0;
vec2 uv1 = res.uv_rect.p1;
uv.xy = mix(uv0, uv1, f);
uv.z = res.layer;
uv_bounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5));
#ifndef WR_FEATURE_TEXTURE_RECT
uv.xy /= texture_size;
uv_bounds /= texture_size.xyxy;
#endif
}
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
ivec3 user_data,
PictureTask pic_task
) {
vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
#ifdef WR_FEATURE_ALPHA_PASS
vLocalPos = vi.local_pos;
#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);
#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);
#elif defined (WR_FEATURE_YUV_INTERLEAVED)
write_uv_rect(user_data.x, f, vec2(textureSize(sColor0, 0).xy), vUv_YUV, vUvBounds_YUV);
#endif //WR_FEATURE_YUV_*
}
#endif
#ifdef WR_FRAGMENT_SHADER
#if !defined(WR_FEATURE_YUV_REC601) && !defined(WR_FEATURE_YUV_REC709)
#define WR_FEATURE_YUV_REC601
#endif
// The constants added to the Y, U and V components are applied in the fragment shader.
#if defined(WR_FEATURE_YUV_REC601)
// From Rec601:
// [R] [1.1643835616438356, 0.0, 1.5960267857142858 ] [Y - 16]
// [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708 ] x [U - 128]
// [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [V - 128]
//
// For the range [0,1] instead of [0,255].
//
// The matrix is stored in column-major.
const mat3 YuvColorMatrix = mat3(
1.16438, 1.16438, 1.16438,
0.0, -0.39176, 2.01723,
1.59603, -0.81297, 0.0
);
#elif defined(WR_FEATURE_YUV_REC709)
// From Rec709:
// [R] [1.1643835616438356, 4.2781193979771426e-17, 1.7927410714285714] [Y - 16]
// [G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444 ] x [U - 128]
// [B] [1.1643835616438356, 2.1124017857142854, 0.0 ] [V - 128]
//
// For the range [0,1] instead of [0,255]:
//
// The matrix is stored in column-major.
const mat3 YuvColorMatrix = mat3(
1.16438, 1.16438, 1.16438,
0.0 , -0.21325, 2.11240,
1.79274, -0.53291, 0.0
);
#endif
vec4 brush_fs() {
vec3 yuv_value;
#if defined (WR_FEATURE_YUV_PLANAR)
// The yuv_planar format should have this third texture coordinate.
vec2 uv_y = clamp(vUv_Y.xy, vUvBounds_Y.xy, vUvBounds_Y.zw);
vec2 uv_u = clamp(vUv_U.xy, vUvBounds_U.xy, vUvBounds_U.zw);
vec2 uv_v = clamp(vUv_V.xy, vUvBounds_V.xy, vUvBounds_V.zw);
yuv_value.x = TEX_SAMPLE(sColor0, vec3(uv_y, vUv_Y.z)).r;
yuv_value.y = TEX_SAMPLE(sColor1, vec3(uv_u, vUv_U.z)).r;
yuv_value.z = TEX_SAMPLE(sColor2, vec3(uv_v, vUv_V.z)).r;
#elif defined (WR_FEATURE_YUV_NV12)
vec2 uv_y = clamp(vUv_Y.xy, vUvBounds_Y.xy, vUvBounds_Y.zw);
vec2 uv_uv = clamp(vUv_UV.xy, vUvBounds_UV.xy, vUvBounds_UV.zw);
yuv_value.x = TEX_SAMPLE(sColor0, vec3(uv_y, vUv_Y.z)).r;
yuv_value.yz = TEX_SAMPLE(sColor1, vec3(uv_uv, vUv_UV.z)).rg;
#elif defined (WR_FEATURE_YUV_INTERLEAVED)
// "The Y, Cb and Cr color channels within the 422 data are mapped into
// the existing green, blue and red color channels."
// https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
vec2 uv_y = clamp(vUv_YUV.xy, vUvBounds_YUV.xy, vUvBounds_YUV.zw);
yuv_value = TEX_SAMPLE(sColor0, vec3(uv_y, vUv_YUV.z)).gbr;
#else
yuv_value = vec3(0.0);
#endif
// See the YuvColorMatrix definition for an explanation of where the constants come from.
vec3 rgb = YuvColorMatrix * (yuv_value - vec3(0.06275, 0.50196, 0.50196));
vec4 color = vec4(rgb, 1.0);
#ifdef WR_FEATURE_ALPHA_PASS
color *= init_transform_fs(vLocalPos);
#endif
return color;
}
#endif

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

@ -4,73 +4,31 @@
#ifdef WR_FRAGMENT_SHADER
// One iteration of Newton's method on the 2D equation of an ellipse:
//
// Signed distance to an ellipse.
// Taken from http://www.iquilezles.org/www/articles/ellipsedist/ellipsedist.htm
// Note that this fails for exact circles.
// E(x, y) = x^2/a^2 + y^2/b^2 - 1
//
float sdEllipse( vec2 p, in vec2 ab ) {
p = abs( p ); if( p.x > p.y ){ p=p.yx; ab=ab.yx; }
float l = ab.y*ab.y - ab.x*ab.x;
float m = ab.x*p.x/l;
float n = ab.y*p.y/l;
float m2 = m*m;
float n2 = n*n;
float c = (m2 + n2 - 1.0)/3.0;
float c3 = c*c*c;
float q = c3 + m2*n2*2.0;
float d = c3 + m2*n2;
float g = m + m*n2;
float co;
if( d<0.0 )
{
float p = acos(q/c3)/3.0;
float s = cos(p);
float t = sin(p)*sqrt(3.0);
float rx = sqrt( -c*(s + t + 2.0) + m2 );
float ry = sqrt( -c*(s - t + 2.0) + m2 );
co = ( ry + sign(l)*rx + abs(g)/(rx*ry) - m)/2.0;
}
else
{
float h = 2.0*m*n*sqrt( d );
float s = sign(q+h)*pow( abs(q+h), 1.0/3.0 );
float u = sign(q-h)*pow( abs(q-h), 1.0/3.0 );
float rx = -s - u - c*4.0 + 2.0*m2;
float ry = (s - u)*sqrt(3.0);
float rm = sqrt( rx*rx + ry*ry );
float p = ry/sqrt(rm-rx);
co = (p + 2.0*g/rm - m)/2.0;
}
float si = sqrt( 1.0 - co*co );
vec2 r = vec2( ab.x*co, ab.y*si );
return length(r - p ) * sign(p.y-r.y);
}
// The Jacobian of this equation is:
//
// J(E(x, y)) = [ 2*x/a^2 2*y/b^2 ]
//
// We approximate the distance with:
//
// E(x, y) / ||J(E(x, y))||
//
// See G. Taubin, "Distance Approximations for Rasterizing Implicit
// Curves", section 3.
float distance_to_ellipse(vec2 p, vec2 radii, float aa_range) {
// sdEllipse fails on exact circles, so handle equal
// radii here. The branch coherency should make this
// a performance win for the circle case too.
float len = length(p);
if (radii.x == radii.y) {
return len - radii.x;
float dist;
if (any(lessThanEqual(radii, vec2(0.0)))) {
dist = length(p);
} else {
if (len < min(radii.x, radii.y) - aa_range) {
return -aa_range;
} else if (len > max(radii.x, radii.y) + aa_range) {
return aa_range;
}
return sdEllipse(p, radii);
vec2 invRadiiSq = 1.0 / (radii * radii);
float g = dot(p * p * invRadiiSq, vec2(1.0)) - 1.0;
vec2 dG = 2.0 * p * invRadiiSq;
dist = g * inversesqrt(dot(dG, dG));
}
return clamp(dist, -aa_range, aa_range);
}
float clip_against_ellipse_if_needed(

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

@ -315,27 +315,6 @@ Gradient fetch_gradient(int address) {
return Gradient(data[0], data[1], data[2]);
}
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]);
}
struct RadialGradient {
vec4 start_end_center;
vec4 start_end_radius_ratio_xy_extend_mode;
vec4 tile_size_repeat;
};
RadialGradient fetch_radial_gradient(int address) {
vec4 data[3] = fetch_from_resource_cache_3(address);
return RadialGradient(data[0], data[1], data[2]);
}
struct Glyph {
vec2 offset;
};
@ -624,7 +603,8 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect,
vec4 clip_edge_mask,
float z,
ClipScrollNode scroll_node,
PictureTask task) {
PictureTask task,
bool do_perspective_interpolation) {
// Calculate a clip rect from local_rect + local clip
RectWithEndpoint clip_rect = to_rect_with_endpoint(local_clip_rect);
RectWithEndpoint segment_rect = to_rect_with_endpoint(local_segment_rect);
@ -661,13 +641,16 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect,
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
vec2 task_offset = task.common_data.task_rect.p0 - task.content_origin;
// Force w = 1, if we don't want perspective interpolation (for
// example, drawing a screen-space quad on an element with a
// perspective transform).
world_pos.w = mix(1.0, world_pos.w, do_perspective_interpolation);
// We want the world space coords to be perspective divided by W.
// We also want that to apply to any interpolators. However, we
// want a constant Z across the primitive, since we're using it
// for draw ordering - so scale by the W coord to ensure this.
vec4 final_pos = vec4((device_pos + task_offset) * world_pos.w,
z * world_pos.w,
world_pos.w);
vec4 final_pos = vec4(device_pos + task_offset, z, 1.0) * world_pos.w;
gl_Position = uTransform * final_pos;
vLocalBounds = mix(
@ -694,7 +677,8 @@ VertexInfo write_transform_vertex_primitive(Primitive prim) {
vec4(1.0),
prim.z,
prim.scroll_node,
prim.task
prim.task,
true
);
}

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

@ -320,7 +320,8 @@ void main(void) {
edge_mask,
prim.z,
prim.scroll_node,
prim.task);
prim.task,
true);
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,

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

@ -233,7 +233,8 @@ void main(void) {
edge_mask,
prim.z,
prim.scroll_node,
prim.task);
prim.task,
true);
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,

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

@ -9,6 +9,16 @@ 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);
@ -73,7 +83,8 @@ void main(void) {
vec4(1.0),
prim.z,
prim.scroll_node,
prim.task);
prim.task,
true);
vLocalPos = vi.local_pos;
vec2 f = (vi.local_pos.xy - prim.local_rect.p0) / prim.local_rect.size;
#else

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

@ -1,197 +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
// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use non-normalized
// texture coordinates. Otherwise, it uses normalized texture coordinates. Please
// check GL_TEXTURE_RECTANGLE.
flat varying vec2 vTextureOffsetY; // Offset of the y plane into the texture atlas.
flat varying vec2 vTextureOffsetU; // Offset of the u plane into the texture atlas.
flat varying vec2 vTextureOffsetV; // Offset of the v plane into the texture atlas.
flat varying vec2 vTextureSizeY; // Size of the y plane in the texture atlas.
flat varying vec2 vTextureSizeUv; // Size of the u and v planes in the texture atlas.
flat varying vec2 vStretchSize;
flat varying vec2 vHalfTexelY; // Normalized length of the half of a Y texel.
flat varying vec2 vHalfTexelUv; // Normalized length of the half of u and v texels.
flat varying vec3 vLayers;
#ifdef WR_FEATURE_TRANSFORM
flat varying vec4 vLocalRect;
#endif
varying vec2 vLocalPos;
#ifdef WR_VERTEX_SHADER
struct YuvImage {
vec2 size;
};
YuvImage fetch_yuv_image(int address) {
vec4 data = fetch_from_resource_cache_1(address);
return YuvImage(data.xy);
}
void main(void) {
Primitive prim = load_primitive();
#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex_primitive(prim);
vLocalPos = vi.local_pos;
vLocalRect = vec4(prim.local_rect.p0, prim.local_rect.p0 + prim.local_rect.size);
#else
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.scroll_node,
prim.task,
prim.local_rect);
vLocalPos = vi.local_pos - prim.local_rect.p0;
#endif
write_clip(vi.screen_pos, prim.clip_area);
ImageResource y_rect = fetch_image_resource(prim.user_data0);
vLayers = vec3(y_rect.layer, 0.0, 0.0);
#ifndef WR_FEATURE_INTERLEAVED_Y_CB_CR // only 1 channel
ImageResource u_rect = fetch_image_resource(prim.user_data1);
vLayers.y = u_rect.layer;
#ifndef WR_FEATURE_NV12 // 2 channel
ImageResource v_rect = fetch_image_resource(prim.user_data2);
vLayers.z = v_rect.layer;
#endif
#endif
// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use
// non-normalized texture coordinates.
#ifdef WR_FEATURE_TEXTURE_RECT
vec2 y_texture_size_normalization_factor = vec2(1, 1);
#else
vec2 y_texture_size_normalization_factor = vec2(textureSize(sColor0, 0));
#endif
vec2 y_st0 = y_rect.uv_rect.p0 / y_texture_size_normalization_factor;
vec2 y_st1 = y_rect.uv_rect.p1 / y_texture_size_normalization_factor;
vTextureSizeY = y_st1 - y_st0;
vTextureOffsetY = y_st0;
#ifndef WR_FEATURE_INTERLEAVED_Y_CB_CR
// This assumes the U and V surfaces have the same size.
#ifdef WR_FEATURE_TEXTURE_RECT
vec2 uv_texture_size_normalization_factor = vec2(1, 1);
#else
vec2 uv_texture_size_normalization_factor = vec2(textureSize(sColor1, 0));
#endif
vec2 u_st0 = u_rect.uv_rect.p0 / uv_texture_size_normalization_factor;
vec2 u_st1 = u_rect.uv_rect.p1 / uv_texture_size_normalization_factor;
#ifndef WR_FEATURE_NV12
vec2 v_st0 = v_rect.uv_rect.p0 / uv_texture_size_normalization_factor;
#endif
vTextureSizeUv = u_st1 - u_st0;
vTextureOffsetU = u_st0;
#ifndef WR_FEATURE_NV12
vTextureOffsetV = v_st0;
#endif
#endif
YuvImage image = fetch_yuv_image(prim.specific_prim_address);
vStretchSize = image.size;
vHalfTexelY = vec2(0.5) / y_texture_size_normalization_factor;
#ifndef WR_FEATURE_INTERLEAVED_Y_CB_CR
vHalfTexelUv = vec2(0.5) / uv_texture_size_normalization_factor;
#endif
}
#endif
#ifdef WR_FRAGMENT_SHADER
#if !defined(WR_FEATURE_YUV_REC601) && !defined(WR_FEATURE_YUV_REC709)
#define WR_FEATURE_YUV_REC601
#endif
// The constants added to the Y, U and V components are applied in the fragment shader.
#if defined(WR_FEATURE_YUV_REC601)
// From Rec601:
// [R] [1.1643835616438356, 0.0, 1.5960267857142858 ] [Y - 16]
// [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708 ] x [U - 128]
// [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [V - 128]
//
// For the range [0,1] instead of [0,255].
//
// The matrix is stored in column-major.
const mat3 YuvColorMatrix = mat3(
1.16438, 1.16438, 1.16438,
0.0, -0.39176, 2.01723,
1.59603, -0.81297, 0.0
);
#elif defined(WR_FEATURE_YUV_REC709)
// From Rec709:
// [R] [1.1643835616438356, 4.2781193979771426e-17, 1.7927410714285714] [Y - 16]
// [G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444 ] x [U - 128]
// [B] [1.1643835616438356, 2.1124017857142854, 0.0 ] [V - 128]
//
// For the range [0,1] instead of [0,255]:
//
// The matrix is stored in column-major.
const mat3 YuvColorMatrix = mat3(
1.16438, 1.16438, 1.16438,
0.0 , -0.21325, 2.11240,
1.79274, -0.53291, 0.0
);
#endif
void main(void) {
#ifdef WR_FEATURE_TRANSFORM
float alpha = init_transform_fs(vLocalPos);
// We clamp the texture coordinate calculation here to the local rectangle boundaries,
// which makes the edge of the texture stretch instead of repeat.
vec2 relative_pos_in_rect = clamp(vLocalPos, vLocalRect.xy, vLocalRect.zw) - vLocalRect.xy;
#else
float alpha = 1.0;;
vec2 relative_pos_in_rect = vLocalPos;
#endif
alpha *= do_clip();
// We clamp the texture coordinates to the half-pixel offset from the borders
// in order to avoid sampling outside of the texture area.
vec2 st_y = vTextureOffsetY + clamp(
relative_pos_in_rect / vStretchSize * vTextureSizeY,
vHalfTexelY, vTextureSizeY - vHalfTexelY);
#ifndef WR_FEATURE_INTERLEAVED_Y_CB_CR
vec2 uv_offset = clamp(
relative_pos_in_rect / vStretchSize * vTextureSizeUv,
vHalfTexelUv, vTextureSizeUv - vHalfTexelUv);
// NV12 only uses 2 textures. The sColor0 is for y and sColor1 is for uv.
// The texture coordinates of u and v are the same. So, we could skip the
// st_v if the format is NV12.
vec2 st_u = vTextureOffsetU + uv_offset;
#endif
vec3 yuv_value;
#ifdef WR_FEATURE_INTERLEAVED_Y_CB_CR
// "The Y, Cb and Cr color channels within the 422 data are mapped into
// the existing green, blue and red color channels."
// https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
yuv_value = TEX_SAMPLE(sColor0, vec3(st_y, vLayers.x)).gbr;
#elif defined(WR_FEATURE_NV12)
yuv_value.x = TEX_SAMPLE(sColor0, vec3(st_y, vLayers.x)).r;
yuv_value.yz = TEX_SAMPLE(sColor1, vec3(st_u, vLayers.y)).rg;
#else
// The yuv_planar format should have this third texture coordinate.
vec2 st_v = vTextureOffsetV + uv_offset;
yuv_value.x = TEX_SAMPLE(sColor0, vec3(st_y, vLayers.x)).r;
yuv_value.y = TEX_SAMPLE(sColor1, vec3(st_u, vLayers.y)).r;
yuv_value.z = TEX_SAMPLE(sColor2, vec3(st_v, vLayers.z)).r;
#endif
// See the YuvColorMatrix definition for an explanation of where the constants come from.
vec3 rgb = YuvColorMatrix * (yuv_value - vec3(0.06275, 0.50196, 0.50196));
oFragColor = vec4(rgb * alpha, alpha);
}
#endif

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

@ -7,22 +7,20 @@ use api::{DeviceUintRect, DeviceUintPoint, DeviceUintSize, ExternalImageType, Fi
use api::{DeviceIntPoint, LayerPoint, SubpixelDirection, YuvColorSpace, YuvFormat};
use api::{LayerToWorldTransform, WorldPixel};
use border::{BorderCornerInstance, BorderCornerSide, BorderEdgeKind};
use clip::{ClipSource, ClipStore};
use clip::{ClipSource, ClipStore, ClipWorkItem};
use clip_scroll_tree::{CoordinateSystemId};
use euclid::{TypedTransform3D, vec3};
use glyph_rasterizer::GlyphFormat;
use gpu_cache::{GpuCache, GpuCacheAddress};
use gpu_types::{BrushImageKind, BrushInstance, ClipChainRectIndex};
use gpu_types::{BrushFlags, BrushImageKind, BrushInstance, ClipChainRectIndex};
use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex};
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
use internal_types::{FastHashMap, SourceTexture};
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::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PrimitiveRun};
use render_task::{ClipWorkItem};
use render_task::{RenderTaskAddress, RenderTaskId};
use render_task::{RenderTaskKind, RenderTaskTree};
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
use renderer::{BlendMode, ImageBufferKind};
use renderer::BLOCKS_PER_UV_RECT;
use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache};
@ -40,10 +38,8 @@ const OPAQUE_TASK_ADDRESS: RenderTaskAddress = RenderTaskAddress(0x7fff);
pub enum TransformBatchKind {
TextRun(GlyphFormat),
Image(ImageBufferKind),
YuvImage(ImageBufferKind, YuvFormat, YuvColorSpace),
AlignedGradient,
AngleGradient,
RadialGradient,
BorderCorner,
BorderEdge,
}
@ -80,6 +76,8 @@ pub enum BrushBatchKind {
source_id: RenderTaskId,
backdrop_id: RenderTaskId,
},
YuvImage(ImageBufferKind, YuvFormat, YuvColorSpace),
RadialGradient,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -953,6 +951,7 @@ impl AlphaBatchBuilder {
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data: [
cache_task_address.0 as i32,
BrushImageKind::Simple as i32,
@ -1039,6 +1038,7 @@ impl AlphaBatchBuilder {
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data: [
cache_task_address.0 as i32,
BrushImageKind::Simple as i32,
@ -1052,12 +1052,12 @@ impl AlphaBatchBuilder {
}
let secondary_id = secondary_render_task_id.expect("no secondary!?");
let render_task = &render_tasks[secondary_id];
let saved_index = render_tasks[secondary_id].saved_index.expect("no saved index!?");
debug_assert_ne!(saved_index, SavedTargetIndex::PENDING);
let secondary_task_address = render_tasks.get_task_address(secondary_id);
let render_pass_index = render_task.pass_index.expect("no render_pass_index!?");
let secondary_textures = BatchTextures {
colors: [
SourceTexture::RenderTaskCacheRGBA8(render_pass_index),
SourceTexture::RenderTaskCache(saved_index),
SourceTexture::Invalid,
SourceTexture::Invalid,
],
@ -1116,6 +1116,7 @@ impl AlphaBatchBuilder {
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
cache_task_address.0 as i32,
filter_mode,
@ -1155,6 +1156,7 @@ impl AlphaBatchBuilder {
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
mode as u32 as i32,
backdrop_task_address.0 as i32,
@ -1226,73 +1228,6 @@ impl AlphaBatchBuilder {
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
batch.push(base_instance.build(0, 0, 0));
}
PrimitiveKind::RadialGradient => {
let kind = BatchKind::Transformable(
transform_kind,
TransformBatchKind::RadialGradient,
);
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));
}
PrimitiveKind::YuvImage => {
let mut textures = BatchTextures::no_texture();
let mut uv_rect_addresses = [0; 3];
let image_yuv_cpu =
&ctx.prim_store.cpu_yuv_images[prim_metadata.cpu_prim_index.0];
//yuv channel
let channel_count = image_yuv_cpu.format.get_plane_num();
debug_assert!(channel_count <= 3);
for channel in 0 .. channel_count {
let image_key = image_yuv_cpu.yuv_key[channel];
let cache_item = resolve_image(
ImageRequest {
key: image_key,
rendering: image_yuv_cpu.image_rendering,
tile: None,
},
ctx.resource_cache,
gpu_cache,
deferred_resolves,
);
if cache_item.texture_id == SourceTexture::Invalid {
warn!("Warnings: skip a PrimitiveKind::YuvImage");
debug!("at {:?}.", task_relative_bounding_rect);
return;
}
textures.colors[channel] = cache_item.texture_id;
uv_rect_addresses[channel] = cache_item.uv_rect_handle.as_int(gpu_cache);
}
// All yuv textures should be the same type.
let buffer_kind = get_buffer_kind(textures.colors[0]);
assert!(
textures.colors[1 .. image_yuv_cpu.format.get_plane_num()]
.iter()
.all(|&tid| buffer_kind == get_buffer_kind(tid))
);
let kind = BatchKind::Transformable(
transform_kind,
TransformBatchKind::YuvImage(
buffer_kind,
image_yuv_cpu.format,
image_yuv_cpu.color_space,
),
);
let key = BatchKey::new(kind, non_segmented_blend_mode, textures);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
batch.push(base_instance.build(
uv_rect_addresses[0],
uv_rect_addresses[1],
uv_rect_addresses[2],
));
}
}
}
@ -1324,6 +1259,7 @@ impl AlphaBatchBuilder {
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::all(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data,
};
@ -1440,6 +1376,71 @@ impl BrushPrimitive {
[0; 3],
))
}
BrushKind::RadialGradient { ref stops_handle, .. } => {
Some((
BrushBatchKind::RadialGradient,
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];
//yuv channel
let channel_count = format.get_plane_num();
debug_assert!(channel_count <= 3);
for channel in 0 .. channel_count {
let image_key = yuv_key[channel];
let cache_item = resolve_image(
ImageRequest {
key: image_key,
rendering: image_rendering,
tile: None,
},
resource_cache,
gpu_cache,
deferred_resolves,
);
if cache_item.texture_id == SourceTexture::Invalid {
warn!("Warnings: skip a PrimitiveKind::YuvImage");
return None;
}
textures.colors[channel] = cache_item.texture_id;
uv_rect_addresses[channel] = cache_item.uv_rect_handle.as_int(gpu_cache);
}
// All yuv textures should be the same type.
let buffer_kind = get_buffer_kind(textures.colors[0]);
assert!(
textures.colors[1 .. format.get_plane_num()]
.iter()
.all(|&tid| buffer_kind == get_buffer_kind(tid))
);
let kind = BrushBatchKind::YuvImage(
buffer_kind,
format,
color_space,
);
Some((
kind,
textures,
[
uv_rect_addresses[0],
uv_rect_addresses[1],
uv_rect_addresses[2],
],
))
}
BrushKind::Mask { .. } => {
unreachable!("bug: mask brushes not expected in normal alpha pass");
}
@ -1463,10 +1464,8 @@ impl AlphaBatchHelpers for PrimitiveStore {
}
PrimitiveKind::Border |
PrimitiveKind::YuvImage |
PrimitiveKind::AlignedGradient |
PrimitiveKind::AngleGradient |
PrimitiveKind::RadialGradient |
PrimitiveKind::Picture => {
BlendMode::PremultipliedAlpha
}
@ -1486,6 +1485,8 @@ impl AlphaBatchHelpers for PrimitiveStore {
BrushKind::Solid { .. } |
BrushKind::Mask { .. } |
BrushKind::Line { .. } |
BrushKind::YuvImage { .. } |
BrushKind::RadialGradient { .. } |
BrushKind::Picture => {
BlendMode::PremultipliedAlpha
}

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

@ -2,15 +2,14 @@
* 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/. */
use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ClipAndScrollInfo, ColorF};
use api::{LayerPoint, LayerRect, LayerPrimitiveInfo, LayerSize};
use api::{NormalBorder, RepeatMode, TexelRect};
use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ColorF, LayerPoint};
use api::{LayerPrimitiveInfo, LayerRect, LayerSize, NormalBorder, RepeatMode, TexelRect};
use clip::ClipSource;
use ellipse::Ellipse;
use frame_builder::FrameBuilder;
use gpu_cache::GpuDataRequest;
use prim_store::{BorderPrimitiveCpu, BrushSegment, BrushSegmentDescriptor};
use prim_store::{BrushClipMaskKind, EdgeAaSegmentMask, PrimitiveContainer};
use prim_store::{BorderPrimitiveCpu, BrushClipMaskKind, BrushSegment, BrushSegmentDescriptor};
use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain};
use util::{lerp, pack_as_float};
#[repr(u8)]
@ -286,7 +285,7 @@ impl FrameBuilder {
info: &LayerPrimitiveInfo,
border: &NormalBorder,
widths: &BorderWidths,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
corner_instances: [BorderCornerInstance; 4],
edges: [BorderEdgeKind; 4],
clip_sources: Vec<ClipSource>,
@ -354,7 +353,7 @@ impl FrameBuilder {
info: &LayerPrimitiveInfo,
border: &NormalBorder,
widths: &BorderWidths,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
) {
// The border shader is quite expensive. For simple borders, we can just draw
// the border with a few rectangles. This generally gives better batching, and

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

@ -2,16 +2,15 @@
* 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/. */
use api::{ColorF, LayerPoint, LayerRect, LayerSize, LayerVector2D};
use api::{BorderRadius, BoxShadowClipMode, LayoutSize, LayerPrimitiveInfo};
use api::{ClipMode, ClipAndScrollInfo, ComplexClipRegion, LocalClip};
use api::{PipelineId};
use api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, ComplexClipRegion, LayerPoint};
use api::{LayerPrimitiveInfo, LayerRect, LayerSize, LayerVector2D, LayoutSize, LocalClip};
use api::PipelineId;
use app_units::Au;
use clip::ClipSource;
use frame_builder::FrameBuilder;
use gpu_types::BrushImageKind;
use prim_store::{PrimitiveContainer};
use prim_store::{BrushMaskKind, BrushKind, BrushPrimitive};
use prim_store::{BrushKind, BrushMaskKind, BrushPrimitive, PrimitiveContainer};
use prim_store::ScrollNodeAndClipChain;
use picture::PicturePrimitive;
use util::RectHelpers;
use render_task::MAX_BLUR_STD_DEVIATION;
@ -53,7 +52,7 @@ impl FrameBuilder {
pub fn add_box_shadow(
&mut self,
pipeline_id: PipelineId,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
prim_info: &LayerPrimitiveInfo,
box_offset: &LayerVector2D,
color: &ColorF,
@ -88,7 +87,8 @@ impl FrameBuilder {
if box_offset.x == 0.0 && box_offset.y == 0.0 && spread_amount == 0.0 {
return;
}
let mut clips = Vec::new();
let mut clips = Vec::with_capacity(2);
clips.push(ClipSource::Rectangle(*prim_info.local_clip.clip_rect()));
let fast_info = match clip_mode {
BoxShadowClipMode::Outset => {
@ -264,8 +264,10 @@ impl FrameBuilder {
border_radius,
ClipMode::ClipOut,
));
let pic_info = LayerPrimitiveInfo::new(pic_rect);
let pic_info = LayerPrimitiveInfo::with_clip_rect(
pic_rect,
*prim_info.local_clip.clip_rect()
);
self.add_primitive(
clip_and_scroll,
&pic_info,
@ -332,6 +334,12 @@ impl FrameBuilder {
clip_and_scroll
);
let clip_rect = prim_info.local_clip.clip_rect();
let clip_rect = match prim_info.rect.intersection(clip_rect) {
Some(clip_rect) => clip_rect,
None => return,
};
// Draw the picture one pixel outside the original
// rect to account for the inflate above. This
// extra edge will be clipped by the local clip
@ -339,7 +347,7 @@ impl FrameBuilder {
let pic_rect = prim_info.rect.inflate(inflate_size + box_offset.x.abs(), inflate_size + box_offset.y.abs());
let pic_info = LayerPrimitiveInfo::with_clip_rect(
pic_rect,
prim_info.rect
clip_rect
);
// Add a normal clip to ensure nothing gets drawn

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

@ -6,12 +6,15 @@ use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelS
use api::{ImageRendering, LayerRect, LayerToWorldTransform, LayoutPoint, LayoutVector2D};
use api::LocalClip;
use border::{BorderCornerClipSource, ensure_no_corner_overlap};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId};
use ellipse::Ellipse;
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
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 std::rc::Rc;
pub type ClipStore = FreeList<ClipSources>;
pub type ClipSourcesHandle = FreeListHandle<ClipSources>;
@ -349,3 +352,106 @@ pub fn rounded_rectangle_contains_point(point: &LayoutPoint,
true
}
pub type ClipChainNodeRef = Option<Rc<ClipChainNode>>;
#[derive(Debug, Clone)]
pub struct ClipChainNode {
pub work_item: ClipWorkItem,
pub local_clip_rect: LayerRect,
pub screen_outer_rect: DeviceIntRect,
pub screen_inner_rect: DeviceIntRect,
pub prev: ClipChainNodeRef,
}
#[derive(Debug, Clone)]
pub struct ClipChain {
pub parent_index: Option<ClipChainIndex>,
pub combined_outer_screen_rect: DeviceIntRect,
pub combined_inner_screen_rect: DeviceIntRect,
pub nodes: ClipChainNodeRef,
}
impl ClipChain {
pub fn empty(screen_rect: &DeviceIntRect) -> ClipChain {
ClipChain {
parent_index: None,
combined_inner_screen_rect: *screen_rect,
combined_outer_screen_rect: *screen_rect,
nodes: None,
}
}
pub fn new_with_added_node(
&self,
work_item: ClipWorkItem,
local_clip_rect: LayerRect,
screen_outer_rect: DeviceIntRect,
screen_inner_rect: DeviceIntRect,
) -> ClipChain {
// If the new node's inner rectangle completely surrounds our outer rectangle,
// we can discard the new node entirely since it isn't going to affect anything.
if screen_inner_rect.contains_rect(&self.combined_outer_screen_rect) {
return self.clone();
}
let new_node = ClipChainNode {
work_item,
local_clip_rect,
screen_outer_rect,
screen_inner_rect,
prev: None,
};
let mut new_chain = self.clone();
new_chain.add_node(new_node);
new_chain
}
pub fn add_node(&mut self, mut new_node: ClipChainNode) {
new_node.prev = self.nodes.clone();
// If this clip's outer rectangle is completely enclosed by the clip
// chain's inner rectangle, then the only clip that matters from this point
// on is this clip. We can disconnect this clip from the parent clip chain.
if self.combined_inner_screen_rect.contains_rect(&new_node.screen_outer_rect) {
new_node.prev = None;
}
self.combined_outer_screen_rect =
self.combined_outer_screen_rect.intersection(&new_node.screen_outer_rect)
.unwrap_or_else(DeviceIntRect::zero);
self.combined_inner_screen_rect =
self.combined_inner_screen_rect.intersection(&new_node.screen_inner_rect)
.unwrap_or_else(DeviceIntRect::zero);
self.nodes = Some(Rc::new(new_node));
}
}
pub struct ClipChainNodeIter {
pub current: ClipChainNodeRef,
}
impl Iterator for ClipChainNodeIter {
type Item = Rc<ClipChainNode>;
fn next(&mut self) -> ClipChainNodeRef {
let previous = self.current.clone();
self.current = match self.current {
Some(ref item) => item.prev.clone(),
None => return None,
};
previous
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ClipWorkItem {
pub scroll_node_data_index: ClipScrollNodeIndex,
pub clip_sources: ClipSourcesWeakHandle,
pub coordinate_system_id: CoordinateSystemId,
}

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

@ -5,14 +5,13 @@
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, ScrollNodeIdType, ScrollSensitivity, StickyOffsetBounds, WorldPoint};
use clip::{ClipSourcesHandle, ClipStore};
use clip_scroll_tree::{CoordinateSystemId, TransformUpdateState};
use api::{ScrollLocation, ScrollSensitivity, StickyOffsetBounds, WorldPoint};
use clip::{ClipChain, ClipSourcesHandle, ClipStore, ClipWorkItem};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, TransformUpdateState};
use euclid::SideOffsets2D;
use geometry::ray_intersects_rect;
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use render_task::{ClipChain, ClipWorkItem};
use resource_cache::ResourceCache;
use scene::SceneProperties;
use spring::{DAMPING, STIFFNESS, Spring};
@ -56,7 +55,10 @@ pub enum NodeType {
ReferenceFrame(ReferenceFrameInfo),
/// Other nodes just do clipping, but no transformation.
Clip(ClipSourcesHandle),
Clip {
handle: ClipSourcesHandle,
clip_chain_index: ClipChainIndex
},
/// Transforms it's content, but doesn't clip it. Can also be adjusted
/// by scroll events or setting scroll offsets.
@ -106,9 +108,6 @@ pub struct ClipScrollNode {
/// The type of this node and any data associated with that node type.
pub node_type: NodeType,
/// The ClipChain that will be used if this node is used as the 'clipping node.'
pub clip_chain: Option<ClipChain>,
/// 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
/// node will not be clipped by clips that are transformed by this node.
@ -128,7 +127,7 @@ pub struct ClipScrollNode {
}
impl ClipScrollNode {
fn new(
pub fn new(
pipeline_id: PipelineId,
parent_id: Option<ClipId>,
rect: &LayerRect,
@ -142,7 +141,6 @@ impl ClipScrollNode {
children: Vec::new(),
pipeline_id,
node_type: node_type,
clip_chain: None,
invertible: true,
coordinate_system_id: CoordinateSystemId(0),
coordinate_system_relative_transform: TransformOrOffset::zero(),
@ -170,15 +168,6 @@ impl ClipScrollNode {
Self::new(pipeline_id, Some(parent_id), frame_rect, node_type)
}
pub fn new_clip_node(
pipeline_id: PipelineId,
parent_id: ClipId,
handle: ClipSourcesHandle,
clip_rect: LayerRect,
) -> Self {
Self::new(pipeline_id, Some(parent_id), &clip_rect, NodeType::Clip(handle))
}
pub fn new_reference_frame(
parent_id: Option<ClipId>,
frame_rect: &LayerRect,
@ -271,7 +260,6 @@ impl ClipScrollNode {
self.invertible = false;
self.world_content_transform = LayerToWorldTransform::identity();
self.world_viewport_transform = LayerToWorldTransform::identity();
self.clip_chain = None;
}
pub fn push_gpu_node_data(&mut self, node_data: &mut Vec<ClipScrollNodeData>) {
@ -304,6 +292,7 @@ impl ClipScrollNode {
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
scene_properties: &SceneProperties,
clip_chains: &mut Vec<ClipChain>,
) {
// If any of our parents was not rendered, we are not rendered either and can just
// quit here.
@ -331,6 +320,7 @@ impl ClipScrollNode {
clip_store,
resource_cache,
gpu_cache,
clip_chains,
);
}
@ -341,11 +331,11 @@ impl ClipScrollNode {
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
clip_chains: &mut Vec<ClipChain>,
) {
let clip_sources_handle = match self.node_type {
NodeType::Clip(ref handle) => handle,
let (clip_sources_handle, clip_chain_index) = match self.node_type {
NodeType::Clip { ref handle, clip_chain_index } => (handle, clip_chain_index),
_ => {
self.clip_chain = Some(state.parent_clip_chain.clone());
self.invertible = true;
return;
}
@ -364,29 +354,22 @@ impl ClipScrollNode {
"Clipping node didn't have outer rect."
);
// If this clip's inner rectangle completely surrounds the existing clip
// chain's outer rectangle, we can discard this clip entirely since it isn't
// going to affect anything.
if screen_inner_rect.contains_rect(&state.parent_clip_chain.combined_outer_screen_rect) {
self.clip_chain = Some(state.parent_clip_chain.clone());
return;
}
let work_item = ClipWorkItem {
scroll_node_data_index: self.node_data_index,
clip_sources: clip_sources_handle.weak(),
coordinate_system_id: state.current_coordinate_system_id,
};
let clip_chain = state.parent_clip_chain.new_with_added_node(
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),
screen_outer_rect,
screen_inner_rect,
);
self.clip_chain = Some(clip_chain.clone());
state.parent_clip_chain = clip_chain;
clip_chain.parent_index = Some(state.parent_clip_chain_index);
clip_chains[clip_chain_index.0] = clip_chain;
state.parent_clip_chain_index = clip_chain_index;
}
pub fn update_transform(
@ -621,7 +604,7 @@ impl ClipScrollNode {
state.nearest_scrolling_ancestor_viewport
.translate(&translation);
}
NodeType::Clip(..) => { }
NodeType::Clip{ .. } => { }
NodeType::ScrollFrame(ref scrolling) => {
state.parent_accumulated_scroll_offset =
scrolling.offset + state.parent_accumulated_scroll_offset;
@ -768,12 +751,7 @@ impl ClipScrollNode {
}
}
pub fn matches_id(&self, node_id: ClipId, id_to_match: ScrollNodeIdType) -> bool {
let external_id = match id_to_match {
ScrollNodeIdType::ExternalScrollId(id) => id,
ScrollNodeIdType::ClipId(clip_id) => return node_id == clip_id,
};
pub fn matches_external_id(&self, external_id: ExternalScrollId) -> bool {
match self.node_type {
NodeType::ScrollFrame(info) if info.external_id == Some(external_id) => true,
_ => false,

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

@ -2,17 +2,15 @@
* 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/. */
use api::{ClipChainId, ClipId, DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint};
use api::{LayerRect, LayerToWorldTransform, LayerVector2D, PipelineId, ScrollClamping};
use api::{ScrollEventPhase, ScrollLocation, ScrollNodeIdType};
use api::{ScrollNodeState, WorldPoint};
use clip::ClipStore;
use api::{ClipId, DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint, LayerRect};
use api::{LayerToWorldTransform, LayerVector2D, PipelineId, ScrollClamping, ScrollEventPhase};
use api::{ScrollLocation, ScrollNodeState, WorldPoint};
use clip::{ClipChain, ClipSourcesHandle, ClipStore};
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollFrameInfo, StickyFrameInfo};
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use internal_types::{FastHashMap, FastHashSet};
use print_tree::{PrintTree, PrintTreePrinter};
use render_task::ClipChain;
use resource_cache::ResourceCache;
use scene::SceneProperties;
use util::TransformOrOffset;
@ -44,11 +42,14 @@ impl CoordinateSystemId {
}
pub struct ClipChainDescriptor {
pub id: ClipChainId,
pub parent: Option<ClipChainId>,
pub index: ClipChainIndex,
pub parent: Option<ClipChainIndex>,
pub clips: Vec<ClipId>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ClipChainIndex(pub usize);
pub struct ClipScrollTree {
pub nodes: FastHashMap<ClipId, ClipScrollNode>,
@ -57,10 +58,11 @@ pub struct ClipScrollTree {
/// the children of ClipChains later in the list.
pub clip_chains_descriptors: Vec<ClipChainDescriptor>,
/// A HashMap of built ClipChains that are described by `clip_chains_descriptors`.
pub clip_chains: FastHashMap<ClipChainId, ClipChain>,
/// A vector of all ClipChains in this ClipScrollTree including those from
/// ClipChainDescriptors and also those defined by the clipping node hierarchy.
pub clip_chains: Vec<ClipChain>,
pub pending_scroll_offsets: FastHashMap<ScrollNodeIdType, (LayerPoint, ScrollClamping)>,
pub pending_scroll_offsets: FastHashMap<ExternalScrollId, (LayerPoint, ScrollClamping)>,
/// The ClipId of the currently scrolling node. Used to allow the same
/// node to scroll even if a touch operation leaves the boundaries of that node.
@ -90,7 +92,9 @@ pub struct TransformUpdateState {
pub parent_accumulated_scroll_offset: LayerVector2D,
pub nearest_scrolling_ancestor_offset: LayerVector2D,
pub nearest_scrolling_ancestor_viewport: LayerRect,
pub parent_clip_chain: ClipChain,
/// The index of the current parent's clip chain.
pub parent_clip_chain_index: ClipChainIndex,
/// An id for keeping track of the axis-aligned space of this node. This is used in
/// order to to track what kinds of clip optimizations can be done for a particular
@ -113,7 +117,7 @@ impl ClipScrollTree {
ClipScrollTree {
nodes: FastHashMap::default(),
clip_chains_descriptors: Vec::new(),
clip_chains: FastHashMap::default(),
clip_chains: vec![ClipChain::empty(&DeviceIntRect::zero())],
pending_scroll_offsets: FastHashMap::default(),
currently_scrolling_node_id: None,
root_reference_frame_id: ClipId::root_reference_frame(dummy_pipeline),
@ -211,7 +215,7 @@ impl ClipScrollTree {
}
self.pipelines_to_discard.clear();
self.clip_chains.clear();
self.clip_chains = vec![ClipChain::empty(&DeviceIntRect::zero())];
self.clip_chains_descriptors.clear();
scroll_states
}
@ -219,11 +223,11 @@ impl ClipScrollTree {
pub fn scroll_node(
&mut self,
origin: LayerPoint,
id: ScrollNodeIdType,
id: ExternalScrollId,
clamp: ScrollClamping
) -> bool {
for (clip_id, node) in &mut self.nodes {
if node.matches_id(*clip_id, id) {
for node in &mut self.nodes.values_mut() {
if node.matches_external_id(id) {
return node.set_scroll_origin(&origin, clamp);
}
}
@ -321,6 +325,8 @@ impl ClipScrollTree {
return;
}
self.clip_chains[0] = ClipChain::empty(screen_rect);
let root_reference_frame_id = self.root_reference_frame_id();
let mut state = TransformUpdateState {
parent_reference_frame_transform: LayerToWorldTransform::create_translation(
@ -331,7 +337,7 @@ impl ClipScrollTree {
parent_accumulated_scroll_offset: LayerVector2D::zero(),
nearest_scrolling_ancestor_offset: LayerVector2D::zero(),
nearest_scrolling_ancestor_viewport: LayerRect::zero(),
parent_clip_chain: ClipChain::empty(screen_rect),
parent_clip_chain_index: ClipChainIndex(0),
current_coordinate_system_id: CoordinateSystemId::root(),
coordinate_system_relative_transform: TransformOrOffset::zero(),
invertible: true,
@ -384,6 +390,7 @@ impl ClipScrollTree {
resource_cache,
gpu_cache,
scene_properties,
&mut self.clip_chains,
);
node.push_gpu_node_data(gpu_node_data);
@ -417,21 +424,28 @@ impl ClipScrollTree {
// ClipScrollNode clipping nodes. Here we start the ClipChain with a clone of the
// parent's node, if necessary.
let mut chain = match descriptor.parent {
Some(id) => self.clip_chains[&id].clone(),
Some(index) => self.clip_chains[index.0].clone(),
None => ClipChain::empty(screen_rect),
};
// Now we walk through each ClipScrollNode in the vector of clip nodes and
// extract their ClipChain nodes to construct the final list.
for clip_id in &descriptor.clips {
if let Some(ref node_chain) = self.nodes[&clip_id].clip_chain {
if let Some(ref nodes) = node_chain.nodes {
chain.add_node((**nodes).clone());
let node_clip_chain_index = match self.nodes[&clip_id].node_type {
NodeType::Clip { clip_chain_index, .. } => clip_chain_index,
_ => {
warn!("Tried to create a clip chain with non-clipping node.");
continue;
}
};
if let Some(ref nodes) = self.clip_chains[node_clip_chain_index.0].nodes {
chain.add_node((**nodes).clone());
}
}
self.clip_chains.insert(descriptor.id, chain);
chain.parent_index = descriptor.parent;
self.clip_chains[descriptor.index.0] = chain;
}
}
@ -442,30 +456,37 @@ impl ClipScrollTree {
}
pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
for (clip_id, node) in &mut self.nodes {
for node in self.nodes.values_mut() {
let external_id = match node.node_type {
NodeType::ScrollFrame(info) => info.external_id,
_ => None,
NodeType::ScrollFrame(ScrollFrameInfo { external_id: Some(id), ..} ) => id,
_ => continue,
};
if let Some(external_id) = external_id {
if let Some(scrolling_state) = old_states.get(&external_id) {
node.apply_old_scrolling_state(scrolling_state);
}
let id = external_id.into();
if let Some((offset, clamping)) = self.pending_scroll_offsets.remove(&id) {
node.set_scroll_origin(&offset, clamping);
}
if let Some(scrolling_state) = old_states.get(&external_id) {
node.apply_old_scrolling_state(scrolling_state);
}
if let Some((offset, clamping)) = self.pending_scroll_offsets.remove(&clip_id.into()) {
if let Some((offset, clamping)) = self.pending_scroll_offsets.remove(&external_id) {
node.set_scroll_origin(&offset, clamping);
}
}
}
pub fn add_clip_node(
&mut self,
id: ClipId,
parent_id: ClipId,
handle: ClipSourcesHandle,
clip_rect: LayerRect,
) -> ClipChainIndex {
let clip_chain_index = self.allocate_clip_chain();
let node_type = NodeType::Clip { handle, clip_chain_index };
let node = ClipScrollNode::new(id.pipeline_id(), Some(parent_id), &clip_rect, node_type);
self.add_node(node, id);
clip_chain_index
}
pub fn add_sticky_frame(
&mut self,
id: ClipId,
@ -484,11 +505,12 @@ impl ClipScrollTree {
pub fn add_clip_chain_descriptor(
&mut self,
id: ClipChainId,
parent: Option<ClipChainId>,
parent: Option<ClipChainIndex>,
clips: Vec<ClipId>
) {
self.clip_chains_descriptors.push(ClipChainDescriptor { id, parent, clips });
) -> ClipChainIndex {
let index = self.allocate_clip_chain();
self.clip_chains_descriptors.push(ClipChainDescriptor { index, parent, clips });
index
}
pub fn add_node(&mut self, node: ClipScrollNode, id: ClipId) {
@ -515,11 +537,11 @@ impl ClipScrollTree {
let node = self.nodes.get(id).unwrap();
match node.node_type {
NodeType::Clip(ref clip_sources_handle) => {
NodeType::Clip { ref handle, .. } => {
pt.new_level("Clip".to_owned());
pt.add_item(format!("id: {:?}", id));
let clips = clip_store.get(&clip_sources_handle).clips();
let clips = clip_store.get(&handle).clips();
pt.new_level(format!("Clip Sources [{}]", clips.len()));
for source in clips {
pt.add_item(format!("{:?}", source));
@ -581,11 +603,15 @@ impl ClipScrollTree {
}
}
pub fn get_clip_chain(&self, id: &ClipId) -> Option<&ClipChain> {
match id {
&ClipId::ClipChain(clip_chain_id) => Some(&self.clip_chains[&clip_chain_id]),
_ => self.nodes[id].clip_chain.as_ref(),
}
pub fn allocate_clip_chain(&mut self) -> ClipChainIndex {
debug_assert!(!self.clip_chains.is_empty());
let new_clip_chain =self.clip_chains[0].clone();
self.clip_chains.push(new_clip_chain);
ClipChainIndex(self.clip_chains.len() - 1)
}
pub fn get_clip_chain(&self, index: ClipChainIndex) -> &ClipChain {
&self.clip_chains[index.0]
}
}

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

@ -438,6 +438,7 @@ pub struct Texture {
render_target: Option<RenderTargetInfo>,
fbo_ids: Vec<FBOId>,
depth_rb: Option<RBOId>,
last_frame_used: FrameId,
}
impl Texture {
@ -473,6 +474,10 @@ impl Texture {
self.render_target.as_ref()
}
pub fn used_in_frame(&self, frame_id: FrameId) -> bool {
self.last_frame_used == frame_id
}
#[cfg(feature = "replay")]
pub fn into_external(mut self) -> ExternalTexture {
let ext = ExternalTexture {
@ -940,6 +945,7 @@ impl Device {
render_target: None,
fbo_ids: vec![],
depth_rb: None,
last_frame_used: self.frame_id,
}
}
@ -1019,6 +1025,7 @@ impl Device {
texture.filter = filter;
texture.layer_count = layer_count;
texture.render_target = render_target;
texture.last_frame_used = self.frame_id;
self.bind_texture(DEFAULT_TEXTURE, texture);
self.set_texture_parameters(texture.target, filter);

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

@ -3,21 +3,22 @@
* 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/. */
use api::{BuiltDisplayListIter, ClipAndScrollInfo, ClipId, ColorF, ComplexClipRegion};
use api::{DevicePixelScale, DeviceUintRect, DeviceUintSize, DisplayItemRef, DocumentLayer, Epoch};
use api::{ExternalScrollId, FilterOp, IframeDisplayItem, ImageDisplayItem, ItemRange, LayerPoint};
use api::{BuiltDisplayListIter, ClipId, ColorF, ComplexClipRegion, DevicePixelScale};
use api::{DeviceUintRect, DeviceUintSize, DisplayItemRef, DocumentLayer, Epoch, ExternalScrollId};
use api::{FilterOp, IframeDisplayItem, ImageDisplayItem, ItemRange, LayerPoint};
use api::{LayerPrimitiveInfo, LayerRect, LayerSize, LayerVector2D, LayoutSize, PipelineId};
use api::{ScrollClamping, ScrollEventPhase, ScrollFrameDisplayItem, ScrollLocation};
use api::{ScrollNodeIdType, ScrollNodeState, ScrollPolicy, ScrollSensitivity, SpecificDisplayItem};
use api::{StackingContext, TileOffset, TransformStyle, WorldPoint};
use api::{ScrollNodeState, ScrollPolicy, ScrollSensitivity, SpecificDisplayItem, StackingContext};
use api::{TileOffset, TransformStyle, WorldPoint};
use clip::ClipRegion;
use clip_scroll_node::StickyFrameInfo;
use clip_scroll_tree::{ClipScrollTree, ScrollStates};
use clip_scroll_tree::{ClipChainIndex, ClipScrollTree, ScrollStates};
use euclid::rect;
use frame_builder::{FrameBuilder, FrameBuilderConfig, ScrollbarInfo};
use gpu_cache::GpuCache;
use hit_test::HitTester;
use internal_types::{FastHashMap, FastHashSet, RenderedDocument};
use prim_store::ScrollNodeAndClipChain;
use profiler::{GpuCacheProfileCounters, TextureCacheProfileCounters};
use resource_cache::{FontInstanceMap,ResourceCache, TiledImageMap};
use scene::{Scene, StackingContextHelpers, ScenePipeline, SceneProperties};
@ -36,6 +37,53 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF {
a: 0.6,
};
/// A data structure that keeps track of mapping between API clip ids and the indices
/// used internally in the ClipScrollTree to avoid having to do HashMap lookups. This
/// also includes a small LRU cache. Currently the cache is small (1 entry), but in the
/// future we could use uluru here to do something more involved.
pub struct ClipIdToIndexMapper {
map: FastHashMap<ClipId, ClipChainIndex>,
cached_index: Option<(ClipId, ClipChainIndex)>,
}
impl ClipIdToIndexMapper {
fn new() -> ClipIdToIndexMapper {
ClipIdToIndexMapper {
map: FastHashMap::default(),
cached_index: None,
}
}
pub fn add(&mut self, id: ClipId, index: ClipChainIndex) {
debug_assert!(!self.map.contains_key(&id));
self.map.insert(id, index);
}
pub fn map_to_parent_clip_chain(&mut self, id: ClipId, parent_id: &ClipId) {
let parent_chain_index = self.map_clip_id(parent_id);
self.add(id, parent_chain_index);
}
pub fn map_clip_id(&mut self, id: &ClipId) -> ClipChainIndex {
match self.cached_index {
Some((cached_id, cached_index)) if cached_id == *id => return cached_index,
_ => {}
}
self.map[id]
}
pub fn map_clip_id_and_cache_result(&mut self, id: &ClipId) -> ClipChainIndex {
let index = self.map_clip_id(id);
self.cached_index = Some((*id, index));
index
}
pub fn simple_scroll_and_clip_chain(&mut self, id: &ClipId) -> ScrollNodeAndClipChain {
ScrollNodeAndClipChain::new(*id, self.map_clip_id(&id))
}
}
struct FlattenContext<'a> {
scene: &'a Scene,
builder: FrameBuilder,
@ -45,6 +93,7 @@ struct FlattenContext<'a> {
pipeline_epochs: Vec<(PipelineId, Epoch)>,
replacements: Vec<(ClipId, ClipId)>,
output_pipelines: &'a FastHashSet<PipelineId>,
id_to_index_mapper: ClipIdToIndexMapper,
}
impl<'a> FlattenContext<'a> {
@ -104,13 +153,23 @@ impl<'a> FlattenContext<'a> {
let root_reference_frame_id = ClipId::root_reference_frame(pipeline_id);
let root_scroll_frame_id = ClipId::root_scroll_node(pipeline_id);
let root_clip_chain_index =
self.id_to_index_mapper.map_clip_id_and_cache_result(&root_reference_frame_id);
let root_reference_frame_clip_and_scroll = ScrollNodeAndClipChain::new(
root_reference_frame_id,
root_clip_chain_index,
);
self.builder.push_stacking_context(
pipeline_id,
CompositeOps::default(),
TransformStyle::Flat,
true,
true,
ClipAndScrollInfo::simple(root_scroll_frame_id),
ScrollNodeAndClipChain::new(
ClipId::root_scroll_node(pipeline_id),
root_clip_chain_index,
),
self.output_pipelines,
);
@ -122,7 +181,7 @@ impl<'a> FlattenContext<'a> {
let root_bounds = LayerRect::new(LayerPoint::zero(), *frame_size);
let info = LayerPrimitiveInfo::new(root_bounds);
self.builder.add_solid_rectangle(
ClipAndScrollInfo::simple(root_reference_frame_id),
root_reference_frame_clip_and_scroll,
&info,
bg_color,
None,
@ -142,7 +201,7 @@ impl<'a> FlattenContext<'a> {
let scrollbar_rect = LayerRect::new(LayerPoint::zero(), LayerSize::new(10.0, 70.0));
let container_rect = LayerRect::new(LayerPoint::zero(), *frame_size);
self.builder.add_scroll_bar(
ClipAndScrollInfo::simple(root_reference_frame_id),
root_reference_frame_clip_and_scroll,
&LayerPrimitiveInfo::new(scrollbar_rect),
DEFAULT_SCROLLBAR_COLOR,
ScrollbarInfo(root_scroll_frame_id, container_rect),
@ -184,19 +243,13 @@ impl<'a> FlattenContext<'a> {
}
}
fn flatten_clip(
&mut self,
pipeline_id: PipelineId,
parent_id: &ClipId,
new_clip_id: &ClipId,
clip_region: ClipRegion,
) {
fn flatten_clip(&mut self, parent_id: &ClipId, new_clip_id: &ClipId, clip_region: ClipRegion) {
self.builder.add_clip_node(
*new_clip_id,
*parent_id,
pipeline_id,
clip_region,
self.clip_scroll_tree,
&mut self.id_to_index_mapper,
);
}
@ -205,7 +258,7 @@ impl<'a> FlattenContext<'a> {
item: &DisplayItemRef,
info: &ScrollFrameDisplayItem,
pipeline_id: PipelineId,
clip_and_scroll: &ClipAndScrollInfo,
clip_and_scroll: &ScrollNodeAndClipChain,
reference_frame_relative_offset: &LayerVector2D,
) {
let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0);
@ -229,9 +282,9 @@ impl<'a> FlattenContext<'a> {
self.builder.add_clip_node(
info.clip_id,
clip_and_scroll.scroll_node_id,
pipeline_id,
clip_region,
self.clip_scroll_tree,
&mut self.id_to_index_mapper,
);
self.builder.add_scroll_frame(
@ -243,6 +296,7 @@ impl<'a> FlattenContext<'a> {
&content_rect.size,
info.scroll_sensitivity,
self.clip_scroll_tree,
&mut self.id_to_index_mapper,
);
}
@ -250,7 +304,8 @@ impl<'a> FlattenContext<'a> {
&mut self,
traversal: &mut BuiltDisplayListIter<'a>,
pipeline_id: PipelineId,
context_scroll_node_id: ClipId,
unreplaced_scroll_id: ClipId,
clip_and_scroll: ScrollNodeAndClipChain,
mut reference_frame_relative_offset: LayerVector2D,
bounds: &LayerRect,
stacking_context: &StackingContext,
@ -279,7 +334,7 @@ impl<'a> FlattenContext<'a> {
if stacking_context.scroll_policy == ScrollPolicy::Fixed {
self.replacements.push((
context_scroll_node_id,
unreplaced_scroll_id,
self.builder.current_reference_frame_id(),
));
}
@ -296,30 +351,33 @@ impl<'a> FlattenContext<'a> {
);
let reference_frame_bounds = LayerRect::new(LayerPoint::zero(), bounds.size);
let mut parent_id = self.apply_scroll_frame_id_replacement(context_scroll_node_id);
self.builder.push_reference_frame(
reference_frame_id,
Some(parent_id),
Some(clip_and_scroll.scroll_node_id),
pipeline_id,
&reference_frame_bounds,
stacking_context.transform,
stacking_context.perspective,
reference_frame_relative_offset,
self.clip_scroll_tree,
&mut self.id_to_index_mapper,
);
self.replacements.push((context_scroll_node_id, reference_frame_id));
self.replacements.push((unreplaced_scroll_id, reference_frame_id));
reference_frame_relative_offset = LayerVector2D::zero();
}
let sc_scroll_node_id = self.apply_scroll_frame_id_replacement(context_scroll_node_id);
// We apply the replacements one more time in case we need to set it to a replacement
// that we just pushed above.
let new_scroll_node = self.apply_scroll_frame_id_replacement(unreplaced_scroll_id);
let stacking_context_clip_and_scroll =
self.id_to_index_mapper.simple_scroll_and_clip_chain(&new_scroll_node);
self.builder.push_stacking_context(
pipeline_id,
composition_operations,
stacking_context.transform_style,
is_backface_visible,
false,
ClipAndScrollInfo::simple(sc_scroll_node_id),
stacking_context_clip_and_scroll,
self.output_pipelines,
);
@ -345,8 +403,7 @@ impl<'a> FlattenContext<'a> {
&mut self,
item: &DisplayItemRef,
info: &IframeDisplayItem,
parent_pipeline_id: PipelineId,
clip_and_scroll: &ClipAndScrollInfo,
clip_and_scroll: &ScrollNodeAndClipChain,
reference_frame_relative_offset: &LayerVector2D,
) {
let iframe_pipeline_id = info.pipeline_id;
@ -358,12 +415,12 @@ impl<'a> FlattenContext<'a> {
self.builder.add_clip_node(
info.clip_id,
clip_and_scroll.scroll_node_id,
parent_pipeline_id,
ClipRegion::create_for_clip_node_with_local_clip(
&item.local_clip(),
&reference_frame_relative_offset
),
self.clip_scroll_tree,
&mut self.id_to_index_mapper,
);
self.pipeline_epochs.push((iframe_pipeline_id, pipeline.epoch));
@ -380,6 +437,7 @@ impl<'a> FlattenContext<'a> {
None,
origin,
self.clip_scroll_tree,
&mut self.id_to_index_mapper,
);
self.builder.add_scroll_frame(
@ -391,6 +449,7 @@ impl<'a> FlattenContext<'a> {
&pipeline.content_size,
ScrollSensitivity::ScriptAndInputEvents,
self.clip_scroll_tree,
&mut self.id_to_index_mapper,
);
self.flatten_root(&mut pipeline.display_list.iter(), iframe_pipeline_id, &iframe_rect.size);
@ -404,7 +463,11 @@ impl<'a> FlattenContext<'a> {
pipeline_id: PipelineId,
reference_frame_relative_offset: LayerVector2D,
) -> Option<BuiltDisplayListIter<'a>> {
let mut clip_and_scroll = item.clip_and_scroll();
let clip_and_scroll = item.clip_and_scroll();
let mut clip_and_scroll = ScrollNodeAndClipChain::new(
clip_and_scroll.scroll_node_id,
self.id_to_index_mapper.map_clip_id_and_cache_result(&clip_and_scroll.clip_node_id()),
);
let unreplaced_scroll_id = clip_and_scroll.scroll_node_id;
clip_and_scroll.scroll_node_id =
@ -557,6 +620,7 @@ impl<'a> FlattenContext<'a> {
&mut subtraversal,
pipeline_id,
unreplaced_scroll_id,
clip_and_scroll,
reference_frame_relative_offset,
&item.rect(),
&info.stacking_context,
@ -569,7 +633,6 @@ impl<'a> FlattenContext<'a> {
self.flatten_iframe(
&item,
info,
pipeline_id,
&clip_and_scroll,
&reference_frame_relative_offset
);
@ -582,16 +645,16 @@ impl<'a> FlattenContext<'a> {
info.image_mask,
&reference_frame_relative_offset,
);
self.flatten_clip(
pipeline_id,
&clip_and_scroll.scroll_node_id,
&info.id,
clip_region,
);
self.flatten_clip(&clip_and_scroll.scroll_node_id, &info.id, clip_region);
}
SpecificDisplayItem::ClipChain(ref info) => {
let items = self.get_clip_chain_items(pipeline_id, item.clip_chain_items());
self.clip_scroll_tree.add_clip_chain_descriptor(info.id, info.parent, items);
let parent = info.parent.map(|id|
self.id_to_index_mapper.map_clip_id(&ClipId::ClipChain(id))
);
let clip_chain_index =
self.clip_scroll_tree.add_clip_chain_descriptor(parent, items);
self.id_to_index_mapper.add(ClipId::ClipChain(info.id), clip_chain_index);
},
SpecificDisplayItem::ScrollFrame(ref info) => {
self.flatten_scroll_frame(
@ -610,12 +673,14 @@ impl<'a> FlattenContext<'a> {
info.horizontal_offset_bounds,
info.previously_applied_offset,
);
let parent_id = clip_and_scroll.scroll_node_id;
self.clip_scroll_tree.add_sticky_frame(
info.id,
clip_and_scroll.scroll_node_id, /* parent id */
parent_id,
frame_rect,
sticky_frame_info
);
self.id_to_index_mapper.map_to_parent_clip_chain(info.id, &parent_id);
}
// Do nothing; these are dummy items for the display list parser
@ -650,7 +715,7 @@ impl<'a> FlattenContext<'a> {
/// takes care of the decomposition required by the internal tiling of the image.
fn decompose_image(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
prim_info: &LayerPrimitiveInfo,
info: &ImageDisplayItem,
image_size: DeviceUintSize,
@ -696,7 +761,7 @@ impl<'a> FlattenContext<'a> {
fn decompose_image_row(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
prim_info: &LayerPrimitiveInfo,
info: &ImageDisplayItem,
image_size: DeviceUintSize,
@ -742,7 +807,7 @@ impl<'a> FlattenContext<'a> {
fn decompose_tiled_image(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
prim_info: &LayerPrimitiveInfo,
info: &ImageDisplayItem,
image_size: DeviceUintSize,
@ -878,7 +943,7 @@ impl<'a> FlattenContext<'a> {
fn add_tile_primitive(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
prim_info: &LayerPrimitiveInfo,
info: &ImageDisplayItem,
tile_offset: TileOffset,
@ -983,7 +1048,7 @@ impl FrameContext {
pub fn scroll_node(
&mut self,
origin: LayerPoint,
id: ScrollNodeIdType,
id: ExternalScrollId,
clamp: ScrollClamping
) -> bool {
self.clip_scroll_tree.scroll_node(origin, id, clamp)
@ -1056,6 +1121,7 @@ impl FrameContext {
pipeline_epochs: Vec::new(),
replacements: Vec::new(),
output_pipelines,
id_to_index_mapper: ClipIdToIndexMapper::new(),
};
roller.builder.push_root(
@ -1063,6 +1129,7 @@ impl FrameContext {
&root_pipeline.viewport_size,
&root_pipeline.content_size,
roller.clip_scroll_tree,
&mut roller.id_to_index_mapper,
);
roller.builder.setup_viewport_offset(

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

@ -2,35 +2,34 @@
* 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/. */
use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipAndScrollInfo};
use api::{ClipId, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, Epoch, ExtendMode};
use api::{ExternalScrollId, FontRenderMode, GlyphInstance, GlyphOptions, GradientStop, ImageKey};
use api::{ImageRendering, ItemRange, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize};
use api::{LayerTransform, LayerVector2D, LayoutTransform, LayoutVector2D, LineOrientation};
use api::{LineStyle, LocalClip, PipelineId, PremultipliedColorF, PropertyBinding, RepeatMode};
use api::{ScrollSensitivity, Shadow, TexelRect, TileOffset, TransformStyle, WorldPoint};
use api::{WorldToLayerTransform, YuvColorSpace, YuvData};
use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipId, ColorF};
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 app_units::Au;
use border::ImageBorderSegment;
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
use clip::{ClipChain, ClipRegion, ClipSource, ClipSources, ClipStore};
use clip_scroll_node::{ClipScrollNode, NodeType};
use clip_scroll_tree::ClipScrollTree;
use clip_scroll_tree::{ClipScrollTree, ClipChainIndex};
use euclid::{SideOffsets2D, vec2};
use frame::FrameId;
use frame::{FrameId, ClipIdToIndexMapper};
use glyph_rasterizer::FontInstance;
use gpu_cache::GpuCache;
use gpu_cache::{GpuCache, GpuCacheHandle};
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, PictureType};
use hit_test::{HitTester, HitTestingItem, HitTestingRun};
use internal_types::{FastHashMap, FastHashSet, RenderPassIndex};
use internal_types::{FastHashMap, FastHashSet};
use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface};
use prim_store::{BrushKind, BrushPrimitive, ImageCacheKey, YuvImagePrimitiveCpu};
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, ImageSource, PrimitiveKind};
use prim_store::{PrimitiveContainer, PrimitiveIndex};
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu};
use prim_store::{BrushSegmentDescriptor, PrimitiveRun, TextRunPrimitiveCpu};
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, GradientPrimitiveCpu};
use prim_store::{ImageCacheKey, ImagePrimitiveCpu, ImageSource, PrimitiveContainer};
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveRun, PrimitiveStore};
use prim_store::{ScrollNodeAndClipChain, TextRunPrimitiveCpu};
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use render_task::{ClearMode, ClipChain, RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree};
use render_task::{ClearMode, RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree};
use resource_cache::{ImageRequest, ResourceCache};
use scene::{ScenePipeline, SceneProperties};
use std::{mem, usize, f32};
@ -90,10 +89,10 @@ pub struct FrameBuilder {
// A stack of the current shadow primitives.
// The sub-Vec stores a buffer of fast-path primitives to be appended on pop.
shadow_prim_stack: Vec<(PrimitiveIndex, Vec<(PrimitiveIndex, ClipAndScrollInfo)>)>,
shadow_prim_stack: Vec<(PrimitiveIndex, Vec<(PrimitiveIndex, ScrollNodeAndClipChain)>)>,
// If we're doing any fast-path shadows, we buffer the "real"
// content here, to be appended when the shadow stack is empty.
pending_shadow_contents: Vec<(PrimitiveIndex, ClipAndScrollInfo, LayerPrimitiveInfo)>,
pending_shadow_contents: Vec<(PrimitiveIndex, ScrollNodeAndClipChain, LayerPrimitiveInfo)>,
scrollbar_prims: Vec<ScrollbarPrimitive>,
@ -150,14 +149,14 @@ impl PictureState {
}
pub struct PrimitiveRunContext<'a> {
pub clip_chain: Option<&'a ClipChain>,
pub clip_chain: &'a ClipChain,
pub scroll_node: &'a ClipScrollNode,
pub clip_chain_rect_index: ClipChainRectIndex,
}
impl<'a> PrimitiveRunContext<'a> {
pub fn new(
clip_chain: Option<&'a ClipChain>,
clip_chain: &'a ClipChain,
scroll_node: &'a ClipScrollNode,
clip_chain_rect_index: ClipChainRectIndex,
) -> Self {
@ -252,7 +251,7 @@ impl FrameBuilder {
pub fn add_primitive_to_hit_testing_list(
&mut self,
info: &LayerPrimitiveInfo,
clip_and_scroll: ClipAndScrollInfo
clip_and_scroll: ScrollNodeAndClipChain
) {
let tag = match info.tag {
Some(tag) => tag,
@ -276,7 +275,7 @@ impl FrameBuilder {
pub fn add_primitive_to_draw_list(
&mut self,
prim_index: PrimitiveIndex,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
) {
// Add primitive to the top-most Picture on the stack.
// TODO(gw): Let's consider removing the extra indirection
@ -294,7 +293,7 @@ impl FrameBuilder {
/// to the draw list.
pub fn add_primitive(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
clip_sources: Vec<ClipSource>,
container: PrimitiveContainer,
@ -313,7 +312,7 @@ impl FrameBuilder {
transform_style: TransformStyle,
is_backface_visible: bool,
is_pipeline_root: bool,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
output_pipelines: &FastHashSet<PipelineId>,
) {
// Construct the necessary set of Picture primitives
@ -640,6 +639,7 @@ impl FrameBuilder {
source_perspective: Option<LayoutTransform>,
origin_in_parent_reference_frame: LayerVector2D,
clip_scroll_tree: &mut ClipScrollTree,
id_to_index_mapper: &mut ClipIdToIndexMapper,
) {
let node = ClipScrollNode::new_reference_frame(
parent_id,
@ -651,6 +651,12 @@ impl FrameBuilder {
);
clip_scroll_tree.add_node(node, reference_frame_id);
self.reference_frame_stack.push(reference_frame_id);
match parent_id {
Some(ref parent_id) =>
id_to_index_mapper.map_to_parent_clip_chain(reference_frame_id, parent_id),
_ => id_to_index_mapper.add(reference_frame_id, ClipChainIndex(0)),
}
}
pub fn current_reference_frame_id(&self) -> ClipId {
@ -682,6 +688,7 @@ impl FrameBuilder {
viewport_size: &LayerSize,
content_size: &LayerSize,
clip_scroll_tree: &mut ClipScrollTree,
id_to_index_mapper: &mut ClipIdToIndexMapper,
) -> ClipId {
let viewport_rect = LayerRect::new(LayerPoint::zero(), *viewport_size);
self.push_reference_frame(
@ -693,6 +700,7 @@ impl FrameBuilder {
None,
LayerVector2D::zero(),
clip_scroll_tree,
id_to_index_mapper,
);
let topmost_scrolling_node_id = ClipId::root_scroll_node(pipeline_id);
@ -707,6 +715,7 @@ impl FrameBuilder {
content_size,
ScrollSensitivity::ScriptAndInputEvents,
clip_scroll_tree,
id_to_index_mapper,
);
topmost_scrolling_node_id
@ -716,18 +725,23 @@ impl FrameBuilder {
&mut self,
new_node_id: ClipId,
parent_id: ClipId,
pipeline_id: PipelineId,
clip_region: ClipRegion,
clip_scroll_tree: &mut ClipScrollTree,
id_to_index_mapper: &mut ClipIdToIndexMapper,
) {
let clip_rect = clip_region.main;
let clip_sources = ClipSources::from(clip_region);
debug_assert!(clip_sources.has_clips());
debug_assert!(clip_sources.has_clips());
let handle = self.clip_store.insert(clip_sources);
let node = ClipScrollNode::new_clip_node(pipeline_id, parent_id, handle, clip_rect);
clip_scroll_tree.add_node(node, new_node_id);
let clip_chain_index = clip_scroll_tree.add_clip_node(
new_node_id,
parent_id,
handle,
clip_rect
);
id_to_index_mapper.add(new_node_id, clip_chain_index);
}
pub fn add_scroll_frame(
@ -740,6 +754,7 @@ impl FrameBuilder {
content_size: &LayerSize,
scroll_sensitivity: ScrollSensitivity,
clip_scroll_tree: &mut ClipScrollTree,
id_to_index_mapper: &mut ClipIdToIndexMapper,
) {
let node = ClipScrollNode::new_scroll_frame(
pipeline_id,
@ -751,6 +766,7 @@ impl FrameBuilder {
);
clip_scroll_tree.add_node(node, new_node_id);
id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id);
}
pub fn pop_reference_frame(&mut self) {
@ -760,7 +776,7 @@ impl FrameBuilder {
pub fn push_shadow(
&mut self,
shadow: Shadow,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
) {
let pipeline_id = self.sc_stack.last().unwrap().pipeline_id;
@ -804,7 +820,7 @@ impl FrameBuilder {
pub fn add_solid_rectangle(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
color: ColorF,
segments: Option<BrushSegmentDescriptor>,
@ -833,7 +849,7 @@ impl FrameBuilder {
pub fn add_clear_rectangle(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
) {
let prim = BrushPrimitive::new(
@ -851,7 +867,7 @@ impl FrameBuilder {
pub fn add_scroll_bar(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
color: ColorF,
scrollbar_info: ScrollbarInfo,
@ -883,7 +899,7 @@ impl FrameBuilder {
pub fn add_line(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
wavy_line_thickness: f32,
orientation: LineOrientation,
@ -970,7 +986,7 @@ impl FrameBuilder {
pub fn add_border(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
border_item: &BorderDisplayItem,
gradient_stops: ItemRange<GradientStop>,
@ -1222,7 +1238,7 @@ impl FrameBuilder {
pub fn add_gradient(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
start_point: LayerPoint,
end_point: LayerPoint,
@ -1290,9 +1306,43 @@ impl FrameBuilder {
self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
}
fn add_radial_gradient_impl(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
start_center: LayerPoint,
start_radius: f32,
end_center: LayerPoint,
end_radius: f32,
ratio_xy: f32,
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
) {
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,
},
None,
);
self.add_primitive(
clip_and_scroll,
info,
Vec::new(),
PrimitiveContainer::Brush(prim),
);
}
pub fn add_radial_gradient(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
start_center: LayerPoint,
start_radius: f32,
@ -1304,40 +1354,44 @@ impl FrameBuilder {
tile_size: LayerSize,
tile_spacing: LayerSize,
) {
let tile_repeat = tile_size + tile_spacing;
let prim_infos = info.decompose(
tile_size,
tile_spacing,
64 * 64,
);
let radial_gradient_cpu = RadialGradientPrimitiveCpu {
stops_range: stops,
extend_mode,
gpu_data_count: 0,
gpu_blocks: [
[start_center.x, start_center.y, end_center.x, end_center.y].into(),
[
if prim_infos.is_empty() {
self.add_radial_gradient_impl(
clip_and_scroll,
info,
start_center,
start_radius,
end_center,
end_radius,
ratio_xy,
stops,
extend_mode,
);
} else {
for prim_info in prim_infos {
self.add_radial_gradient_impl(
clip_and_scroll,
&prim_info,
start_center,
start_radius,
end_center,
end_radius,
ratio_xy,
pack_as_float(extend_mode as u32),
].into(),
[
tile_size.width,
tile_size.height,
tile_repeat.width,
tile_repeat.height,
].into(),
],
};
self.add_primitive(
clip_and_scroll,
info,
Vec::new(),
PrimitiveContainer::RadialGradient(radial_gradient_cpu),
);
stops,
extend_mode,
);
}
}
}
pub fn add_text(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
run_offset: LayoutVector2D,
info: &LayerPrimitiveInfo,
font: &FontInstance,
@ -1493,7 +1547,7 @@ impl FrameBuilder {
pub fn add_image(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
stretch_size: LayerSize,
mut tile_spacing: LayerSize,
@ -1573,7 +1627,7 @@ impl FrameBuilder {
pub fn add_yuv_image(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
yuv_data: YuvData,
color_space: YuvColorSpace,
@ -1586,19 +1640,21 @@ impl FrameBuilder {
YuvData::InterleavedYCbCr(plane_0) => [plane_0, ImageKey::DUMMY, ImageKey::DUMMY],
};
let prim_cpu = YuvImagePrimitiveCpu {
yuv_key,
format,
color_space,
image_rendering,
gpu_block: [info.rect.size.width, info.rect.size.height, 0.0, 0.0].into(),
};
let prim = BrushPrimitive::new(
BrushKind::YuvImage {
yuv_key,
format,
color_space,
image_rendering,
},
None,
);
self.add_primitive(
clip_and_scroll,
info,
Vec::new(),
PrimitiveContainer::YuvImage(prim_cpu),
PrimitiveContainer::Brush(prim),
);
}
@ -1807,7 +1863,7 @@ impl FrameBuilder {
let use_dual_source_blending = self.config.dual_source_blending_is_enabled &&
self.config.dual_source_blending_is_supported;
for (pass_index, pass) in passes.iter_mut().enumerate() {
for pass in &mut passes {
let ctx = RenderTargetContext {
device_pixel_scale,
prim_store: &self.prim_store,
@ -1823,7 +1879,6 @@ impl FrameBuilder {
&mut render_tasks,
&mut deferred_resolves,
&self.clip_store,
RenderPassIndex(pass_index),
);
if let RenderPassKind::OffScreen { ref texture_cache, .. } = pass.kind {
@ -1863,3 +1918,67 @@ impl FrameBuilder {
)
}
}
trait PrimitiveInfoTiler {
fn decompose(
&self,
tile_size: LayerSize,
tile_spacing: LayerSize,
max_prims: usize,
) -> Vec<LayerPrimitiveInfo>;
}
impl PrimitiveInfoTiler for LayerPrimitiveInfo {
fn decompose(
&self,
tile_size: LayerSize,
tile_spacing: LayerSize,
max_prims: usize,
) -> Vec<LayerPrimitiveInfo> {
let mut prims = Vec::new();
let tile_repeat = tile_size + tile_spacing;
if tile_repeat.width <= 0.0 ||
tile_repeat.height <= 0.0 {
return prims;
}
if tile_repeat.width < self.rect.size.width ||
tile_repeat.height < self.rect.size.height {
let local_clip = self.local_clip.clip_by(&self.rect);
let rect_p0 = self.rect.origin;
let rect_p1 = self.rect.bottom_right();
let mut y0 = rect_p0.y;
while y0 < rect_p1.y {
let mut x0 = rect_p0.x;
while x0 < rect_p1.x {
prims.push(LayerPrimitiveInfo {
rect: LayerRect::new(
LayerPoint::new(x0, y0),
tile_size,
),
local_clip,
is_backface_visible: self.is_backface_visible,
tag: self.tag,
});
// Mostly a safety against a crazy number of primitives
// being generated. If we exceed that amount, just bail
// out and only draw the maximum amount.
if prims.len() > max_prims {
warn!("too many prims found due to repeat/tile. dropping extra prims!");
return prims;
}
x0 += tile_repeat.width;
}
y0 += tile_repeat.height;
}
}
prims
}
}

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

@ -628,16 +628,17 @@ fn rasterize_200_glyphs() {
// This test loads a font from disc, the renders 4 requests containing
// 50 glyphs each, deletes the font and waits for the result.
use rayon::Configuration;
use rayon::ThreadPoolBuilder;
use std::fs::File;
use std::io::Read;
let worker_config = Configuration::new()
let worker = ThreadPoolBuilder::new()
.thread_name(|idx|{ format!("WRWorker#{}", idx) })
.start_handler(move |idx| {
register_thread_with_profiler(format!("WRWorker#{}", idx));
});
let workers = Arc::new(ThreadPool::new(worker_config).unwrap());
})
.build();
let workers = Arc::new(worker.unwrap());
let mut glyph_rasterizer = GlyphRasterizer::new(workers).unwrap();
let mut glyph_cache = GlyphCache::new();
let mut gpu_cache = GpuCache::new();

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

@ -147,6 +147,14 @@ impl From<CompositePrimitiveInstance> for PrimitiveInstance {
}
}
bitflags! {
/// Flags that define how the common brush shader
/// code should process this instance.
pub struct BrushFlags: u8 {
const PERSPECTIVE_INTERPOLATION = 0x1;
}
}
// TODO(gw): While we are comverting things over, we
// need to have the instance be the same
// size as an old PrimitiveInstance. In the
@ -164,6 +172,7 @@ pub struct BrushInstance {
pub z: i32,
pub segment_index: i32,
pub edge_flags: EdgeAaSegmentMask,
pub brush_flags: BrushFlags,
pub user_data: [i32; 3],
}
@ -175,7 +184,9 @@ impl From<BrushInstance> for PrimitiveInstance {
instance.prim_address.as_int(),
((instance.clip_chain_rect_index.0 as i32) << 16) | instance.scroll_id.0 as i32,
instance.z,
instance.segment_index | ((instance.edge_flags.bits() as i32) << 16),
instance.segment_index |
((instance.edge_flags.bits() as i32) << 16) |
((instance.brush_flags.bits() as i32) << 24),
instance.user_data[0],
instance.user_data[1],
instance.user_data[2],

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

@ -2,13 +2,14 @@
* 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/. */
use api::{BorderRadius, ClipAndScrollInfo, ClipId, ClipMode, HitTestFlags, HitTestItem};
use api::{HitTestResult, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect};
use api::{LayerToWorldTransform, LocalClip, PipelineId, WorldPoint};
use api::{BorderRadius, ClipId, ClipMode, HitTestFlags, HitTestItem, HitTestResult, ItemTag};
use api::{LayerPoint, LayerPrimitiveInfo, LayerRect, LayerToWorldTransform, LocalClip, PipelineId};
use api::WorldPoint;
use clip::{ClipSource, ClipStore, Contains, rounded_rectangle_contains_point};
use clip_scroll_node::{ClipScrollNode, NodeType};
use clip_scroll_tree::ClipScrollTree;
use clip_scroll_tree::{ClipChainIndex, ClipScrollTree};
use internal_types::FastHashMap;
use prim_store::ScrollNodeAndClipChain;
/// 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,
@ -33,11 +34,21 @@ pub struct HitTestClipScrollNode {
/// handled the same way during hit testing. Once we represent all ClipChains
/// using ClipChainDescriptors, we can get rid of this and just use the
/// ClipChainDescriptor here.
#[derive(Clone)]
struct HitTestClipChainDescriptor {
parent: Option<ClipId>,
parent: Option<ClipChainIndex>,
clips: Vec<ClipId>,
}
impl HitTestClipChainDescriptor {
fn empty() -> HitTestClipChainDescriptor {
HitTestClipChainDescriptor {
parent: None,
clips: Vec::new(),
}
}
}
#[derive(Clone)]
pub struct HitTestingItem {
rect: LayerRect,
@ -56,7 +67,7 @@ impl HitTestingItem {
}
#[derive(Clone)]
pub struct HitTestingRun(pub Vec<HitTestingItem>, pub ClipAndScrollInfo);
pub struct HitTestingRun(pub Vec<HitTestingItem>, pub ScrollNodeAndClipChain);
enum HitTestRegion {
Rectangle(LayerRect),
@ -78,7 +89,7 @@ impl HitTestRegion {
pub struct HitTester {
runs: Vec<HitTestingRun>,
nodes: FastHashMap<ClipId, HitTestClipScrollNode>,
clip_chains: FastHashMap<ClipId, HitTestClipChainDescriptor>,
clip_chains: Vec<HitTestClipChainDescriptor>,
}
impl HitTester {
@ -90,7 +101,7 @@ impl HitTester {
let mut hit_tester = HitTester {
runs: runs.clone(),
nodes: FastHashMap::default(),
clip_chains: FastHashMap::default(),
clip_chains: Vec::new(),
};
hit_tester.read_clip_scroll_tree(clip_scroll_tree, clip_store);
hit_tester
@ -102,6 +113,11 @@ impl HitTester {
clip_store: &ClipStore
) {
self.nodes.clear();
self.clip_chains.clear();
self.clip_chains.resize(
clip_scroll_tree.clip_chains.len(),
HitTestClipChainDescriptor::empty()
);
for (id, node) in &clip_scroll_tree.nodes {
self.nodes.insert(*id, HitTestClipScrollNode {
@ -111,52 +127,50 @@ impl HitTester {
node_origin: node.local_viewport_rect.origin,
});
self.clip_chains.insert(*id, HitTestClipChainDescriptor {
parent: node.parent,
clips: vec![*id],
});
if let NodeType::Clip { clip_chain_index, .. } = node.node_type {
let clip_chain = self.clip_chains.get_mut(clip_chain_index.0).unwrap();
clip_chain.parent =
clip_scroll_tree.get_clip_chain(clip_chain_index).parent_index;
clip_chain.clips = vec![*id];
}
}
for descriptor in &clip_scroll_tree.clip_chains_descriptors {
self.clip_chains.insert(
ClipId::ClipChain(descriptor.id),
HitTestClipChainDescriptor {
parent: descriptor.parent.map(|id| ClipId::ClipChain(id)),
clips: descriptor.clips.clone(),
}
);
let clip_chain = self.clip_chains.get_mut(descriptor.index.0).unwrap();
clip_chain.parent = clip_scroll_tree.get_clip_chain(descriptor.index).parent_index;
clip_chain.clips = descriptor.clips.clone();
}
}
fn is_point_clipped_in_for_clip_chain(
&self,
point: WorldPoint,
chain_id: &ClipId,
clip_chain_index: ClipChainIndex,
test: &mut HitTest
) -> bool {
if let Some(result) = test.clip_chain_cache.get(&chain_id) {
return *result;
if let Some(result) = test.get_from_clip_chain_cache(clip_chain_index) {
return result;
}
let descriptor = &self.clip_chains[&chain_id];
let descriptor = &self.clip_chains[clip_chain_index.0];
let parent_clipped_in = match descriptor.parent {
None => true,
Some(ref parent) => self.is_point_clipped_in_for_clip_chain(point, parent, test),
Some(parent) => self.is_point_clipped_in_for_clip_chain(point, parent, test),
};
if !parent_clipped_in {
test.clip_chain_cache.insert(*chain_id, false);
test.set_in_clip_chain_cache(clip_chain_index, false);
return false;
}
for clip_node in &descriptor.clips {
if !self.is_point_clipped_in_for_node(point, clip_node, test) {
test.clip_chain_cache.insert(*chain_id, false);
test.set_in_clip_chain_cache(clip_chain_index, false);
return false;
}
}
test.clip_chain_cache.insert(*chain_id, true);
test.set_in_clip_chain_cache(clip_chain_index, true);
true
}
@ -197,7 +211,9 @@ impl HitTester {
let mut result = HitTestResult::default();
for &HitTestingRun(ref items, ref clip_and_scroll) in self.runs.iter().rev() {
let scroll_node = &self.nodes[&clip_and_scroll.scroll_node_id];
let scroll_node_id = clip_and_scroll.scroll_node_id;
let scroll_node = &self.nodes[&scroll_node_id];
let pipeline_id = scroll_node_id.pipeline_id();
match (test.pipeline_id, clip_and_scroll.scroll_node_id.pipeline_id()) {
(Some(id), node_id) if node_id != id => continue,
_ => {},
@ -215,12 +231,11 @@ impl HitTester {
continue;
}
let clip_id = &clip_and_scroll.clip_node_id();
let clip_chain_index = clip_and_scroll.clip_chain_index;
clipped_in |=
self.is_point_clipped_in_for_clip_chain(point, clip_chain_index, &mut test);
if !clipped_in {
clipped_in = self.is_point_clipped_in_for_clip_chain(point, clip_id, &mut test);
if !clipped_in {
break;
}
break;
}
// We need to trigger a lookup against the root reference frame here, because
@ -228,7 +243,7 @@ impl HitTester {
// hierarchy. If we don't have a valid point for this test, we are likely
// in a situation where the reference frame has an univertible transform, but the
// item's clip does not.
let root_reference_frame = ClipId::root_reference_frame(clip_id.pipeline_id());
let root_reference_frame = ClipId::root_reference_frame(pipeline_id);
if !self.is_point_clipped_in_for_node(point, &root_reference_frame, &mut test) {
continue;
}
@ -238,7 +253,7 @@ impl HitTester {
};
result.items.push(HitTestItem {
pipeline: clip_and_scroll.clip_node_id().pipeline_id(),
pipeline: pipeline_id,
tag: item.tag,
point_in_viewport,
point_relative_to_item: point_in_layer - item.rect.origin.to_vector(),
@ -259,7 +274,7 @@ fn get_regions_for_clip_scroll_node(
clip_store: &ClipStore
) -> Vec<HitTestRegion> {
let clips = match node.node_type {
NodeType::Clip(ref handle) => clip_store.get(handle).clips(),
NodeType::Clip{ ref handle, .. } => clip_store.get(handle).clips(),
_ => return Vec::new(),
};
@ -280,7 +295,7 @@ pub struct HitTest {
point: WorldPoint,
flags: HitTestFlags,
node_cache: FastHashMap<ClipId, Option<LayerPoint>>,
clip_chain_cache: FastHashMap<ClipId, bool>,
clip_chain_cache: Vec<Option<bool>>,
}
impl HitTest {
@ -294,10 +309,25 @@ impl HitTest {
point,
flags,
node_cache: FastHashMap::default(),
clip_chain_cache: FastHashMap::default(),
clip_chain_cache: Vec::new(),
}
}
pub fn get_from_clip_chain_cache(&mut self, index: ClipChainIndex) -> Option<bool> {
if index.0 >= self.clip_chain_cache.len() {
None
} else {
self.clip_chain_cache[index.0]
}
}
pub fn set_in_clip_chain_cache(&mut self, index: ClipChainIndex, value: bool) {
if index.0 >= self.clip_chain_cache.len() {
self.clip_chain_cache.resize(index.0 + 1, None);
}
self.clip_chain_cache[index.0] = Some(value);
}
pub fn get_absolute_point(&self, hit_tester: &HitTester) -> WorldPoint {
if !self.flags.contains(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT) {
return self.point;

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

@ -44,7 +44,11 @@ pub struct CacheTextureId(pub usize);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderPassIndex(pub usize);
pub struct SavedTargetIndex(pub usize);
impl SavedTargetIndex {
pub const PENDING: Self = SavedTargetIndex(!0);
}
// Represents the source for a texture.
// These are passed from throughout the
@ -61,10 +65,7 @@ pub enum SourceTexture {
External(ExternalImageData),
CacheA8,
CacheRGBA8,
// XXX Remove this once RenderTaskCacheA8 is used.
#[allow(dead_code)]
RenderTaskCacheA8(RenderPassIndex),
RenderTaskCacheRGBA8(RenderPassIndex),
RenderTaskCache(SavedTargetIndex),
}
pub const ORTHO_NEAR_PLANE: f32 = -1000000.0;

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

@ -2,15 +2,15 @@
* 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/. */
use api::{ColorF, ClipAndScrollInfo, FilterOp, MixBlendMode};
use api::{DeviceIntPoint, DeviceIntRect, LayerToWorldScale, PipelineId};
use api::{BoxShadowClipMode, LayerPoint, LayerRect, LayerVector2D, Shadow};
use api::{ClipId, PremultipliedColorF};
use api::{BoxShadowClipMode, ClipId, ColorF, DeviceIntPoint, DeviceIntRect, FilterOp, LayerPoint};
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_types::{BrushImageKind, PictureType};
use prim_store::{BrushKind, BrushPrimitive, PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
use prim_store::ScrollNodeAndClipChain;
use render_task::{ClearMode, RenderTask, RenderTaskCacheKey};
use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation};
use resource_cache::CacheItem;
@ -230,7 +230,7 @@ impl PicturePrimitive {
pub fn add_primitive(
&mut self,
prim_index: PrimitiveIndex,
clip_and_scroll: ClipAndScrollInfo
clip_and_scroll: ScrollNodeAndClipChain
) {
if let Some(ref mut run) = self.runs.last_mut() {
if run.clip_and_scroll == clip_and_scroll &&
@ -368,7 +368,7 @@ impl PicturePrimitive {
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
let rect = (prim_local_rect.translate(&-offset) * content_scale).round().to_i32();
let picture_task = RenderTask::new_picture(
let mut picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, rect.size),
prim_index,
RenderTargetKind::Color,
@ -378,6 +378,7 @@ impl PicturePrimitive {
pic_state_for_children.tasks,
PictureType::Image,
);
picture_task.mark_for_saving();
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let picture_task_id = frame_state.render_tasks.add(picture_task);
@ -601,7 +602,7 @@ impl PicturePrimitive {
match composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::ColorMatrix(m))) => {
for i in 0..5 {
request.push([m[i], m[i+5], m[i+10], m[i+15]]);
request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
}
}
Some(PictureCompositeMode::Filter(filter)) => {

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

@ -2,25 +2,24 @@
* 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/. */
use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipAndScrollInfo, ClipMode};
use api::{ColorF, DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch};
use api::{ComplexClipRegion, ExtendMode, FontRenderMode};
use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipId, ClipMode, ColorF, ComplexClipRegion};
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};
use api::{WorldToLayerTransform, YuvColorSpace, YuvFormat};
use api::{LineStyle, PremultipliedColorF, WorldToLayerTransform, YuvColorSpace, YuvFormat};
use border::{BorderCornerInstance, BorderEdgeKind};
use clip_scroll_tree::{CoordinateSystemId};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId};
use clip_scroll_node::ClipScrollNode;
use clip::{ClipSource, ClipSourcesHandle};
use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSource};
use clip::{ClipSourcesHandle, ClipWorkItem};
use frame_builder::{FrameContext, FrameState, PictureContext, PictureState, PrimitiveRunContext};
use glyph_rasterizer::{FontInstance, FontTransform};
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
ToGpuBlocks};
use gpu_types::{ClipChainRectIndex};
use picture::{PictureKind, PicturePrimitive};
use render_task::{BlitSource, ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipWorkItem};
use render_task::{RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId};
use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind};
use render_task::RenderTaskId;
use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
use resource_cache::{CacheItem, ImageProperties, ImageRequest, ResourceCache};
use segment::SegmentBuilder;
@ -32,11 +31,23 @@ use util::recycle_vec;
const MIN_BRUSH_SPLIT_AREA: f32 = 128.0 * 128.0;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ScrollNodeAndClipChain {
pub scroll_node_id: ClipId,
pub clip_chain_index: ClipChainIndex,
}
impl ScrollNodeAndClipChain {
pub fn new(scroll_node_id: ClipId, clip_chain_index: ClipChainIndex) -> ScrollNodeAndClipChain {
ScrollNodeAndClipChain { scroll_node_id, clip_chain_index }
}
}
#[derive(Debug)]
pub struct PrimitiveRun {
pub base_prim_index: PrimitiveIndex,
pub count: usize,
pub clip_and_scroll: ClipAndScrollInfo,
pub clip_and_scroll: ScrollNodeAndClipChain,
}
#[derive(Debug, Copy, Clone)]
@ -112,11 +123,9 @@ pub struct PrimitiveIndex(pub usize);
pub enum PrimitiveKind {
TextRun,
Image,
YuvImage,
Border,
AlignedGradient,
AngleGradient,
RadialGradient,
Picture,
Brush,
}
@ -195,6 +204,22 @@ pub enum BrushKind {
current_epoch: Epoch,
alpha_type: AlphaType,
},
YuvImage {
yuv_key: [ImageKey; 3],
format: YuvFormat,
color_space: YuvColorSpace,
image_rendering: ImageRendering,
},
RadialGradient {
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,
}
}
impl BrushKind {
@ -202,7 +227,9 @@ impl BrushKind {
match *self {
BrushKind::Solid { .. } |
BrushKind::Picture |
BrushKind::Image { .. } => true,
BrushKind::Image { .. } |
BrushKind::YuvImage { .. } |
BrushKind::RadialGradient { .. } => true,
BrushKind::Mask { .. } |
BrushKind::Clear |
@ -284,7 +311,8 @@ impl BrushPrimitive {
// has to match VECS_PER_SPECIFIC_BRUSH
match self.kind {
BrushKind::Picture |
BrushKind::Image { .. } => {
BrushKind::Image { .. } |
BrushKind::YuvImage { .. } => {
}
BrushKind::Solid { color } => {
request.push(color.premultiplied());
@ -331,6 +359,20 @@ impl BrushPrimitive {
0.0,
]);
}
BrushKind::RadialGradient { start_center, end_center, start_radius, end_radius, ratio_xy, extend_mode, .. } => {
request.push([
start_center.x,
start_center.y,
end_center.x,
end_center.y,
]);
request.push([
start_radius,
end_radius,
ratio_xy,
pack_as_float(extend_mode as u32),
]);
}
}
}
}
@ -377,24 +419,6 @@ impl ToGpuBlocks for ImagePrimitiveCpu {
}
}
#[derive(Debug)]
pub struct YuvImagePrimitiveCpu {
pub yuv_key: [ImageKey; 3],
pub format: YuvFormat,
pub color_space: YuvColorSpace,
pub image_rendering: ImageRendering,
// TODO(gw): Generate on demand
pub gpu_block: GpuBlockData,
}
impl ToGpuBlocks for YuvImagePrimitiveCpu {
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
request.push(self.gpu_block);
}
}
#[derive(Debug)]
pub struct BorderPrimitiveCpu {
pub corner_instances: [BorderCornerInstance; 4],
@ -631,27 +655,6 @@ impl<'a> GradientGpuBlockBuilder<'a> {
}
}
#[derive(Debug)]
pub struct RadialGradientPrimitiveCpu {
pub stops_range: ItemRange<GradientStop>,
pub extend_mode: ExtendMode,
pub gpu_data_count: i32,
pub gpu_blocks: [GpuBlockData; 3],
}
impl RadialGradientPrimitiveCpu {
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(false, &mut request);
}
}
#[derive(Debug, Clone)]
pub struct TextRunPrimitiveCpu {
pub font: FontInstance,
@ -933,11 +936,9 @@ impl ClipData {
pub enum PrimitiveContainer {
TextRun(TextRunPrimitiveCpu),
Image(ImagePrimitiveCpu),
YuvImage(YuvImagePrimitiveCpu),
Border(BorderPrimitiveCpu),
AlignedGradient(GradientPrimitiveCpu),
AngleGradient(GradientPrimitiveCpu),
RadialGradient(RadialGradientPrimitiveCpu),
Picture(PicturePrimitive),
Brush(BrushPrimitive),
}
@ -948,9 +949,7 @@ pub struct PrimitiveStore {
pub cpu_text_runs: Vec<TextRunPrimitiveCpu>,
pub cpu_pictures: Vec<PicturePrimitive>,
pub cpu_images: Vec<ImagePrimitiveCpu>,
pub cpu_yuv_images: Vec<YuvImagePrimitiveCpu>,
pub cpu_gradients: Vec<GradientPrimitiveCpu>,
pub cpu_radial_gradients: Vec<RadialGradientPrimitiveCpu>,
pub cpu_metadata: Vec<PrimitiveMetadata>,
pub cpu_borders: Vec<BorderPrimitiveCpu>,
}
@ -963,9 +962,7 @@ impl PrimitiveStore {
cpu_text_runs: Vec::new(),
cpu_pictures: Vec::new(),
cpu_images: Vec::new(),
cpu_yuv_images: Vec::new(),
cpu_gradients: Vec::new(),
cpu_radial_gradients: Vec::new(),
cpu_borders: Vec::new(),
}
}
@ -977,9 +974,7 @@ 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_yuv_images: recycle_vec(self.cpu_yuv_images),
cpu_gradients: recycle_vec(self.cpu_gradients),
cpu_radial_gradients: recycle_vec(self.cpu_radial_gradients),
cpu_borders: recycle_vec(self.cpu_borders),
}
}
@ -1018,6 +1013,8 @@ impl PrimitiveStore {
BrushKind::Mask { .. } => PrimitiveOpacity::translucent(),
BrushKind::Line { .. } => PrimitiveOpacity::translucent(),
BrushKind::Image { .. } => PrimitiveOpacity::translucent(),
BrushKind::YuvImage { .. } => PrimitiveOpacity::opaque(),
BrushKind::RadialGradient { .. } => PrimitiveOpacity::translucent(),
BrushKind::Picture => {
// TODO(gw): This is not currently used. In the future
// we should detect opaque pictures.
@ -1069,17 +1066,6 @@ impl PrimitiveStore {
self.cpu_images.push(image_cpu);
metadata
}
PrimitiveContainer::YuvImage(image_cpu) => {
let metadata = PrimitiveMetadata {
opacity: PrimitiveOpacity::opaque(),
prim_kind: PrimitiveKind::YuvImage,
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_yuv_images.len()),
..base_metadata
};
self.cpu_yuv_images.push(image_cpu);
metadata
}
PrimitiveContainer::Border(border_cpu) => {
let metadata = PrimitiveMetadata {
opacity: PrimitiveOpacity::translucent(),
@ -1114,18 +1100,6 @@ impl PrimitiveStore {
self.cpu_gradients.push(gradient_cpu);
metadata
}
PrimitiveContainer::RadialGradient(radial_gradient_cpu) => {
let metadata = PrimitiveMetadata {
// TODO: calculate if the gradient is actually opaque
opacity: PrimitiveOpacity::translucent(),
prim_kind: PrimitiveKind::RadialGradient,
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_radial_gradients.len()),
..base_metadata
};
self.cpu_radial_gradients.push(radial_gradient_cpu);
metadata
}
};
self.cpu_metadata.push(metadata);
@ -1293,22 +1267,6 @@ impl PrimitiveStore {
}
}
}
PrimitiveKind::YuvImage => {
let image_cpu = &mut self.cpu_yuv_images[metadata.cpu_prim_index.0];
let channel_num = image_cpu.format.get_plane_num();
debug_assert!(channel_num <= 3);
for channel in 0 .. channel_num {
frame_state.resource_cache.request_image(
ImageRequest {
key: image_cpu.yuv_key[channel],
rendering: image_cpu.image_rendering,
tile: None,
},
frame_state.gpu_cache,
);
}
}
PrimitiveKind::Brush => {
let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
@ -1332,6 +1290,32 @@ impl PrimitiveStore {
frame_state.gpu_cache,
);
}
BrushKind::YuvImage { format, yuv_key, image_rendering, .. } => {
let channel_num = format.get_plane_num();
debug_assert!(channel_num <= 3);
for channel in 0 .. channel_num {
frame_state.resource_cache.request_image(
ImageRequest {
key: yuv_key[channel],
rendering: image_rendering,
tile: None,
},
frame_state.gpu_cache,
);
}
}
BrushKind::RadialGradient { ref mut stops_handle, stops_range, .. } => {
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(
false,
&mut request,
);
}
}
BrushKind::Mask { .. } |
BrushKind::Solid { .. } |
BrushKind::Clear |
@ -1340,8 +1324,7 @@ impl PrimitiveStore {
}
}
PrimitiveKind::AlignedGradient |
PrimitiveKind::AngleGradient |
PrimitiveKind::RadialGradient => {}
PrimitiveKind::AngleGradient => {}
}
// Mark this GPU resource as required for this frame.
@ -1359,10 +1342,6 @@ impl PrimitiveStore {
let image = &self.cpu_images[metadata.cpu_prim_index.0];
image.write_gpu_blocks(request);
}
PrimitiveKind::YuvImage => {
let yuv_image = &self.cpu_yuv_images[metadata.cpu_prim_index.0];
yuv_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(
@ -1377,13 +1356,6 @@ impl PrimitiveStore {
request,
);
}
PrimitiveKind::RadialGradient => {
let gradient = &self.cpu_radial_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);
@ -1634,12 +1606,9 @@ impl PrimitiveStore {
}
};
let mut combined_outer_rect = match prim_run_context.clip_chain {
Some(ref chain) => prim_screen_rect.intersection(&chain.combined_outer_screen_rect),
None => Some(prim_screen_rect),
};
let clip_chain = prim_run_context.clip_chain.map_or(None, |x| x.nodes.clone());
let mut combined_outer_rect =
prim_screen_rect.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect);
let clip_chain = prim_run_context.clip_chain.nodes.clone();
let prim_coordinate_system_id = prim_run_context.scroll_node.coordinate_system_id;
let transform = &prim_run_context.scroll_node.world_content_transform;
@ -1860,12 +1829,8 @@ impl PrimitiveStore {
frame_context.device_pixel_scale,
);
let clip_bounds = match prim_run_context.clip_chain {
Some(ref node) => node.combined_outer_screen_rect,
None => frame_context.screen_rect,
};
metadata.screen_rect = screen_bounding_rect
.intersection(&clip_bounds)
.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect)
.map(|clipped| {
ScreenRect {
clipped,
@ -1935,7 +1900,7 @@ impl PrimitiveStore {
.nodes[&run.clip_and_scroll.scroll_node_id];
let clip_chain = frame_context
.clip_scroll_tree
.get_clip_chain(&run.clip_and_scroll.clip_node_id());
.get_clip_chain(run.clip_and_scroll.clip_chain_index);
if pic_context.perform_culling {
if !scroll_node.invertible {
@ -1943,16 +1908,12 @@ impl PrimitiveStore {
continue;
}
match clip_chain {
Some(ref chain) if chain.combined_outer_screen_rect.is_empty() => {
debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id);
continue;
}
_ => {},
if clip_chain.combined_outer_screen_rect.is_empty() {
debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id);
continue;
}
}
let parent_relative_transform = pic_context
.inv_world_transform
.map(|inv_parent| {
@ -2082,14 +2043,9 @@ fn convert_clip_chain_to_clip_vector(
fn get_local_clip_rect_for_nodes(
scroll_node: &ClipScrollNode,
clip_chain: Option<&ClipChain>,
clip_chain: &ClipChain,
) -> Option<LayerRect> {
let clip_chain_nodes = match clip_chain {
Some(ref clip_chain) => clip_chain.nodes.clone(),
None => return None,
};
let local_rect = ClipChainNodeIter { current: clip_chain_nodes }.fold(
let local_rect = ClipChainNodeIter { current: clip_chain.nodes.clone() }.fold(
None,
|combined_local_clip_rect: Option<LayerRect>, node| {
if node.work_item.coordinate_system_id != scroll_node.coordinate_system_id {

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

@ -300,6 +300,9 @@ impl ProfileCounter for AverageTimeProfileCounter {
pub struct FrameProfileCounters {
pub total_primitives: IntProfileCounter,
pub visible_primitives: IntProfileCounter,
pub targets_used: IntProfileCounter,
pub targets_changed: IntProfileCounter,
pub targets_created: IntProfileCounter,
}
impl FrameProfileCounters {
@ -307,8 +310,16 @@ impl FrameProfileCounters {
FrameProfileCounters {
total_primitives: IntProfileCounter::new("Total Primitives"),
visible_primitives: IntProfileCounter::new("Visible Primitives"),
targets_used: IntProfileCounter::new("Used targets"),
targets_changed: IntProfileCounter::new("Changed targets"),
targets_created: IntProfileCounter::new("Created targets"),
}
}
pub fn reset_targets(&mut self) {
self.targets_used.reset();
self.targets_changed.reset();
self.targets_created.reset();
}
}
#[derive(Clone)]
@ -840,7 +851,7 @@ impl Profiler {
}
}
fn draw_gpu_cache_bar(
fn draw_bar(
&mut self,
label: &str,
label_color: ColorU,
@ -898,9 +909,9 @@ impl Profiler {
value: counters.allocated_rows.value * MAX_VERTEX_TEXTURE_WIDTH,
};
let rect0 = self.draw_gpu_cache_bar(
let rect0 = self.draw_bar(
&format!("GPU cache rows ({}):", counters.allocated_rows.value),
ColorU::new(255, 255, 255, 255),
ColorU::new(0xFF, 0xFF, 0xFF, 0xFF),
&[
(color_updated, &counters.updated_rows),
(color_free, &counters.allocated_rows),
@ -908,14 +919,53 @@ impl Profiler {
debug_renderer,
);
let rect1 = self.draw_gpu_cache_bar(
let rect1 = self.draw_bar(
"GPU cache blocks",
ColorU::new(255, 255, 0, 255),
ColorU::new(0xFF, 0xFF, 0, 0xFF),
&[
(color_updated, &counters.updated_blocks),
(color_saved, &requested_blocks),
(color_free, &counters.allocated_blocks),
(ColorU::new(0, 0, 0, 255), &total_blocks),
(ColorU::new(0, 0, 0, 0xFF), &total_blocks),
],
debug_renderer,
);
let total_rect = rect0.union(&rect1).inflate(10.0, 10.0);
debug_renderer.add_quad(
total_rect.origin.x,
total_rect.origin.y,
total_rect.origin.x + total_rect.size.width,
total_rect.origin.y + total_rect.size.height,
ColorF::new(0.1, 0.1, 0.1, 0.8).into(),
ColorF::new(0.2, 0.2, 0.2, 0.8).into(),
);
self.draw_state.y_left = total_rect.origin.y + total_rect.size.height + 30.0;
}
fn draw_frame_bars(
&mut self,
counters: &FrameProfileCounters,
debug_renderer: &mut DebugRenderer,
) {
let rect0 = self.draw_bar(
&format!("primitives ({}):", counters.total_primitives.value),
ColorU::new(0xFF, 0xFF, 0xFF, 0xFF),
&[
(ColorU::new(0, 0, 0xFF, 0xFF), &counters.visible_primitives),
(ColorU::new(0, 0, 0, 0xFF), &counters.total_primitives),
],
debug_renderer,
);
let rect1 = self.draw_bar(
&format!("GPU targets ({}):", &counters.targets_used.value),
ColorU::new(0xFF, 0xFF, 0, 0xFF),
&[
(ColorU::new(0, 0, 0xFF, 0xFF), &counters.targets_created),
(ColorU::new(0xFF, 0, 0, 0xFF), &counters.targets_changed),
(ColorU::new(0, 0xFF, 0, 0xFF), &counters.targets_used),
],
debug_renderer,
);
@ -1017,15 +1067,7 @@ impl Profiler {
);
for frame_profile in frame_profiles {
Profiler::draw_counters(
&[
&frame_profile.total_primitives,
&frame_profile.visible_primitives,
],
debug_renderer,
true,
&mut self.draw_state
);
self.draw_frame_bars(frame_profile, debug_renderer);
}
Profiler::draw_counters(

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

@ -2,22 +2,21 @@
* 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/. */
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{ImageDescriptor, ImageFormat, LayerRect, PremultipliedColorF};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, ImageDescriptor, ImageFormat};
use api::PremultipliedColorF;
use box_shadow::BoxShadowCacheKey;
use clip::{ClipSourcesWeakHandle};
use clip::ClipWorkItem;
use clip_scroll_tree::CoordinateSystemId;
use device::TextureFilter;
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, PictureType};
use internal_types::{FastHashMap, RenderPassIndex, SourceTexture};
use gpu_types::PictureType;
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::ContentOrigin;
use prim_store::{PrimitiveIndex, ImageCacheKey};
#[cfg(feature = "debugger")]
use print_tree::{PrintTreePrinter};
use resource_cache::CacheItem;
use std::{cmp, ops, usize, f32, i32};
use std::rc::Rc;
use texture_cache::{TextureCache, TextureCacheHandle};
use tiling::{RenderPass, RenderTargetIndex};
use tiling::{RenderTargetKind};
@ -43,91 +42,7 @@ pub struct RenderTaskAddress(pub u32);
pub struct RenderTaskTree {
pub tasks: Vec<RenderTask>,
pub task_data: Vec<RenderTaskData>,
}
pub type ClipChainNodeRef = Option<Rc<ClipChainNode>>;
#[derive(Debug, Clone)]
pub struct ClipChainNode {
pub work_item: ClipWorkItem,
pub local_clip_rect: LayerRect,
pub screen_outer_rect: DeviceIntRect,
pub screen_inner_rect: DeviceIntRect,
pub prev: ClipChainNodeRef,
}
#[derive(Debug, Clone)]
pub struct ClipChain {
pub combined_outer_screen_rect: DeviceIntRect,
pub combined_inner_screen_rect: DeviceIntRect,
pub nodes: ClipChainNodeRef,
}
impl ClipChain {
pub fn empty(screen_rect: &DeviceIntRect) -> ClipChain {
ClipChain {
combined_inner_screen_rect: *screen_rect,
combined_outer_screen_rect: *screen_rect,
nodes: None,
}
}
pub fn new_with_added_node(
&self,
work_item: ClipWorkItem,
local_clip_rect: LayerRect,
screen_outer_rect: DeviceIntRect,
screen_inner_rect: DeviceIntRect,
) -> ClipChain {
let new_node = ClipChainNode {
work_item,
local_clip_rect,
screen_outer_rect,
screen_inner_rect,
prev: None,
};
let mut new_chain = self.clone();
new_chain.add_node(new_node);
new_chain
}
pub fn add_node(&mut self, mut new_node: ClipChainNode) {
new_node.prev = self.nodes.clone();
// If this clip's outer rectangle is completely enclosed by the clip
// chain's inner rectangle, then the only clip that matters from this point
// on is this clip. We can disconnect this clip from the parent clip chain.
if self.combined_inner_screen_rect.contains_rect(&new_node.screen_outer_rect) {
new_node.prev = None;
}
self.combined_outer_screen_rect =
self.combined_outer_screen_rect.intersection(&new_node.screen_outer_rect)
.unwrap_or_else(DeviceIntRect::zero);
self.combined_inner_screen_rect =
self.combined_inner_screen_rect.intersection(&new_node.screen_inner_rect)
.unwrap_or_else(DeviceIntRect::zero);
self.nodes = Some(Rc::new(new_node));
}
}
pub struct ClipChainNodeIter {
pub current: ClipChainNodeRef,
}
impl Iterator for ClipChainNodeIter {
type Item = Rc<ClipChainNode>;
fn next(&mut self) -> ClipChainNodeRef {
let previous = self.current.clone();
self.current = match self.current {
Some(ref item) => item.prev.clone(),
None => return None,
};
previous
}
next_saved: SavedTargetIndex,
}
impl RenderTaskTree {
@ -135,6 +50,7 @@ impl RenderTaskTree {
RenderTaskTree {
tasks: Vec::new(),
task_data: Vec::new(),
next_saved: SavedTargetIndex(0),
}
}
@ -195,10 +111,16 @@ impl RenderTaskTree {
}
pub fn build(&mut self) {
for task in &mut self.tasks {
for task in &self.tasks {
self.task_data.push(task.write_task_data());
}
}
pub fn save_target(&mut self) -> SavedTargetIndex {
let id = self.next_saved;
self.next_saved.0 += 1;
id
}
}
impl ops::Index<RenderTaskId> for RenderTaskTree {
@ -223,15 +145,6 @@ pub enum RenderTaskLocation {
TextureCache(SourceTexture, i32, DeviceIntRect),
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ClipWorkItem {
pub scroll_node_data_index: ClipScrollNodeIndex,
pub clip_sources: ClipSourcesWeakHandle,
pub coordinate_system_id: CoordinateSystemId,
}
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@ -331,7 +244,7 @@ pub struct RenderTask {
pub children: Vec<RenderTaskId>,
pub kind: RenderTaskKind,
pub clear_mode: ClearMode,
pub pass_index: Option<RenderPassIndex>,
pub saved_index: Option<SavedTargetIndex>,
}
impl RenderTask {
@ -356,7 +269,7 @@ impl RenderTask {
pic_type,
}),
clear_mode,
pass_index: None,
saved_index: None,
}
}
@ -366,7 +279,7 @@ impl RenderTask {
location: RenderTaskLocation::Dynamic(None, screen_rect.size),
kind: RenderTaskKind::Readback(screen_rect),
clear_mode: ClearMode::Transparent,
pass_index: None,
saved_index: None,
}
}
@ -392,7 +305,7 @@ impl RenderTask {
source,
}),
clear_mode: ClearMode::Transparent,
pass_index: None,
saved_index: None,
}
}
@ -400,7 +313,7 @@ impl RenderTask {
outer_rect: DeviceIntRect,
clips: Vec<ClipWorkItem>,
prim_coordinate_system_id: CoordinateSystemId,
) -> RenderTask {
) -> Self {
RenderTask {
children: Vec::new(),
location: RenderTaskLocation::Dynamic(None, outer_rect.size),
@ -410,7 +323,7 @@ impl RenderTask {
coordinate_system_id: prim_coordinate_system_id,
}),
clear_mode: ClearMode::One,
pass_index: None,
saved_index: None,
}
}
@ -473,7 +386,7 @@ impl RenderTask {
scale_factor,
}),
clear_mode,
pass_index: None,
saved_index: None,
};
let blur_task_v_id = render_tasks.add(blur_task_v);
@ -488,7 +401,7 @@ impl RenderTask {
scale_factor,
}),
clear_mode,
pass_index: None,
saved_index: None,
};
(blur_task_h, scale_factor)
@ -507,7 +420,7 @@ impl RenderTask {
RenderTargetKind::Color => ClearMode::Transparent,
RenderTargetKind::Alpha => ClearMode::One,
},
pass_index: None,
saved_index: None,
}
}
@ -674,7 +587,6 @@ impl RenderTask {
RenderTaskKind::HorizontalBlur(..) |
RenderTaskKind::Scaling(..) |
RenderTaskKind::Blit(..) => false,
RenderTaskKind::CacheMask(..) => true,
}
}
@ -723,6 +635,19 @@ impl RenderTask {
pt.end_level();
true
}
/// Mark this render task for keeping the results alive up until the end of the frame.
pub fn mark_for_saving(&mut self) {
match self.location {
RenderTaskLocation::Fixed(..) |
RenderTaskLocation::Dynamic(..) => {
self.saved_index = Some(SavedTargetIndex::PENDING);
}
RenderTaskLocation::TextureCache(..) => {
panic!("Unable to mark a permanently cached task for saving!");
}
}
}
}
#[derive(Debug, Hash, PartialEq, Eq)]

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

@ -40,15 +40,15 @@ use glyph_rasterizer::GlyphFormat;
use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
use gpu_types::PrimitiveInstance;
use internal_types::{SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError};
use internal_types::{CacheTextureId, FastHashMap, RenderedDocument, ResultMsg, TextureUpdateOp};
use internal_types::{DebugOutput, RenderPassIndex, RenderTargetInfo, TextureUpdateList, TextureUpdateSource};
use internal_types::{CacheTextureId, DebugOutput, FastHashMap, RenderedDocument, ResultMsg};
use internal_types::{TextureUpdateList, TextureUpdateOp, TextureUpdateSource};
use internal_types::{RenderTargetInfo, SavedTargetIndex};
use picture::ContentOrigin;
use prim_store::DeferredResolve;
use profiler::{BackendProfileCounters, Profiler};
use profiler::{BackendProfileCounters, FrameProfileCounters, Profiler};
use profiler::{GpuProfileTag, RendererProfileCounters, RendererProfileTimers};
use query::{GpuProfiler, GpuTimer};
use rayon::Configuration as ThreadPoolConfig;
use rayon::ThreadPool;
use rayon::{ThreadPool, ThreadPoolBuilder};
use record::ApiRecordingReceiver;
use render_backend::RenderBackend;
use render_task::{RenderTaskKind, RenderTaskTree};
@ -83,6 +83,14 @@ 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_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag {
label: "B_RadialGradient",
color: debug_colors::LIGHTPINK,
};
const GPU_TAG_BRUSH_YUV_IMAGE: GpuProfileTag = GpuProfileTag {
label: "B_YuvImage",
color: debug_colors::DARKGREEN,
};
const GPU_TAG_BRUSH_MIXBLEND: GpuProfileTag = GpuProfileTag {
label: "B_MixBlend",
color: debug_colors::MAGENTA,
@ -131,10 +139,6 @@ const GPU_TAG_PRIM_IMAGE: GpuProfileTag = GpuProfileTag {
label: "Image",
color: debug_colors::GREEN,
};
const GPU_TAG_PRIM_YUV_IMAGE: GpuProfileTag = GpuProfileTag {
label: "YuvImage",
color: debug_colors::DARKGREEN,
};
const GPU_TAG_PRIM_HW_COMPOSITE: GpuProfileTag = GpuProfileTag {
label: "HwComposite",
color: debug_colors::DODGERBLUE,
@ -155,10 +159,6 @@ const GPU_TAG_PRIM_ANGLE_GRADIENT: GpuProfileTag = GpuProfileTag {
label: "AngleGradient",
color: debug_colors::POWDERBLUE,
};
const GPU_TAG_PRIM_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag {
label: "RadialGradient",
color: debug_colors::LIGHTPINK,
};
const GPU_TAG_PRIM_BORDER_CORNER: GpuProfileTag = GpuProfileTag {
label: "BorderCorner",
color: debug_colors::DARKSLATEGREY,
@ -200,10 +200,8 @@ impl TransformBatchKind {
ImageBufferKind::TextureExternal => "Image (External)",
ImageBufferKind::Texture2DArray => "Image (Array)",
},
TransformBatchKind::YuvImage(..) => "YuvImage",
TransformBatchKind::AlignedGradient => "AlignedGradient",
TransformBatchKind::AngleGradient => "AngleGradient",
TransformBatchKind::RadialGradient => "RadialGradient",
TransformBatchKind::BorderCorner => "BorderCorner",
TransformBatchKind::BorderEdge => "BorderEdge",
}
@ -213,12 +211,10 @@ impl TransformBatchKind {
match *self {
TransformBatchKind::TextRun(..) => GPU_TAG_PRIM_TEXT_RUN,
TransformBatchKind::Image(..) => GPU_TAG_PRIM_IMAGE,
TransformBatchKind::YuvImage(..) => GPU_TAG_PRIM_YUV_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,
TransformBatchKind::RadialGradient => GPU_TAG_PRIM_RADIAL_GRADIENT,
}
}
}
@ -237,6 +233,8 @@ impl BatchKind {
BrushBatchKind::Image(..) => "Brush (Image)",
BrushBatchKind::Blend => "Brush (Blend)",
BrushBatchKind::MixBlend { .. } => "Brush (Composite)",
BrushBatchKind::YuvImage(..) => "Brush (YuvImage)",
BrushBatchKind::RadialGradient => "Brush (RadialGradient)",
}
}
BatchKind::Transformable(_, batch_kind) => batch_kind.debug_name(),
@ -255,6 +253,8 @@ impl BatchKind {
BrushBatchKind::Image(..) => GPU_TAG_BRUSH_IMAGE,
BrushBatchKind::Blend => GPU_TAG_BRUSH_BLEND,
BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND,
BrushBatchKind::YuvImage(..) => GPU_TAG_BRUSH_YUV_IMAGE,
BrushBatchKind::RadialGradient => GPU_TAG_BRUSH_RADIAL_GRADIENT,
}
}
BatchKind::Transformable(_, batch_kind) => batch_kind.gpu_sampler_tag(),
@ -598,7 +598,11 @@ impl CpuProfile {
}
}
struct RenderTargetPoolId(usize);
struct ActiveTexture {
texture: Texture,
saved_index: Option<SavedTargetIndex>,
is_shared: bool,
}
struct SourceTextureResolver {
/// A vector for fast resolves of texture cache IDs to
@ -620,12 +624,17 @@ struct SourceTextureResolver {
dummy_cache_texture: Texture,
/// The current cache textures.
cache_rgba8_texture: Option<Texture>,
cache_a8_texture: Option<Texture>,
cache_rgba8_texture: Option<ActiveTexture>,
cache_a8_texture: Option<ActiveTexture>,
pass_rgba8_textures: FastHashMap<RenderPassIndex, RenderTargetPoolId>,
pass_a8_textures: FastHashMap<RenderPassIndex, RenderTargetPoolId>,
/// An alpha texture shared between all passes.
//TODO: just use the standard texture saving logic instead.
shared_alpha_texture: Option<Texture>,
/// Saved cache textures that are to be re-used.
saved_textures: Vec<Texture>,
/// General pool of render targets.
render_target_pool: Vec<Texture>,
}
@ -649,8 +658,8 @@ impl SourceTextureResolver {
dummy_cache_texture,
cache_a8_texture: None,
cache_rgba8_texture: None,
pass_rgba8_textures: FastHashMap::default(),
pass_a8_textures: FastHashMap::default(),
shared_alpha_texture: None,
saved_textures: Vec::default(),
render_target_pool: Vec::new(),
}
}
@ -670,34 +679,47 @@ impl SourceTextureResolver {
fn begin_frame(&mut self) {
assert!(self.cache_rgba8_texture.is_none());
assert!(self.cache_a8_texture.is_none());
self.pass_rgba8_textures.clear();
self.pass_a8_textures.clear();
assert!(self.saved_textures.is_empty());
}
fn end_frame(&mut self, pass_index: RenderPassIndex) {
fn end_frame(&mut self) {
// return the cached targets to the pool
self.end_pass(None, None, pass_index)
self.end_pass(None, None);
// return the global alpha texture
self.render_target_pool.extend(self.shared_alpha_texture.take());
// return the saved targets as well
self.render_target_pool.extend(self.saved_textures.drain(..));
}
fn end_pass(
&mut self,
a8_texture: Option<Texture>,
rgba8_texture: Option<Texture>,
pass_index: RenderPassIndex,
a8_texture: Option<ActiveTexture>,
rgba8_texture: Option<ActiveTexture>,
) {
// If we have cache textures from previous pass, return them to the pool.
// Also assign the pool index of those cache textures to last pass's index because this is
// the result of last pass.
if let Some(texture) = self.cache_rgba8_texture.take() {
self.pass_rgba8_textures.insert(
RenderPassIndex(pass_index.0 - 1), RenderTargetPoolId(self.render_target_pool.len()));
self.render_target_pool.push(texture);
// Note: the order here is important, needs to match the logic in `RenderPass::build()`.
if let Some(at) = self.cache_rgba8_texture.take() {
assert!(!at.is_shared);
if let Some(index) = at.saved_index {
assert_eq!(self.saved_textures.len(), index.0);
self.saved_textures.push(at.texture);
} else {
self.render_target_pool.push(at.texture);
}
}
if let Some(texture) = self.cache_a8_texture.take() {
self.pass_a8_textures.insert(
RenderPassIndex(pass_index.0 - 1), RenderTargetPoolId(self.render_target_pool.len()));
self.render_target_pool.push(texture);
if let Some(at) = self.cache_a8_texture.take() {
if let Some(index) = at.saved_index {
assert!(!at.is_shared);
assert_eq!(self.saved_textures.len(), index.0);
self.saved_textures.push(at.texture);
} else if at.is_shared {
assert!(self.shared_alpha_texture.is_none());
self.shared_alpha_texture = Some(at.texture);
} else {
self.render_target_pool.push(at.texture);
}
}
// We have another pass to process, make these textures available
@ -711,15 +733,17 @@ impl SourceTextureResolver {
match *texture_id {
SourceTexture::Invalid => {}
SourceTexture::CacheA8 => {
let texture = self.cache_a8_texture
.as_ref()
.unwrap_or(&self.dummy_cache_texture);
let texture = match self.cache_a8_texture {
Some(ref at) => &at.texture,
None => &self.dummy_cache_texture,
};
device.bind_texture(sampler, texture);
}
SourceTexture::CacheRGBA8 => {
let texture = self.cache_rgba8_texture
.as_ref()
.unwrap_or(&self.dummy_cache_texture);
let texture = match self.cache_rgba8_texture {
Some(ref at) => &at.texture,
None => &self.dummy_cache_texture,
};
device.bind_texture(sampler, texture);
}
SourceTexture::External(external_image) => {
@ -732,17 +756,9 @@ impl SourceTextureResolver {
let texture = &self.cache_texture_map[index.0];
device.bind_texture(sampler, texture);
}
SourceTexture::RenderTaskCacheRGBA8(pass_index) => {
let pool_index = self.pass_rgba8_textures
.get(&pass_index)
.expect("BUG: pass_index doesn't map to pool_index");
device.bind_texture(sampler, &self.render_target_pool[pool_index.0])
}
SourceTexture::RenderTaskCacheA8(pass_index) => {
let pool_index = self.pass_a8_textures
.get(&pass_index)
.expect("BUG: pass_index doesn't map to pool_index");
device.bind_texture(sampler, &self.render_target_pool[pool_index.0])
SourceTexture::RenderTaskCache(saved_index) => {
let texture = &self.saved_textures[saved_index.0];
device.bind_texture(sampler, texture)
}
}
}
@ -754,31 +770,26 @@ impl SourceTextureResolver {
match *texture_id {
SourceTexture::Invalid => None,
SourceTexture::CacheA8 => Some(
self.cache_a8_texture
.as_ref()
.unwrap_or(&self.dummy_cache_texture),
match self.cache_a8_texture {
Some(ref at) => &at.texture,
None => &self.dummy_cache_texture,
}
),
SourceTexture::CacheRGBA8 => Some(
self.cache_rgba8_texture
.as_ref()
.unwrap_or(&self.dummy_cache_texture),
match self.cache_rgba8_texture {
Some(ref at) => &at.texture,
None => &self.dummy_cache_texture,
}
),
SourceTexture::External(..) => {
panic!("BUG: External textures cannot be resolved, they can only be bound.");
}
SourceTexture::TextureCache(index) => Some(&self.cache_texture_map[index.0]),
SourceTexture::RenderTaskCacheRGBA8(pass_index) => {
let pool_index = self.pass_rgba8_textures
.get(&pass_index)
.expect("BUG: pass_index doesn't map to pool_index");
Some(&self.render_target_pool[pool_index.0])
},
SourceTexture::RenderTaskCacheA8(pass_index) => {
let pool_index = self.pass_a8_textures
.get(&pass_index)
.expect("BUG: pass_index doesn't map to pool_index");
Some(&self.render_target_pool[pool_index.0])
},
SourceTexture::TextureCache(index) => {
Some(&self.cache_texture_map[index.0])
}
SourceTexture::RenderTaskCache(saved_index) => {
Some(&self.saved_textures[saved_index.0])
}
}
}
}
@ -1605,6 +1616,8 @@ pub struct Renderer {
brush_image: Vec<Option<BrushShader>>,
brush_blend: BrushShader,
brush_mix_blend: BrushShader,
brush_yuv_image: Vec<Option<BrushShader>>,
brush_radial_gradient: BrushShader,
/// These are "cache clip shaders". These shaders are used to
/// draw clip instances into the cached clip mask. The results
@ -1623,12 +1636,10 @@ pub struct Renderer {
ps_text_run: TextShader,
ps_text_run_dual_source: TextShader,
ps_image: Vec<Option<PrimitiveShader>>,
ps_yuv_image: Vec<Option<PrimitiveShader>>,
ps_border_corner: PrimitiveShader,
ps_border_edge: PrimitiveShader,
ps_gradient: PrimitiveShader,
ps_angle_gradient: PrimitiveShader,
ps_radial_gradient: PrimitiveShader,
ps_hw_composite: LazilyCompiledShader,
ps_split_composite: LazilyCompiledShader,
@ -1745,6 +1756,7 @@ impl Renderer {
let (payload_tx, payload_rx) = try!{ channel::payload_channel() };
let (result_tx, result_rx) = channel();
let gl_type = gl.get_type();
let dithering_feature = ["DITHERING"];
let debug_server = DebugServer::new(api_tx.clone());
@ -1861,6 +1873,17 @@ impl Renderer {
options.precache_shaders)
};
let brush_radial_gradient = try!{
BrushShader::new("brush_radial_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",
@ -1952,10 +1975,10 @@ impl Renderer {
// All yuv_image configuration.
let mut yuv_features = Vec::new();
let yuv_shader_num = IMAGE_BUFFER_KINDS.len() * YUV_FORMATS.len() * YUV_COLOR_SPACES.len();
let mut ps_yuv_image: Vec<Option<PrimitiveShader>> = Vec::new();
let mut brush_yuv_image = Vec::new();
// PrimitiveShader is not clonable. Use push() to initialize the vec.
for _ in 0 .. yuv_shader_num {
ps_yuv_image.push(None);
brush_yuv_image.push(None);
}
for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() {
if IMAGE_BUFFER_KINDS[buffer_kind].has_platform_support(&gl_type) {
@ -1976,17 +1999,17 @@ impl Renderer {
}
let shader = try!{
PrimitiveShader::new("ps_yuv_image",
&mut device,
&yuv_features,
options.precache_shaders)
BrushShader::new("brush_yuv_image",
&mut device,
&yuv_features,
options.precache_shaders)
};
let index = Renderer::get_yuv_shader_index(
IMAGE_BUFFER_KINDS[buffer_kind],
YUV_FORMATS[format_kind],
YUV_COLOR_SPACES[color_space_kind],
);
ps_yuv_image[index] = Some(shader);
brush_yuv_image[index] = Some(shader);
yuv_features.clear();
}
}
@ -2007,8 +2030,6 @@ impl Renderer {
options.precache_shaders)
};
let dithering_feature = ["DITHERING"];
let ps_gradient = try!{
PrimitiveShader::new("ps_gradient",
&mut device,
@ -2031,17 +2052,6 @@ impl Renderer {
options.precache_shaders)
};
let ps_radial_gradient = try!{
PrimitiveShader::new("ps_radial_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",
@ -2215,7 +2225,7 @@ impl Renderer {
.workers
.take()
.unwrap_or_else(|| {
let worker_config = ThreadPoolConfig::new()
let worker = ThreadPoolBuilder::new()
.thread_name(|idx|{ format!("WRWorker#{}", idx) })
.start_handler(move |idx| {
register_thread_with_profiler(format!("WRWorker#{}", idx));
@ -2227,8 +2237,9 @@ impl Renderer {
if let Some(ref thread_listener) = *thread_listener_for_rayon_end {
thread_listener.thread_stopped(&format!("WRWorker#{}", idx));
}
});
Arc::new(ThreadPool::new(worker_config).unwrap())
})
.build();
Arc::new(worker.unwrap())
});
let enable_render_on_scroll = options.enable_render_on_scroll;
@ -2290,18 +2301,18 @@ impl Renderer {
brush_image,
brush_blend,
brush_mix_blend,
brush_yuv_image,
brush_radial_gradient,
cs_clip_rectangle,
cs_clip_border,
cs_clip_image,
ps_text_run,
ps_text_run_dual_source,
ps_image,
ps_yuv_image,
ps_border_corner,
ps_border_edge,
ps_gradient,
ps_angle_gradient,
ps_radial_gradient,
ps_hw_composite,
ps_split_composite,
debug: debug_renderer,
@ -2873,18 +2884,13 @@ impl Renderer {
}
}
// Re-use whatever targets possible from the pool, before
// they get changed/re-allocated by the rendered frames.
for doc_with_id in &mut active_documents {
self.prepare_tile_frame(&mut doc_with_id.1.frame);
}
#[cfg(feature = "replay")]
self.texture_resolver.external_images.extend(
self.owned_external_images.iter().map(|(key, value)| (*key, value.clone()))
);
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);
@ -3257,6 +3263,29 @@ impl Renderer {
&mut self.renderer_errors,
);
}
BrushBatchKind::RadialGradient => {
self.brush_radial_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);
self.brush_yuv_image[shader_index]
.as_mut()
.expect("Unsupported YUV shader kind")
.bind(
&mut self.device,
key.blend_mode,
projection,
0,
&mut self.renderer_errors,
);
}
}
}
BatchKind::Transformable(transform_kind, batch_kind) => match batch_kind {
@ -3275,20 +3304,6 @@ impl Renderer {
&mut self.renderer_errors,
);
}
TransformBatchKind::YuvImage(image_buffer_kind, format, color_space) => {
let shader_index =
Renderer::get_yuv_shader_index(image_buffer_kind, format, color_space);
self.ps_yuv_image[shader_index]
.as_mut()
.expect("Unsupported YUV shader kind")
.bind(
&mut self.device,
transform_kind,
projection,
0,
&mut self.renderer_errors,
);
}
TransformBatchKind::BorderCorner => {
self.ps_border_corner.bind(
&mut self.device,
@ -3325,15 +3340,6 @@ impl Renderer {
&mut self.renderer_errors,
);
}
TransformBatchKind::RadialGradient => {
self.ps_radial_gradient.bind(
&mut self.device,
transform_kind,
projection,
0,
&mut self.renderer_errors,
);
}
},
};
@ -4250,47 +4256,52 @@ impl Renderer {
}
}
fn prepare_target_list<T: RenderTarget>(
fn allocate_target_texture<T: RenderTarget>(
&mut self,
list: &mut RenderTargetList<T>,
perfect_only: bool,
) {
counters: &mut FrameProfileCounters,
frame_id: FrameId,
) -> Option<ActiveTexture> {
debug_assert_ne!(list.max_size, DeviceUintSize::zero());
if list.targets.is_empty() {
return;
return None
}
let mut texture = if perfect_only {
debug_assert!(list.texture.is_none());
let selector = TargetSelector {
size: list.max_size,
num_layers: list.targets.len() as _,
format: list.format,
};
let index = self.texture_resolver.render_target_pool
counters.targets_used.inc();
// First, try finding a perfect match
let selector = TargetSelector {
size: list.max_size,
num_layers: list.targets.len() as _,
format: list.format,
};
let mut index = self.texture_resolver.render_target_pool
.iter()
.position(|texture| {
//TODO: re-use a part of a larger target, if available
selector == TargetSelector {
size: texture.get_dimensions(),
num_layers: texture.get_render_target_layer_count(),
format: texture.get_format(),
}
});
// Next, try at least finding a matching format
if index.is_none() {
counters.targets_changed.inc();
index = self.texture_resolver.render_target_pool
.iter()
.position(|texture| {
selector == TargetSelector {
size: texture.get_dimensions(),
num_layers: texture.get_render_target_layer_count(),
format: texture.get_format(),
}
});
match index {
Some(pos) => self.texture_resolver.render_target_pool.swap_remove(pos),
None => return,
.position(|texture| texture.get_format() == list.format && !texture.used_in_frame(frame_id));
}
let mut texture = match index {
Some(pos) => {
self.texture_resolver.render_target_pool.swap_remove(pos)
}
} else {
if list.texture.is_some() {
list.check_ready();
return
}
let index = self.texture_resolver.render_target_pool
.iter()
.position(|texture| texture.get_format() == list.format);
match index {
Some(pos) => self.texture_resolver.render_target_pool.swap_remove(pos),
None => self.device.create_texture(TextureTarget::Array, list.format),
None => {
counters.targets_created.inc();
// finally, give up and create a new one
self.device.create_texture(TextureTarget::Array, list.format)
}
};
@ -4305,34 +4316,19 @@ impl Renderer {
list.targets.len() as _,
None,
);
list.texture = Some(texture);
list.check_ready();
}
fn prepare_tile_frame(&mut self, frame: &mut Frame) {
// Init textures and render targets to match this scene.
// First pass grabs all the perfectly matching targets from the pool.
for pass in &mut frame.passes {
if let RenderPassKind::OffScreen { ref mut alpha, ref mut color, .. } = pass.kind {
self.prepare_target_list(alpha, true);
self.prepare_target_list(color, true);
}
}
list.check_ready(&texture);
Some(ActiveTexture {
texture,
saved_index: list.saved_index.clone(),
is_shared: list.is_shared,
})
}
fn bind_frame_data(&mut self, frame: &mut Frame) {
let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_DATA);
self.device.set_device_pixel_ratio(frame.device_pixel_ratio);
// Some of the textures are already assigned by `prepare_frame`.
// Now re-allocate the space for the rest of the target textures.
for pass in &mut frame.passes {
if let RenderPassKind::OffScreen { ref mut alpha, ref mut color, .. } = pass.kind {
self.prepare_target_list(alpha, false);
self.prepare_target_list(color, false);
}
}
self.node_data_texture.update(&mut self.device, &mut frame.node_data);
self.device.bind_texture(TextureSampler::ClipScrollNodes, &self.node_data_texture.texture);
@ -4424,8 +4420,8 @@ impl Renderer {
(None, None)
}
RenderPassKind::OffScreen { ref mut alpha, ref mut color, ref mut texture_cache } => {
alpha.check_ready();
color.check_ready();
let alpha_tex = self.allocate_target_texture(alpha, &mut frame.profile_counters, frame_id);
let color_tex = self.allocate_target_texture(color, &mut frame.profile_counters, frame_id);
// If this frame has already been drawn, then any texture
// cache targets have already been updated and can be
@ -4455,7 +4451,7 @@ impl Renderer {
);
self.draw_alpha_target(
(alpha.texture.as_ref().unwrap(), target_index as i32),
(&alpha_tex.as_ref().unwrap().texture, target_index as i32),
target,
alpha.max_size,
&projection,
@ -4477,7 +4473,7 @@ impl Renderer {
);
self.draw_color_target(
Some((color.texture.as_ref().unwrap(), target_index as i32)),
Some((&color_tex.as_ref().unwrap().texture, target_index as i32)),
target,
frame.inner_rect,
color.max_size,
@ -4490,29 +4486,23 @@ impl Renderer {
);
}
(alpha.texture.take(), color.texture.take())
(alpha_tex, color_tex)
}
};
//Note: the `end_pass` will make sure this texture is not recycled this frame
if let Some(ActiveTexture { ref texture, is_shared: true, .. }) = cur_alpha {
self.device
.bind_texture(TextureSampler::SharedCacheA8, texture);
}
self.texture_resolver.end_pass(
cur_alpha,
cur_color,
RenderPassIndex(pass_index),
);
// After completing the first pass, make the A8 target available as an
// input to any subsequent passes.
if pass_index == 0 {
if let Some(shared_alpha_texture) =
self.texture_resolver.resolve(&SourceTexture::CacheA8)
{
self.device
.bind_texture(TextureSampler::SharedCacheA8, shared_alpha_texture);
}
}
}
self.texture_resolver.end_frame(RenderPassIndex(frame.passes.len()));
self.texture_resolver.end_frame();
if let Some(framebuffer_size) = framebuffer_size {
self.draw_render_target_debug(framebuffer_size);
self.draw_texture_cache_debug(framebuffer_size);
@ -4750,6 +4740,7 @@ impl Renderer {
self.brush_line.deinit(&mut self.device);
self.brush_blend.deinit(&mut self.device);
self.brush_mix_blend.deinit(&mut self.device);
self.brush_radial_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);
@ -4765,7 +4756,7 @@ impl Renderer {
shader.deinit(&mut self.device);
}
}
for shader in self.ps_yuv_image {
for shader in self.brush_yuv_image {
if let Some(shader) = shader {
shader.deinit(&mut self.device);
}
@ -4777,7 +4768,6 @@ impl Renderer {
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_radial_gradient.deinit(&mut self.device);
self.ps_hw_composite.deinit(&mut self.device);
self.ps_split_composite.deinit(&mut self.device);
#[cfg(feature = "capture")]

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

@ -197,10 +197,11 @@ impl FilterOpHelpers for FilterOp {
offset.x == 0.0 && offset.y == 0.0 && blur == 0.0
},
FilterOp::ColorMatrix(matrix) => {
matrix == [1.0, 0.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0, 0.0]
matrix == [1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
0.0, 0.0, 0.0, 0.0]
}
}
}

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

@ -11,10 +11,10 @@ use clip::{ClipStore};
use clip_scroll_tree::{ClipScrollTree};
use device::{FrameId, Texture};
use gpu_cache::{GpuCache};
use gpu_types::{BlurDirection, BlurInstance, BrushInstance, ClipChainRectIndex};
use gpu_types::{BlurDirection, BlurInstance, BrushFlags, BrushInstance, ClipChainRectIndex};
use gpu_types::{ClipScrollNodeData, ClipScrollNodeIndex};
use gpu_types::{PrimitiveInstance};
use internal_types::{FastHashMap, RenderPassIndex, SourceTexture};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{PictureKind};
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveStore};
use prim_store::{BrushMaskKind, BrushKind, DeferredResolve, EdgeAaSegmentMask};
@ -137,8 +137,8 @@ pub struct RenderTargetList<T> {
pub format: ImageFormat,
pub max_size: DeviceUintSize,
pub targets: Vec<T>,
#[cfg_attr(feature = "serde", serde(skip))]
pub texture: Option<Texture>,
pub saved_index: Option<SavedTargetIndex>,
pub is_shared: bool,
}
impl<T: RenderTarget> RenderTargetList<T> {
@ -151,7 +151,8 @@ impl<T: RenderTarget> RenderTargetList<T> {
format,
max_size: DeviceUintSize::new(MIN_TARGET_SIZE, MIN_TARGET_SIZE),
targets: Vec::new(),
texture: None,
saved_index: None,
is_shared: false,
}
}
@ -161,7 +162,11 @@ impl<T: RenderTarget> RenderTargetList<T> {
gpu_cache: &mut GpuCache,
render_tasks: &mut RenderTaskTree,
deferred_resolves: &mut Vec<DeferredResolve>,
saved_index: Option<SavedTargetIndex>,
) {
debug_assert_eq!(None, self.saved_index);
self.saved_index = saved_index;
for target in &mut self.targets {
target.build(ctx, gpu_cache, render_tasks, deferred_resolves);
}
@ -214,20 +219,13 @@ impl<T: RenderTarget> RenderTargetList<T> {
self.targets.iter().any(|target| target.needs_depth())
}
pub fn check_ready(&self) {
match self.texture {
Some(ref t) => {
assert_eq!(t.get_dimensions(), self.max_size);
assert_eq!(t.get_format(), self.format);
assert_eq!(t.get_render_target_layer_count(), self.targets.len());
assert_eq!(t.get_layer_count() as usize, self.targets.len());
assert_eq!(t.has_depth(), t.get_rt_info().unwrap().has_depth);
assert_eq!(t.has_depth(), self.needs_depth());
}
None => {
assert!(self.targets.is_empty())
}
}
pub fn check_ready(&self, t: &Texture) {
assert_eq!(t.get_dimensions(), self.max_size);
assert_eq!(t.get_format(), self.format);
assert_eq!(t.get_render_target_layer_count(), self.targets.len());
assert_eq!(t.get_layer_count() as usize, self.targets.len());
assert_eq!(t.has_depth(), t.get_rt_info().unwrap().has_depth);
assert_eq!(t.has_depth(), self.needs_depth());
}
}
@ -589,6 +587,7 @@ impl RenderTarget for AlphaRenderTarget {
clip_task_address: RenderTaskAddress(0),
z: 0,
segment_index: 0,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
edge_flags: EdgeAaSegmentMask::empty(),
user_data: [0; 3],
};
@ -598,6 +597,8 @@ impl RenderTarget for AlphaRenderTarget {
BrushKind::Clear |
BrushKind::Picture |
BrushKind::Line { .. } |
BrushKind::YuvImage { .. } |
BrushKind::RadialGradient { .. } |
BrushKind::Image { .. } => {
unreachable!("bug: unexpected brush here");
}
@ -784,7 +785,6 @@ impl RenderPass {
render_tasks: &mut RenderTaskTree,
deferred_resolves: &mut Vec<DeferredResolve>,
clip_store: &ClipStore,
pass_index: RenderPassIndex,
) {
profile_scope!("RenderPass::build");
@ -792,7 +792,6 @@ impl RenderPass {
RenderPassKind::MainFramebuffer(ref mut target) => {
for &task_id in &self.tasks {
assert_eq!(render_tasks[task_id].target_kind(), RenderTargetKind::Color);
render_tasks[task_id].pass_index = Some(pass_index);
target.add_task(
task_id,
ctx,
@ -805,16 +804,38 @@ impl RenderPass {
target.build(ctx, gpu_cache, render_tasks, deferred_resolves);
}
RenderPassKind::OffScreen { ref mut color, ref mut alpha, ref mut texture_cache } => {
let is_shared_alpha = self.tasks.iter().any(|&task_id| {
match render_tasks[task_id].kind {
RenderTaskKind::CacheMask(..) => true,
_ => false,
}
});
let saved_color = if self.tasks.iter().any(|&task_id| {
let t = &render_tasks[task_id];
t.target_kind() == RenderTargetKind::Color && t.saved_index.is_some()
}) {
Some(render_tasks.save_target())
} else {
None
};
let saved_alpha = if self.tasks.iter().any(|&task_id| {
let t = &render_tasks[task_id];
t.target_kind() == RenderTargetKind::Alpha && t.saved_index.is_some()
}) {
Some(render_tasks.save_target())
} else {
None
};
// Step through each task, adding to batches as appropriate.
for &task_id in &self.tasks {
let (target_kind, texture_target) = {
let task = &mut render_tasks[task_id];
task.pass_index = Some(pass_index);
let target_kind = task.target_kind();
// Find a target to assign this task to, or create a new
// one if required.
match task.location {
let (target_kind, texture_target) = match task.location {
RenderTaskLocation::TextureCache(texture_id, layer, _) => {
// TODO(gw): When we support caching color items, we will
// need to calculate that here to get the
@ -834,7 +855,18 @@ impl RenderPass {
(target_kind, None)
}
};
// Replace the pending saved index with a real one
if let Some(index) = task.saved_index {
assert_eq!(index, SavedTargetIndex::PENDING);
task.saved_index = match target_kind {
RenderTargetKind::Color => saved_color,
RenderTargetKind::Alpha => saved_alpha,
};
}
(target_kind, texture_target)
};
match texture_target {
@ -869,8 +901,9 @@ impl RenderPass {
}
}
color.build(ctx, gpu_cache, render_tasks, deferred_resolves);
alpha.build(ctx, gpu_cache, render_tasks, deferred_resolves);
color.build(ctx, gpu_cache, render_tasks, deferred_resolves, saved_color);
alpha.build(ctx, gpu_cache, render_tasks, deferred_resolves, saved_alpha);
alpha.is_shared = is_shared_alpha;
}
}
}

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

@ -62,10 +62,6 @@ const SHADERS: &[Shader] = &[
name: "ps_angle_gradient",
features: PRIM_FEATURES,
},
Shader {
name: "ps_radial_gradient",
features: PRIM_FEATURES,
},
Shader {
name: "ps_hardware_composite",
features: PRIM_FEATURES,
@ -78,15 +74,15 @@ const SHADERS: &[Shader] = &[
name: "ps_image",
features: PRIM_FEATURES,
},
Shader {
name: "ps_yuv_image",
features: PRIM_FEATURES,
},
Shader {
name: "ps_text_run",
features: PRIM_FEATURES,
},
// Brush shaders
Shader {
name: "brush_yuv_image",
features: &["", "YUV_NV12", "YUV_PLANAR", "YUV_INTERLEAVED"],
},
Shader {
name: "brush_mask",
features: &[],
@ -111,6 +107,10 @@ const SHADERS: &[Shader] = &[
name: "brush_line",
features: &[],
},
Shader {
name: "brush_radial_gradient",
features: &[],
},
];
const VERSION_STRING: &str = "#version 300 es\n";

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

@ -9,7 +9,7 @@ use std::fmt;
use std::marker::PhantomData;
use std::path::PathBuf;
use std::u32;
use {BuiltDisplayList, BuiltDisplayListDescriptor, ClipId, ColorF, DeviceIntPoint, DeviceUintRect};
use {BuiltDisplayList, BuiltDisplayListDescriptor, ColorF, DeviceIntPoint, DeviceUintRect};
use {DeviceUintSize, ExternalScrollId, FontInstanceKey, FontInstanceOptions};
use {FontInstancePlatformOptions, FontKey, FontVariation, GlyphDimensions, GlyphKey, ImageData};
use {ImageDescriptor, ImageKey, ItemTag, LayoutPoint, LayoutSize, LayoutTransform, LayoutVector2D};
@ -254,7 +254,7 @@ impl Transaction {
pub fn scroll_node_with_id(
&mut self,
origin: LayoutPoint,
id: ScrollNodeIdType,
id: ExternalScrollId,
clamp: ScrollClamping,
) {
self.ops.push(DocumentMsg::ScrollNodeWithId(origin, id, clamp));
@ -384,37 +384,13 @@ pub enum DocumentMsg {
device_pixel_ratio: f32,
},
Scroll(ScrollLocation, WorldPoint, ScrollEventPhase),
ScrollNodeWithId(LayoutPoint, ScrollNodeIdType, ScrollClamping),
ScrollNodeWithId(LayoutPoint, ExternalScrollId, ScrollClamping),
TickScrollingBounce,
GetScrollNodeState(MsgSender<Vec<ScrollNodeState>>),
GenerateFrame,
UpdateDynamicProperties(DynamicProperties),
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ScrollNodeIdType {
ExternalScrollId(ExternalScrollId),
ClipId(ClipId),
}
impl From<ExternalScrollId> for ScrollNodeIdType {
fn from(id: ExternalScrollId) -> Self {
ScrollNodeIdType::ExternalScrollId(id)
}
}
impl From<ClipId> for ScrollNodeIdType {
fn from(id: ClipId) -> Self {
ScrollNodeIdType::ClipId(id)
}
}
impl<'a> From<&'a ClipId> for ScrollNodeIdType {
fn from(id: &'a ClipId) -> Self {
ScrollNodeIdType::ClipId(*id)
}
}
impl fmt::Debug for DocumentMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {

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

@ -601,9 +601,9 @@ impl YuvFormat {
pub fn get_feature_string(&self) -> &'static str {
match *self {
YuvFormat::NV12 => "NV12",
YuvFormat::PlanarYCbCr => "",
YuvFormat::InterleavedYCbCr => "INTERLEAVED_Y_CB_CR",
YuvFormat::NV12 => "YUV_NV12",
YuvFormat::PlanarYCbCr => "YUV_PLANAR",
YuvFormat::InterleavedYCbCr => "YUV_INTERLEAVED",
}
}
}
@ -649,6 +649,22 @@ impl LocalClip {
),
}
}
pub fn clip_by(&self, rect: &LayoutRect) -> LocalClip {
match *self {
LocalClip::Rect(clip_rect) => {
LocalClip::Rect(
clip_rect.intersection(rect).unwrap_or(LayoutRect::zero())
)
}
LocalClip::RoundedRect(clip_rect, complex) => {
LocalClip::RoundedRect(
clip_rect.intersection(rect).unwrap_or(LayoutRect::zero()),
complex,
)
}
}
}
}
#[repr(C)]

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

@ -5,7 +5,7 @@ authors = ["The Mozilla Project Developers"]
license = "MPL-2.0"
[dependencies]
rayon = "0.8"
rayon = "1"
thread_profiler = "0.1.1"
euclid = "0.16"
app_units = "0.6"

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

@ -1 +1 @@
4af31b8aa79d5a1f3c0242dea6be4876c71075c5
e8d2ffb404a85651fe08a6d09abbece9bd2b9182

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

@ -502,7 +502,7 @@ impl Wrench {
&mut self,
frame_number: u32,
display_lists: Vec<(PipelineId, LayerSize, BuiltDisplayList)>,
scroll_offsets: &HashMap<ClipId, LayerPoint>,
scroll_offsets: &HashMap<ExternalScrollId, LayerPoint>,
) {
let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));
@ -523,7 +523,7 @@ impl Wrench {
let mut txn = Transaction::new();
for (id, offset) in scroll_offsets {
txn.scroll_node_with_id(*offset, id.into(), ScrollClamping::NoClamping);
txn.scroll_node_with_id(*offset, *id, ScrollClamping::NoClamping);
}
// TODO(nical) - Wrench does not notify frames when there was scrolling
// in the transaction (See RenderNotifier implementations). If we don't

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

@ -193,7 +193,7 @@ pub struct YamlFrameReader {
/// A HashMap of offsets which specify what scroll offsets particular
/// scroll layers should be initialized with.
scroll_offsets: HashMap<ClipId, LayerPoint>,
scroll_offsets: HashMap<ExternalScrollId, LayerPoint>,
image_map: HashMap<(PathBuf, Option<i64>), (ImageKey, LayoutSize)>,
@ -1273,7 +1273,12 @@ impl YamlFrameReader {
wrench: &mut Wrench,
yaml: &Yaml,
) {
let full_clip = LayoutRect::new(LayoutPoint::zero(), wrench.window_size_f32());
// A very large number (but safely far away from finite limits of f32)
let big_number = 1.0e30;
// A rect that should in practical terms serve as a no-op for clipping
let full_clip = LayoutRect::new(
LayoutPoint::new(-big_number / 2.0, -big_number / 2.0),
LayoutSize::new(big_number, big_number));
for item in yaml.as_vec().unwrap() {
// an explicit type can be skipped with some shorthand
@ -1362,7 +1367,12 @@ impl YamlFrameReader {
let complex_clips = self.to_complex_clip_regions(&yaml["complex"]);
let image_mask = self.to_image_mask(&yaml["image-mask"], wrench);
let external_id = numeric_id.map(|id| ExternalScrollId(id as u64, dl.pipeline_id));
let external_id = yaml["scroll-offset"].as_point().map(|size| {
let id = ExternalScrollId((self.scroll_offsets.len() + 1) as u64, dl.pipeline_id);
self.scroll_offsets.insert(id, LayerPoint::new(size.x, size.y));
id
});
let real_id = dl.define_scroll_frame(
external_id,
content_rect,
@ -1375,10 +1385,6 @@ impl YamlFrameReader {
self.clip_id_map.insert(numeric_id, real_id);
}
if let Some(size) = yaml["scroll-offset"].as_point() {
self.scroll_offsets.insert(real_id, LayerPoint::new(size.x, size.y));
}
if !yaml["items"].is_badvalue() {
dl.push_clip_id(real_id);
self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]);
@ -1542,9 +1548,8 @@ impl YamlFrameReader {
if is_root {
if let Some(size) = yaml["scroll-offset"].as_point() {
let id = ClipId::root_scroll_node(dl.pipeline_id);
self.scroll_offsets
.insert(id, LayerPoint::new(size.x, size.y));
let external_id = ExternalScrollId(0, dl.pipeline_id);
self.scroll_offsets.insert(external_id, LayerPoint::new(size.x, size.y));
}
}