зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset dd8eb671df75 (bug 1408461) for failing reftests border-dotted/border-dotted-interaction.html and border-radius/curved-stripe-border.html on Linux QuantumRender. r=backout
--HG-- extra : rebase_source : 6ecd1fd58e3a2b1c711e386a77d4da26dab308c1
This commit is contained in:
Родитель
3bc133f2e6
Коммит
bffd61287d
|
@ -175,4 +175,4 @@ Troubleshooting tips:
|
|||
-------------------------------------------------------------------------------
|
||||
|
||||
The version of WebRender currently in the tree is:
|
||||
7892f5364bc4d35c7a9b42949f0ace4cc54f8b3c
|
||||
a624aa6d3b6006c510c8b14026567af4ac545d2f
|
||||
|
|
|
@ -11,7 +11,6 @@ default = ["freetype-lib"]
|
|||
freetype-lib = ["freetype/servo-freetype-sys"]
|
||||
profiler = ["thread_profiler/thread_profiler"]
|
||||
debugger = ["ws", "serde_json", "serde", "serde_derive"]
|
||||
query = []
|
||||
|
||||
[dependencies]
|
||||
app_units = "0.5.6"
|
||||
|
@ -26,7 +25,7 @@ num-traits = "0.1.32"
|
|||
time = "0.1"
|
||||
rayon = "0.8"
|
||||
webrender_api = {path = "../webrender_api"}
|
||||
bitflags = "1.0"
|
||||
bitflags = "0.9"
|
||||
thread_profiler = "0.1.1"
|
||||
plane-split = "0.6"
|
||||
ws = { optional = true, version = "0.7.3" }
|
||||
|
|
|
@ -187,7 +187,7 @@ pub fn main_wrapper(example: &mut Example, options: Option<webrender::RendererOp
|
|||
Some(glutin::VirtualKeyCode::P),
|
||||
) => {
|
||||
let mut flags = renderer.get_debug_flags();
|
||||
flags.toggle(webrender::DebugFlags::PROFILER_DBG);
|
||||
flags.toggle(webrender::PROFILER_DBG);
|
||||
renderer.set_debug_flags(flags);
|
||||
}
|
||||
glutin::Event::KeyboardInput(
|
||||
|
@ -196,7 +196,7 @@ pub fn main_wrapper(example: &mut Example, options: Option<webrender::RendererOp
|
|||
Some(glutin::VirtualKeyCode::O),
|
||||
) => {
|
||||
let mut flags = renderer.get_debug_flags();
|
||||
flags.toggle(webrender::DebugFlags::RENDER_TARGET_DBG);
|
||||
flags.toggle(webrender::RENDER_TARGET_DBG);
|
||||
renderer.set_debug_flags(flags);
|
||||
}
|
||||
glutin::Event::KeyboardInput(
|
||||
|
@ -205,7 +205,7 @@ pub fn main_wrapper(example: &mut Example, options: Option<webrender::RendererOp
|
|||
Some(glutin::VirtualKeyCode::I),
|
||||
) => {
|
||||
let mut flags = renderer.get_debug_flags();
|
||||
flags.toggle(webrender::DebugFlags::TEXTURE_CACHE_DBG);
|
||||
flags.toggle(webrender::TEXTURE_CACHE_DBG);
|
||||
renderer.set_debug_flags(flags);
|
||||
}
|
||||
glutin::Event::KeyboardInput(
|
||||
|
@ -214,7 +214,7 @@ pub fn main_wrapper(example: &mut Example, options: Option<webrender::RendererOp
|
|||
Some(glutin::VirtualKeyCode::B),
|
||||
) => {
|
||||
let mut flags = renderer.get_debug_flags();
|
||||
flags.toggle(webrender::DebugFlags::ALPHA_PRIM_DBG);
|
||||
flags.toggle(webrender::ALPHA_PRIM_DBG);
|
||||
renderer.set_debug_flags(flags);
|
||||
}
|
||||
glutin::Event::KeyboardInput(
|
||||
|
|
|
@ -1,81 +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/. */
|
||||
|
||||
varying vec2 vLocalPos;
|
||||
flat varying vec4 vLocalRect;
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
|
||||
struct BrushInstance {
|
||||
int picture_address;
|
||||
int prim_address;
|
||||
};
|
||||
|
||||
BrushInstance load_brush() {
|
||||
BrushInstance bi;
|
||||
|
||||
bi.picture_address = aData0.x;
|
||||
bi.prim_address = aData0.y;
|
||||
|
||||
return bi;
|
||||
}
|
||||
|
||||
/*
|
||||
The dynamic picture that this brush exists on. Right now, it
|
||||
contains minimal information. In the future, it will describe
|
||||
the transform mode of primitives on this picture, among other things.
|
||||
*/
|
||||
struct PictureTask {
|
||||
RectWithSize target_rect;
|
||||
};
|
||||
|
||||
PictureTask fetch_picture_task(int index) {
|
||||
ivec2 uv = get_fetch_uv(index, VECS_PER_RENDER_TASK);
|
||||
|
||||
vec4 target_rect = TEXEL_FETCH(sRenderTasks, uv, 0, ivec2(0, 0));
|
||||
|
||||
PictureTask task = PictureTask(RectWithSize(target_rect.xy, target_rect.zw));
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
// Load the brush instance from vertex attributes.
|
||||
BrushInstance brush = load_brush();
|
||||
|
||||
// Fetch the dynamic picture that we are drawing on.
|
||||
PictureTask pic_task = fetch_picture_task(brush.picture_address);
|
||||
|
||||
// Load the geometry for this brush. For now, this is simply the
|
||||
// local rect of the primitive. In the future, this will support
|
||||
// loading segment rects, and other rect formats (glyphs).
|
||||
PrimitiveGeometry geom = fetch_primitive_geometry(brush.prim_address);
|
||||
|
||||
// Write the (p0,p1) form of the primitive rect and the local position
|
||||
// of this vertex. Specific brush shaders can use this information to
|
||||
// interpolate texture coordinates etc.
|
||||
vLocalRect = vec4(geom.local_rect.p0, geom.local_rect.p0 + geom.local_rect.size);
|
||||
|
||||
// Right now - pictures only support local positions. In the future, this
|
||||
// will be expanded to support transform picture types (the common kind).
|
||||
vec2 pos = pic_task.target_rect.p0 + aPosition.xy * pic_task.target_rect.size;
|
||||
vLocalPos = aPosition.xy * pic_task.target_rect.size / uDevicePixelRatio;
|
||||
|
||||
// Run the specific brush VS code to write interpolators.
|
||||
brush_vs(brush.prim_address, vLocalRect);
|
||||
|
||||
// Write the final position transformed by the orthographic device-pixel projection.
|
||||
gl_Position = uTransform * vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
void main(void) {
|
||||
// Run the specific brush FS code to output the color.
|
||||
vec4 color = brush_fs(vLocalPos, vLocalRect);
|
||||
|
||||
// TODO(gw): Handle pre-multiply common code here as required.
|
||||
oFragColor = color;
|
||||
}
|
||||
#endif
|
|
@ -1,61 +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,ellipse
|
||||
|
||||
flat varying float vClipMode;
|
||||
flat varying vec4 vClipCenter_Radius_TL;
|
||||
flat varying vec4 vClipCenter_Radius_TR;
|
||||
flat varying vec4 vClipCenter_Radius_BR;
|
||||
flat varying vec4 vClipCenter_Radius_BL;
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
|
||||
struct BrushPrimitive {
|
||||
float clip_mode;
|
||||
float radius;
|
||||
};
|
||||
|
||||
BrushPrimitive fetch_brush_primitive(int address) {
|
||||
vec4 data = fetch_from_resource_cache_1(address);
|
||||
return BrushPrimitive(data.x, data.y);
|
||||
}
|
||||
|
||||
void brush_vs(int prim_address, vec4 prim_rect) {
|
||||
// Load the specific primitive.
|
||||
BrushPrimitive prim = fetch_brush_primitive(prim_address + 2);
|
||||
|
||||
// Write clip parameters
|
||||
vClipMode = prim.clip_mode;
|
||||
|
||||
vec2 r = vec2(prim.radius);
|
||||
vClipCenter_Radius_TL = vec4(prim_rect.xy + vec2(r.x, r.y), r);
|
||||
vClipCenter_Radius_TR = vec4(prim_rect.zy + vec2(-r.x, r.y), r);
|
||||
vClipCenter_Radius_BR = vec4(prim_rect.zw + vec2(-r.x, -r.y), r);
|
||||
vClipCenter_Radius_BL = vec4(prim_rect.xw + vec2(r.x, -r.y), r);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
vec4 brush_fs(vec2 local_pos, vec4 local_rect) {
|
||||
// TODO(gw): The mask code below is super-inefficient. Once we
|
||||
// start using primitive segments in brush shaders, this can
|
||||
// be made much faster.
|
||||
float d = 0.0;
|
||||
// Check if in valid clip region.
|
||||
if (local_pos.x >= local_rect.x && local_pos.x < local_rect.z &&
|
||||
local_pos.y >= local_rect.y && local_pos.y < local_rect.w) {
|
||||
// Apply ellipse clip on each corner.
|
||||
d = rounded_rect(local_pos,
|
||||
vClipCenter_Radius_TL,
|
||||
vClipCenter_Radius_TR,
|
||||
vClipCenter_Radius_BR,
|
||||
vClipCenter_Radius_BL);
|
||||
}
|
||||
|
||||
return vec4(mix(d, 1.0 - d, vClipMode));
|
||||
}
|
||||
#endif
|
||||
|
||||
#include brush
|
|
@ -31,11 +31,7 @@ void main(void) {
|
|||
local_rect.xy + local_rect.zw,
|
||||
aPosition.xy);
|
||||
|
||||
#if defined WR_FEATURE_COLOR
|
||||
vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0).xy);
|
||||
#else
|
||||
vec2 texture_size = vec2(textureSize(sCacheA8, 0).xy);
|
||||
#endif
|
||||
vUv.z = src_task.data1.x;
|
||||
vBlurRadius = 3 * int(task.data1.y);
|
||||
vSigma = task.data1.y;
|
||||
|
@ -62,15 +58,6 @@ void main(void) {
|
|||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
|
||||
#if defined WR_FEATURE_COLOR
|
||||
#define SAMPLE_TYPE vec4
|
||||
#define SAMPLE_TEXTURE(uv) texture(sCacheRGBA8, uv)
|
||||
#else
|
||||
#define SAMPLE_TYPE float
|
||||
#define SAMPLE_TEXTURE(uv) texture(sCacheA8, uv).r
|
||||
#endif
|
||||
|
||||
// TODO(gw): Write a fast path blur that handles smaller blur radii
|
||||
// with a offset / weight uniform table and a constant
|
||||
// loop iteration count!
|
||||
|
@ -79,13 +66,13 @@ void main(void) {
|
|||
// the number of texture fetches needed for a gaussian blur.
|
||||
|
||||
void main(void) {
|
||||
SAMPLE_TYPE original_color = SAMPLE_TEXTURE(vUv);
|
||||
vec4 original_color = texture(sCacheRGBA8, vUv);
|
||||
|
||||
// TODO(gw): The gauss function gets NaNs when blur radius
|
||||
// is zero. In the future, detect this earlier
|
||||
// and skip the blur passes completely.
|
||||
if (vBlurRadius == 0) {
|
||||
oFragColor = vec4(original_color);
|
||||
oFragColor = original_color;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -96,7 +83,7 @@ void main(void) {
|
|||
gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y;
|
||||
|
||||
float gauss_coefficient_sum = 0.0;
|
||||
SAMPLE_TYPE avg_color = original_color * gauss_coefficient.x;
|
||||
vec4 avg_color = original_color * gauss_coefficient.x;
|
||||
gauss_coefficient_sum += gauss_coefficient.x;
|
||||
gauss_coefficient.xy *= gauss_coefficient.yz;
|
||||
|
||||
|
@ -104,15 +91,15 @@ void main(void) {
|
|||
vec2 offset = vOffsetScale * float(i);
|
||||
|
||||
vec2 st0 = clamp(vUv.xy - offset, vUvRect.xy, vUvRect.zw);
|
||||
avg_color += SAMPLE_TEXTURE(vec3(st0, vUv.z)) * gauss_coefficient.x;
|
||||
avg_color += texture(sCacheRGBA8, vec3(st0, vUv.z)) * gauss_coefficient.x;
|
||||
|
||||
vec2 st1 = clamp(vUv.xy + offset, vUvRect.xy, vUvRect.zw);
|
||||
avg_color += SAMPLE_TEXTURE(vec3(st1, vUv.z)) * gauss_coefficient.x;
|
||||
avg_color += texture(sCacheRGBA8, vec3(st1, vUv.z)) * gauss_coefficient.x;
|
||||
|
||||
gauss_coefficient_sum += 2.0 * gauss_coefficient.x;
|
||||
gauss_coefficient.xy *= gauss_coefficient.yz;
|
||||
}
|
||||
|
||||
oFragColor = vec4(avg_color) / gauss_coefficient_sum;
|
||||
oFragColor = avg_color / gauss_coefficient_sum;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include shared,prim_shared
|
||||
|
||||
varying vec2 vPos;
|
||||
flat varying vec2 vBorderRadii;
|
||||
flat varying float vBlurRadius;
|
||||
flat varying vec4 vBoxShadowRect;
|
||||
flat varying float vInverted;
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
in ivec2 aPrimAddress;
|
||||
in int aTaskIndex;
|
||||
|
||||
void main(void) {
|
||||
RenderTaskData task = fetch_render_task(aTaskIndex);
|
||||
BoxShadow bs = fetch_boxshadow_direct(ivec2(aPrimAddress.x + VECS_PER_PRIM_HEADER, aPrimAddress.y));
|
||||
|
||||
vec2 p0 = task.data0.xy;
|
||||
vec2 p1 = p0 + task.data0.zw;
|
||||
|
||||
vec2 pos = mix(p0, p1, aPosition.xy);
|
||||
|
||||
vBorderRadii = bs.border_radius_edge_size_blur_radius_inverted.xx;
|
||||
vBlurRadius = bs.border_radius_edge_size_blur_radius_inverted.z;
|
||||
vInverted = bs.border_radius_edge_size_blur_radius_inverted.w;
|
||||
vBoxShadowRect = vec4(bs.bs_rect.xy, bs.bs_rect.xy + bs.bs_rect.zw);
|
||||
|
||||
// The fragment shader expects logical units, beginning at where the
|
||||
// blur radius begins.
|
||||
// The first path of the equation gets the virtual position in
|
||||
// logical pixels within the patch rectangle (accounting for
|
||||
// bilinear offset). Then we add the start position of the
|
||||
// box shadow rect and subtract the blur radius to get the
|
||||
// virtual coordinates that the FS expects.
|
||||
vPos = (pos - 1.0 - p0) / uDevicePixelRatio + bs.bs_rect.xy - vec2(2.0 * vBlurRadius);
|
||||
|
||||
gl_Position = uTransform * vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
// See http://asciimath.org to render the equations here.
|
||||
|
||||
// The Gaussian function used for blurring:
|
||||
//
|
||||
// G_sigma(x) = 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2))
|
||||
float gauss(float x, float sigma) {
|
||||
float sigmaPow2 = sigma * sigma;
|
||||
return 1.0 / sqrt(6.283185307179586 * sigmaPow2) * exp(-(x * x) / (2.0 * sigmaPow2));
|
||||
}
|
||||
|
||||
// An approximation of the error function, which is related to the integral of the Gaussian
|
||||
// function:
|
||||
//
|
||||
// "erf"(x) = 2/sqrt(pi) int_0^x e^(-t^2) dt
|
||||
// ~~ 1 - 1 / (1 + a_1 x + a_2 x^2 + a_3 x^3 + a_4 x^4)^4
|
||||
//
|
||||
// where:
|
||||
//
|
||||
// a_1 = 0.278393, a_2 = 0.230389, a_3 = 0.000972, a_4 = 0.078108
|
||||
//
|
||||
// This approximation is accurate to `5 xx 10^-4`, more than accurate enough for our purposes.
|
||||
//
|
||||
// See: https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions
|
||||
float erf(float x) {
|
||||
bool negative = x < 0.0;
|
||||
if (negative)
|
||||
x = -x;
|
||||
float x2 = x * x;
|
||||
float x3 = x2 * x;
|
||||
float x4 = x2 * x2;
|
||||
float denom = 1.0 + 0.278393 * x + 0.230389 * x2 + 0.000972 * x3 + 0.078108 * x4;
|
||||
float result = 1.0 - 1.0 / (denom * denom * denom * denom);
|
||||
return negative ? -result : result;
|
||||
}
|
||||
|
||||
// A useful helper for calculating integrals of the Gaussian function via the error function:
|
||||
//
|
||||
// "erf"_sigma(x) = 2 int 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) dx
|
||||
// = "erf"(x/(sigma sqrt(2)))
|
||||
float erfSigma(float x, float sigma) {
|
||||
return erf(x / (sigma * 1.4142135623730951));
|
||||
}
|
||||
|
||||
// Returns the blurred color value from the box itself (not counting any rounded corners). `p_0` is
|
||||
// the vector distance to the top left corner of the box; `p_1` is the vector distance to its
|
||||
// bottom right corner.
|
||||
//
|
||||
// "colorFromRect"_sigma(p_0, p_1)
|
||||
// = int_{p_{0_y}}^{p_{1_y}} int_{p_{1_x}}^{p_{0_x}} G_sigma(y) G_sigma(x) dx dy
|
||||
// = 1/4 ("erf"_sigma(p_{1_x}) - "erf"_sigma(p_{0_x}))
|
||||
// ("erf"_sigma(p_{1_y}) - "erf"_sigma(p_{0_y}))
|
||||
float colorFromRect(vec2 p0, vec2 p1, float sigma) {
|
||||
return (erfSigma(p1.x, sigma) - erfSigma(p0.x, sigma)) *
|
||||
(erfSigma(p1.y, sigma) - erfSigma(p0.y, sigma)) / 4.0;
|
||||
}
|
||||
|
||||
// Returns the `x` coordinate on the ellipse with the given radii for the given `y` coordinate:
|
||||
//
|
||||
// "ellipsePoint"(y, y_0, a, b) = a sqrt(1 - ((y - y_0) / b)^2)
|
||||
float ellipsePoint(float y, float y0, vec2 radii) {
|
||||
float bStep = (y - y0) / radii.y;
|
||||
return radii.x * sqrt(1.0 - bStep * bStep);
|
||||
}
|
||||
|
||||
// A helper function to compute the value that needs to be subtracted to accommodate the border
|
||||
// corners.
|
||||
//
|
||||
// "colorCutout"_sigma(x_{0_l}, x_{0_r}, y_0, y_{min}, y_{max}, a, b)
|
||||
// = int_{y_{min}}^{y_{max}}
|
||||
// int_{x_{0_r} + "ellipsePoint"(y, y_0, a, b)}^{x_{0_r} + a} G_sigma(y) G_sigma(x) dx
|
||||
// + int_{x_{0_l} - a}^{x_{0_l} - "ellipsePoint"(y, y_0, a, b)} G_sigma(y) G_sigma(x)
|
||||
// dx dy
|
||||
// = int_{y_{min}}^{y_{max}} 1/2 G_sigma(y)
|
||||
// ("erf"_sigma(x_{0_r} + a) - "erf"_sigma(x_{0_r} + "ellipsePoint"(y, y_0, a, b)) +
|
||||
// "erf"_sigma(x_{0_l} - "ellipsePoint"(y, y_0, a, b)) - "erf"_sigma(x_{0_l} - a))
|
||||
//
|
||||
// with the outer integral evaluated numerically.
|
||||
float colorCutoutGeneral(float x0l,
|
||||
float x0r,
|
||||
float y0,
|
||||
float yMin,
|
||||
float yMax,
|
||||
vec2 radii,
|
||||
float sigma) {
|
||||
float sum = 0.0;
|
||||
for (float y = yMin; y <= yMax; y += 1.0) {
|
||||
float xEllipsePoint = ellipsePoint(y, y0, radii);
|
||||
sum += gauss(y, sigma) *
|
||||
(erfSigma(x0r + radii.x, sigma) - erfSigma(x0r + xEllipsePoint, sigma) +
|
||||
erfSigma(x0l - xEllipsePoint, sigma) - erfSigma(x0l - radii.x, sigma));
|
||||
}
|
||||
return sum / 2.0;
|
||||
}
|
||||
|
||||
// The value that needs to be subtracted to accommodate the top border corners.
|
||||
float colorCutoutTop(float x0l, float x0r, float y0, vec2 radii, float sigma) {
|
||||
return colorCutoutGeneral(x0l, x0r, y0, y0, y0 + radii.y, radii, sigma);
|
||||
}
|
||||
|
||||
// The value that needs to be subtracted to accommodate the bottom border corners.
|
||||
float colorCutoutBottom(float x0l, float x0r, float y0, vec2 radii, float sigma) {
|
||||
return colorCutoutGeneral(x0l, x0r, y0, y0 - radii.y, y0, radii, sigma);
|
||||
}
|
||||
|
||||
// The blurred color value for the point at `pos` with the top left corner of the box at
|
||||
// `p_{0_"rect"}` and the bottom right corner of the box at `p_{1_"rect"}`.
|
||||
float color(vec2 pos, vec2 p0Rect, vec2 p1Rect, vec2 radii, float sigma) {
|
||||
// Compute the vector distances `p_0` and `p_1`.
|
||||
vec2 p0 = p0Rect - pos, p1 = p1Rect - pos;
|
||||
|
||||
// Compute the basic color `"colorFromRect"_sigma(p_0, p_1)`. This is all we have to do if
|
||||
// the box is unrounded.
|
||||
float cRect = colorFromRect(p0, p1, sigma);
|
||||
if (radii.x == 0.0 || radii.y == 0.0)
|
||||
return cRect;
|
||||
|
||||
// Compute the inner corners of the box, taking border radii into account: `x_{0_l}`,
|
||||
// `y_{0_t}`, `x_{0_r}`, and `y_{0_b}`.
|
||||
float x0l = p0.x + radii.x;
|
||||
float y0t = p1.y - radii.y;
|
||||
float x0r = p1.x - radii.x;
|
||||
float y0b = p0.y + radii.y;
|
||||
|
||||
// Compute the final color:
|
||||
//
|
||||
// "colorFromRect"_sigma(p_0, p_1) -
|
||||
// ("colorCutoutTop"_sigma(x_{0_l}, x_{0_r}, y_{0_t}, a, b) +
|
||||
// "colorCutoutBottom"_sigma(x_{0_l}, x_{0_r}, y_{0_b}, a, b))
|
||||
float cCutoutTop = colorCutoutTop(x0l, x0r, y0t, radii, sigma);
|
||||
float cCutoutBottom = colorCutoutBottom(x0l, x0r, y0b, radii, sigma);
|
||||
return cRect - (cCutoutTop + cCutoutBottom);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 pos = vPos.xy;
|
||||
vec2 p0Rect = vBoxShadowRect.xy, p1Rect = vBoxShadowRect.zw;
|
||||
vec2 radii = vBorderRadii.xy;
|
||||
float sigma = vBlurRadius / 2.0;
|
||||
float value = color(pos, p0Rect, p1Rect, radii, sigma);
|
||||
|
||||
value = max(value, 0.0);
|
||||
oFragColor = dither(vec4(vInverted == 1.0 ? 1.0 - value : value));
|
||||
}
|
||||
#endif
|
|
@ -155,7 +155,8 @@ void main(void) {
|
|||
clip_relative_pos);
|
||||
|
||||
// Get AA widths based on zoom / scale etc.
|
||||
float aa_range = compute_aa_range(local_pos);
|
||||
vec2 fw = fwidth(local_pos);
|
||||
float afwidth = length(fw);
|
||||
|
||||
// SDF subtract edges for dash clip
|
||||
float dash_distance = max(d0, -d1);
|
||||
|
@ -166,8 +167,8 @@ void main(void) {
|
|||
// Select between dot/dash clip based on mode.
|
||||
float d = mix(dash_distance, dot_distance, vAlphaMask.x);
|
||||
|
||||
// Apply AA.
|
||||
d = distance_aa(aa_range, d);
|
||||
// Apply AA over half a device pixel for the clip.
|
||||
d = 1.0 - smoothstep(0.0, 0.5 * afwidth, d);
|
||||
|
||||
// Completely mask out clip if zero'ing out the rect.
|
||||
d = d * vAlphaMask.y;
|
||||
|
|
|
@ -81,35 +81,76 @@ void main(void) {
|
|||
|
||||
RectWithEndpoint clip_rect = to_rect_with_endpoint(local_rect);
|
||||
|
||||
vec2 r_tl = clip.top_left.outer_inner_radius.xy;
|
||||
vec2 r_tr = clip.top_right.outer_inner_radius.xy;
|
||||
vec2 r_br = clip.bottom_right.outer_inner_radius.xy;
|
||||
vec2 r_bl = clip.bottom_left.outer_inner_radius.xy;
|
||||
vClipCenter_Radius_TL = vec4(clip_rect.p0 + clip.top_left.outer_inner_radius.xy,
|
||||
clip.top_left.outer_inner_radius.xy);
|
||||
|
||||
vClipCenter_Radius_TL = vec4(clip_rect.p0 + r_tl, r_tl);
|
||||
vClipCenter_Radius_TR = vec4(clip_rect.p1.x - clip.top_right.outer_inner_radius.x,
|
||||
clip_rect.p0.y + clip.top_right.outer_inner_radius.y,
|
||||
clip.top_right.outer_inner_radius.xy);
|
||||
|
||||
vClipCenter_Radius_TR = vec4(clip_rect.p1.x - r_tr.x,
|
||||
clip_rect.p0.y + r_tr.y,
|
||||
r_tr);
|
||||
vClipCenter_Radius_BR = vec4(clip_rect.p1 - clip.bottom_right.outer_inner_radius.xy,
|
||||
clip.bottom_right.outer_inner_radius.xy);
|
||||
|
||||
vClipCenter_Radius_BR = vec4(clip_rect.p1 - r_br, r_br);
|
||||
|
||||
vClipCenter_Radius_BL = vec4(clip_rect.p0.x + r_bl.x,
|
||||
clip_rect.p1.y - r_bl.y,
|
||||
r_bl);
|
||||
vClipCenter_Radius_BL = vec4(clip_rect.p0.x + clip.bottom_left.outer_inner_radius.x,
|
||||
clip_rect.p1.y - clip.bottom_left.outer_inner_radius.y,
|
||||
clip.bottom_left.outer_inner_radius.xy);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
float clip_against_ellipse_if_needed(vec2 pos,
|
||||
float current_distance,
|
||||
vec4 ellipse_center_radius,
|
||||
vec2 sign_modifier,
|
||||
float afwidth) {
|
||||
float ellipse_distance = distance_to_ellipse(pos - ellipse_center_radius.xy,
|
||||
ellipse_center_radius.zw);
|
||||
|
||||
return mix(current_distance,
|
||||
ellipse_distance + afwidth,
|
||||
all(lessThan(sign_modifier * pos, sign_modifier * ellipse_center_radius.xy)));
|
||||
}
|
||||
|
||||
float rounded_rect(vec2 pos) {
|
||||
float current_distance = 0.0;
|
||||
|
||||
// Apply AA
|
||||
float afwidth = 0.5 * length(fwidth(pos));
|
||||
|
||||
// Clip against each ellipse.
|
||||
current_distance = clip_against_ellipse_if_needed(pos,
|
||||
current_distance,
|
||||
vClipCenter_Radius_TL,
|
||||
vec2(1.0),
|
||||
afwidth);
|
||||
|
||||
current_distance = clip_against_ellipse_if_needed(pos,
|
||||
current_distance,
|
||||
vClipCenter_Radius_TR,
|
||||
vec2(-1.0, 1.0),
|
||||
afwidth);
|
||||
|
||||
current_distance = clip_against_ellipse_if_needed(pos,
|
||||
current_distance,
|
||||
vClipCenter_Radius_BR,
|
||||
vec2(-1.0),
|
||||
afwidth);
|
||||
|
||||
current_distance = clip_against_ellipse_if_needed(pos,
|
||||
current_distance,
|
||||
vClipCenter_Radius_BL,
|
||||
vec2(1.0, -1.0),
|
||||
afwidth);
|
||||
|
||||
return smoothstep(0.0, afwidth, 1.0 - current_distance);
|
||||
}
|
||||
|
||||
|
||||
void main(void) {
|
||||
float alpha = 1.f;
|
||||
vec2 local_pos = init_transform_fs(vPos, alpha);
|
||||
|
||||
float clip_alpha = rounded_rect(local_pos,
|
||||
vClipCenter_Radius_TL,
|
||||
vClipCenter_Radius_TR,
|
||||
vClipCenter_Radius_BR,
|
||||
vClipCenter_Radius_BL);
|
||||
float clip_alpha = rounded_rect(local_pos);
|
||||
|
||||
float combined_alpha = min(alpha, clip_alpha);
|
||||
|
||||
|
|
|
@ -18,16 +18,16 @@ void main(void) {
|
|||
|
||||
int glyph_index = prim.user_data0;
|
||||
int resource_address = prim.user_data1;
|
||||
int picture_address = prim.user_data2;
|
||||
int text_shadow_address = prim.user_data2;
|
||||
|
||||
// Fetch the owning picture for this primitive. This allows the code
|
||||
// Fetch the parent text-shadow for this primitive. This allows the code
|
||||
// below to normalize the glyph offsets relative to the original text
|
||||
// shadow rect, which is the union of all elements that make up this
|
||||
// text shadow. This allows the text shadow to be rendered at an
|
||||
// arbitrary location in a render target (provided by the render
|
||||
// task render_target_origin field).
|
||||
PrimitiveGeometry shadow_geom = fetch_primitive_geometry(picture_address);
|
||||
Picture pic = fetch_picture(picture_address + VECS_PER_PRIM_HEADER);
|
||||
PrimitiveGeometry shadow_geom = fetch_primitive_geometry(text_shadow_address);
|
||||
TextShadow shadow = fetch_text_shadow(text_shadow_address + VECS_PER_PRIM_HEADER);
|
||||
|
||||
Glyph glyph = fetch_glyph(prim.specific_prim_address,
|
||||
glyph_index,
|
||||
|
@ -41,7 +41,7 @@ void main(void) {
|
|||
vec2 size = (res.uv_rect.zw - res.uv_rect.xy) * res.scale;
|
||||
vec2 local_pos = glyph.offset + vec2(res.offset.x, -res.offset.y) / uDevicePixelRatio;
|
||||
vec2 origin = prim.task.render_target_origin +
|
||||
uDevicePixelRatio * (local_pos + pic.offset - shadow_geom.local_rect.p0);
|
||||
uDevicePixelRatio * (local_pos + shadow.offset - shadow_geom.local_rect.p0);
|
||||
vec4 local_rect = vec4(origin, size);
|
||||
|
||||
vec2 texture_size = vec2(textureSize(sColor0, 0));
|
||||
|
@ -53,7 +53,7 @@ void main(void) {
|
|||
aPosition.xy);
|
||||
|
||||
vUv = vec3(mix(st0, st1, aPosition.xy), res.layer);
|
||||
vColor = pic.color;
|
||||
vColor = shadow.color;
|
||||
|
||||
gl_Position = uTransform * vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
|
|
|
@ -66,55 +66,4 @@ float distance_to_ellipse(vec2 p, vec2 radii) {
|
|||
}
|
||||
}
|
||||
|
||||
float clip_against_ellipse_if_needed(
|
||||
vec2 pos,
|
||||
float current_distance,
|
||||
vec4 ellipse_center_radius,
|
||||
vec2 sign_modifier
|
||||
) {
|
||||
float ellipse_distance = distance_to_ellipse(pos - ellipse_center_radius.xy,
|
||||
ellipse_center_radius.zw);
|
||||
|
||||
return mix(current_distance,
|
||||
ellipse_distance,
|
||||
all(lessThan(sign_modifier * pos, sign_modifier * ellipse_center_radius.xy)));
|
||||
}
|
||||
|
||||
float rounded_rect(vec2 pos,
|
||||
vec4 clip_center_radius_tl,
|
||||
vec4 clip_center_radius_tr,
|
||||
vec4 clip_center_radius_br,
|
||||
vec4 clip_center_radius_bl) {
|
||||
// Start with a negative value (means "inside") for all fragments that are not
|
||||
// in a corner. If the fragment is in a corner, one of the clip_against_ellipse_if_needed
|
||||
// calls below will update it.
|
||||
float current_distance = -1.0;
|
||||
|
||||
// Clip against each ellipse.
|
||||
current_distance = clip_against_ellipse_if_needed(pos,
|
||||
current_distance,
|
||||
clip_center_radius_tl,
|
||||
vec2(1.0));
|
||||
|
||||
current_distance = clip_against_ellipse_if_needed(pos,
|
||||
current_distance,
|
||||
clip_center_radius_tr,
|
||||
vec2(-1.0, 1.0));
|
||||
|
||||
current_distance = clip_against_ellipse_if_needed(pos,
|
||||
current_distance,
|
||||
clip_center_radius_br,
|
||||
vec2(-1.0));
|
||||
|
||||
current_distance = clip_against_ellipse_if_needed(pos,
|
||||
current_distance,
|
||||
clip_center_radius_bl,
|
||||
vec2(1.0, -1.0));
|
||||
|
||||
// Apply AA
|
||||
// See comment in ps_border_corner about the choice of constants.
|
||||
float aa_range = compute_aa_range(pos);
|
||||
|
||||
return distance_aa(aa_range, current_distance);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -659,15 +659,15 @@ Rectangle fetch_rectangle(int address) {
|
|||
return Rectangle(data);
|
||||
}
|
||||
|
||||
struct Picture {
|
||||
struct TextShadow {
|
||||
vec4 color;
|
||||
vec2 offset;
|
||||
float blur_radius;
|
||||
};
|
||||
|
||||
Picture fetch_picture(int address) {
|
||||
TextShadow fetch_text_shadow(int address) {
|
||||
vec4 data[2] = fetch_from_resource_cache_2(address);
|
||||
return Picture(data[0], data[1].xy, data[1].z);
|
||||
return TextShadow(data[0], data[1].xy, data[1].z);
|
||||
}
|
||||
|
||||
struct TextRun {
|
||||
|
@ -692,6 +692,23 @@ Image fetch_image(int address) {
|
|||
return Image(data[0], data[1]);
|
||||
}
|
||||
|
||||
struct BoxShadow {
|
||||
vec4 src_rect;
|
||||
vec4 bs_rect;
|
||||
vec4 color;
|
||||
vec4 border_radius_edge_size_blur_radius_inverted;
|
||||
};
|
||||
|
||||
BoxShadow fetch_boxshadow(int address) {
|
||||
vec4 data[4] = fetch_from_resource_cache_4(address);
|
||||
return BoxShadow(data[0], data[1], data[2], data[3]);
|
||||
}
|
||||
|
||||
BoxShadow fetch_boxshadow_direct(ivec2 address) {
|
||||
vec4 data[4] = fetch_from_resource_cache_4_direct(address);
|
||||
return BoxShadow(data[0], data[1], data[2], data[3]);
|
||||
}
|
||||
|
||||
void write_clip(vec2 global_pos, ClipArea area) {
|
||||
vec2 texture_size = vec2(textureSize(sSharedCacheA8, 0).xy);
|
||||
vec2 uv = global_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
|
||||
|
@ -702,35 +719,6 @@ void write_clip(vec2 global_pos, ClipArea area) {
|
|||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
|
||||
/// Find the appropriate half range to apply the AA smoothstep over.
|
||||
/// This range represents a coefficient to go from one CSS pixel to half a device pixel.
|
||||
float compute_aa_range(vec2 position) {
|
||||
// The constant factor is chosen to compensate for the fact that length(fw) is equal
|
||||
// to sqrt(2) times the device pixel ratio in the typical case. 0.5/sqrt(2) = 0.35355.
|
||||
//
|
||||
// This coefficient is chosen to ensure that any sample 0.5 pixels or more inside of
|
||||
// the shape has no anti-aliasing applied to it (since pixels are sampled at their center,
|
||||
// such a pixel (axis aligned) is fully inside the border). We need this so that antialiased
|
||||
// curves properly connect with non-antialiased vertical or horizontal lines, among other things.
|
||||
//
|
||||
// Using larger aa steps is quite common when rendering shapes with distance fields.
|
||||
// It gives a smoother (although blurrier look) by extending the range that is smoothed
|
||||
// to produce the anti aliasing. In our case, however, extending the range inside of
|
||||
// the shape causes noticeable artifacts at the junction between an antialiased corner
|
||||
// and a straight edge.
|
||||
// We may want to adjust this constant in specific scenarios (for example keep the principled
|
||||
// value for straight edges where we want pixel-perfect equivalence with non antialiased lines
|
||||
// when axis aligned, while selecting a larger and smoother aa range on curves).
|
||||
return 0.35355 * length(fwidth(position));
|
||||
}
|
||||
|
||||
/// Return the blending coefficient to for distance antialiasing.
|
||||
///
|
||||
/// 0.0 means inside the shape, 1.0 means outside.
|
||||
float distance_aa(float aa_range, float signed_distance) {
|
||||
return 1.0 - smoothstep(-aa_range, aa_range, signed_distance);
|
||||
}
|
||||
|
||||
#ifdef WR_FEATURE_TRANSFORM
|
||||
float signed_distance_rect(vec2 pos, vec2 p0, vec2 p1) {
|
||||
vec2 d = max(p0 - pos, pos - p1);
|
||||
|
@ -745,10 +733,10 @@ vec2 init_transform_fs(vec3 local_pos, out float fragment_alpha) {
|
|||
float d = signed_distance_rect(pos, vLocalBounds.xy, vLocalBounds.zw);
|
||||
|
||||
// Find the appropriate distance to apply the AA smoothstep over.
|
||||
float aa_range = compute_aa_range(pos.xy);
|
||||
float afwidth = 0.5 * length(fwidth(pos.xy));
|
||||
|
||||
// Only apply AA to fragments outside the signed distance field.
|
||||
fragment_alpha = distance_aa(aa_range, d);
|
||||
fragment_alpha = 1.0 - smoothstep(0.0, afwidth, d);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
|
|
@ -324,7 +324,11 @@ void main(void) {
|
|||
|
||||
alpha = min(alpha, do_clip());
|
||||
|
||||
float aa_range = compute_aa_range(local_pos);
|
||||
// Find the appropriate distance to apply the AA smoothstep over.
|
||||
// Using 0.7 instead of 0.5 for the step compensates for the fact that smoothstep
|
||||
// is smooth at its endpoints and has a steeper maximum slope than a linear ramp.
|
||||
vec2 fw = fwidth(local_pos);
|
||||
float aa_step = 0.7 * length(fw);
|
||||
|
||||
float distance_for_color;
|
||||
float color_mix_factor;
|
||||
|
@ -345,26 +349,29 @@ void main(void) {
|
|||
// To correct this exactly we would need to offset p by half a pixel in the
|
||||
// direction of the center of the ellipse (a different offset for each corner).
|
||||
|
||||
// A half device pixel in css pixels (using the average of width and height in case
|
||||
// there is any kind of transform applied).
|
||||
float half_px = 0.25 * (fw.x + fw.y);
|
||||
// Get signed distance from the inner/outer clips.
|
||||
float d0 = distance_to_ellipse(p, vRadii0.xy);
|
||||
float d1 = distance_to_ellipse(p, vRadii0.zw);
|
||||
float d2 = distance_to_ellipse(p, vRadii1.xy);
|
||||
float d3 = distance_to_ellipse(p, vRadii1.zw);
|
||||
float d0 = distance_to_ellipse(p, vRadii0.xy) + half_px;
|
||||
float d1 = distance_to_ellipse(p, vRadii0.zw) + half_px;
|
||||
float d2 = distance_to_ellipse(p, vRadii1.xy) + half_px;
|
||||
float d3 = distance_to_ellipse(p, vRadii1.zw) + half_px;
|
||||
|
||||
// SDF subtract main radii
|
||||
float d_main = max(d0, -d1);
|
||||
float d_main = max(d0, aa_step - d1);
|
||||
|
||||
// SDF subtract inner radii (double style borders)
|
||||
float d_inner = max(d2, -d3);
|
||||
float d_inner = max(d2 - aa_step, -d3);
|
||||
|
||||
// Select how to combine the SDF based on border style.
|
||||
float d = mix(max(d_main, -d_inner), d_main, vSDFSelect);
|
||||
|
||||
// Only apply AA to fragments outside the signed distance field.
|
||||
alpha = min(alpha, distance_aa(aa_range, d));
|
||||
alpha = min(alpha, 1.0 - smoothstep(0.0, aa_step, d));
|
||||
|
||||
// Get the groove/ridge mix factor.
|
||||
color_mix_factor = distance_aa(aa_range, d2);
|
||||
color_mix_factor = smoothstep(-aa_step, aa_step, -d2);
|
||||
} else {
|
||||
// Handle the case where the fragment is outside the clip
|
||||
// region in a corner. This occurs when border width is
|
||||
|
@ -396,7 +403,7 @@ void main(void) {
|
|||
// Select color based on side of line. Get distance from the
|
||||
// reference line, and then apply AA along the edge.
|
||||
float ld = distance_to_line(vColorEdgeLine.xy, vColorEdgeLine.zw, local_pos);
|
||||
float m = distance_aa(aa_range, -ld);
|
||||
float m = smoothstep(-aa_step, aa_step, ld);
|
||||
vec4 color = mix(color0, color1, m);
|
||||
|
||||
oFragColor = color * vec4(1.0, 1.0, 1.0, alpha);
|
||||
|
|
|
@ -253,7 +253,8 @@ void main(void) {
|
|||
alpha = min(alpha, do_clip());
|
||||
|
||||
// Find the appropriate distance to apply the step over.
|
||||
float aa_range = compute_aa_range(local_pos);
|
||||
vec2 fw = fwidth(local_pos);
|
||||
float afwidth = length(fw);
|
||||
|
||||
// Applies the math necessary to draw a style: double
|
||||
// border. In the case of a solid border, the vertex
|
||||
|
@ -290,7 +291,9 @@ void main(void) {
|
|||
// Get the dot alpha
|
||||
vec2 dot_relative_pos = vec2(x, pos.x) - vClipParams.zw;
|
||||
float dot_distance = length(dot_relative_pos) - vClipParams.z;
|
||||
float dot_alpha = distance_aa(aa_range, dot_distance);
|
||||
float dot_alpha = 1.0 - smoothstep(-0.5 * afwidth,
|
||||
0.5 * afwidth,
|
||||
dot_distance);
|
||||
|
||||
// Select between dot/dash alpha based on clip mode.
|
||||
alpha = min(alpha, mix(dash_alpha, dot_alpha, vClipSelect));
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include shared,prim_shared
|
||||
|
||||
flat varying vec4 vColor;
|
||||
|
||||
varying vec3 vUv;
|
||||
flat varying vec2 vMirrorPoint;
|
||||
flat varying vec4 vCacheUvRectCoords;
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
#define BS_HEADER_VECS 4
|
||||
|
||||
RectWithSize fetch_instance_geometry(int address) {
|
||||
vec4 data = fetch_from_resource_cache_1(address);
|
||||
return RectWithSize(data.xy, data.zw);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
Primitive prim = load_primitive();
|
||||
BoxShadow bs = fetch_boxshadow(prim.specific_prim_address);
|
||||
RectWithSize segment_rect = fetch_instance_geometry(prim.specific_prim_address + BS_HEADER_VECS + prim.user_data0);
|
||||
|
||||
VertexInfo vi = write_vertex(segment_rect,
|
||||
prim.local_clip_rect,
|
||||
prim.z,
|
||||
prim.layer,
|
||||
prim.task,
|
||||
prim.local_rect);
|
||||
|
||||
RenderTaskData child_task = fetch_render_task(prim.user_data1);
|
||||
vUv.z = child_task.data1.x;
|
||||
|
||||
// Constant offsets to inset from bilinear filtering border.
|
||||
vec2 patch_origin = child_task.data0.xy + vec2(1.0);
|
||||
vec2 patch_size_device_pixels = child_task.data0.zw - vec2(2.0);
|
||||
vec2 patch_size = patch_size_device_pixels / uDevicePixelRatio;
|
||||
|
||||
vUv.xy = (vi.local_pos - prim.local_rect.p0) / patch_size;
|
||||
vMirrorPoint = 0.5 * prim.local_rect.size / patch_size;
|
||||
|
||||
vec2 texture_size = vec2(textureSize(sSharedCacheA8, 0));
|
||||
vCacheUvRectCoords = vec4(patch_origin, patch_origin + patch_size_device_pixels) / texture_size.xyxy;
|
||||
|
||||
vColor = bs.color;
|
||||
|
||||
write_clip(vi.screen_pos, prim.clip_area);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
void main(void) {
|
||||
vec4 clip_scale = vec4(1.0, 1.0, 1.0, do_clip());
|
||||
|
||||
// Mirror and stretch the box shadow corner over the entire
|
||||
// primitives.
|
||||
vec2 uv = vMirrorPoint - abs(vUv.xy - vMirrorPoint);
|
||||
|
||||
// Ensure that we don't fetch texels outside the box
|
||||
// shadow corner. This can happen, for example, when
|
||||
// drawing the outer parts of an inset box shadow.
|
||||
uv = clamp(uv, vec2(0.0), vec2(1.0));
|
||||
|
||||
// Map the unit UV to the actual UV rect in the cache.
|
||||
uv = mix(vCacheUvRectCoords.xy, vCacheUvRectCoords.zw, uv);
|
||||
|
||||
// Modulate the box shadow by the color.
|
||||
float mask = texture(sSharedCacheA8, vec3(uv, vUv.z)).r;
|
||||
oFragColor = clip_scale * dither(vColor * vec4(1.0, 1.0, 1.0, mask));
|
||||
}
|
||||
#endif
|
|
@ -7,10 +7,6 @@
|
|||
varying vec3 vUv;
|
||||
flat varying vec4 vUvBounds;
|
||||
|
||||
#if defined WR_FEATURE_ALPHA
|
||||
flat varying vec4 vColor;
|
||||
#endif
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
// Draw a cached primitive (e.g. a blurred text run) from the
|
||||
// target cache to the framebuffer, applying tile clip boundaries.
|
||||
|
@ -28,14 +24,7 @@ void main(void) {
|
|||
RenderTaskData child_task = fetch_render_task(prim.user_data1);
|
||||
vUv.z = child_task.data1.x;
|
||||
|
||||
#if defined WR_FEATURE_COLOR
|
||||
vec2 texture_size = vec2(textureSize(sColor0, 0).xy);
|
||||
#else
|
||||
Picture pic = fetch_picture(prim.specific_prim_address);
|
||||
|
||||
vec2 texture_size = vec2(textureSize(sColor1, 0).xy);
|
||||
vColor = pic.color;
|
||||
#endif
|
||||
vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
|
||||
vec2 uv0 = child_task.data0.xy;
|
||||
vec2 uv1 = (child_task.data0.xy + child_task.data0.zw);
|
||||
|
||||
|
@ -45,32 +34,12 @@ void main(void) {
|
|||
uv1 / texture_size,
|
||||
f);
|
||||
vUvBounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) / texture_size.xyxy;
|
||||
|
||||
write_clip(vi.screen_pos, prim.clip_area);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
void main(void) {
|
||||
vec2 uv = clamp(vUv.xy, vUvBounds.xy, vUvBounds.zw);
|
||||
|
||||
#if defined WR_FEATURE_COLOR
|
||||
vec4 color = texture(sColor0, vec3(uv, vUv.z));
|
||||
#else
|
||||
vec4 color = vColor * texture(sColor1, vec3(uv, vUv.z)).r;
|
||||
#endif
|
||||
|
||||
// Un-premultiply the color from sampling the gradient.
|
||||
if (color.a > 0.0) {
|
||||
color.rgb /= color.a;
|
||||
|
||||
// Apply the clip mask
|
||||
color.a = min(color.a, do_clip());
|
||||
|
||||
// Pre-multiply the result.
|
||||
color.rgb *= color.a;
|
||||
}
|
||||
|
||||
oFragColor = color;
|
||||
oFragColor = texture(sColor0, vec3(uv, vUv.z));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -98,19 +98,19 @@ void main(void) {
|
|||
}
|
||||
|
||||
#ifdef WR_FEATURE_CACHE
|
||||
int picture_address = prim.user_data0;
|
||||
PrimitiveGeometry picture_geom = fetch_primitive_geometry(picture_address);
|
||||
Picture pic = fetch_picture(picture_address + VECS_PER_PRIM_HEADER);
|
||||
int text_shadow_address = prim.user_data0;
|
||||
PrimitiveGeometry shadow_geom = fetch_primitive_geometry(text_shadow_address);
|
||||
TextShadow shadow = fetch_text_shadow(text_shadow_address + VECS_PER_PRIM_HEADER);
|
||||
|
||||
vec2 device_origin = prim.task.render_target_origin +
|
||||
uDevicePixelRatio * (prim.local_rect.p0 + pic.offset - picture_geom.local_rect.p0);
|
||||
uDevicePixelRatio * (prim.local_rect.p0 + shadow.offset - shadow_geom.local_rect.p0);
|
||||
vec2 device_size = uDevicePixelRatio * prim.local_rect.size;
|
||||
|
||||
vec2 device_pos = mix(device_origin,
|
||||
device_origin + device_size,
|
||||
aPosition.xy);
|
||||
|
||||
vColor = pic.color;
|
||||
vColor = shadow.color;
|
||||
vLocalPos = mix(prim.local_rect.p0,
|
||||
prim.local_rect.p0 + prim.local_rect.size,
|
||||
aPosition.xy);
|
||||
|
@ -190,7 +190,8 @@ void main(void) {
|
|||
#endif
|
||||
|
||||
// Find the appropriate distance to apply the step over.
|
||||
float aa_range = compute_aa_range(local_pos);
|
||||
vec2 fw = fwidth(local_pos);
|
||||
float afwidth = length(fw);
|
||||
|
||||
// Select the x/y coord, depending on which axis this edge is.
|
||||
vec2 pos = mix(local_pos.xy, local_pos.yx, vAxisSelect);
|
||||
|
@ -214,7 +215,9 @@ void main(void) {
|
|||
// Get the dot alpha
|
||||
vec2 dot_relative_pos = vec2(x, pos.y) - vParams.yz;
|
||||
float dot_distance = length(dot_relative_pos) - vParams.y;
|
||||
alpha = min(alpha, distance_aa(aa_range, dot_distance));
|
||||
alpha = min(alpha, 1.0 - smoothstep(-0.5 * afwidth,
|
||||
0.5 * afwidth,
|
||||
dot_distance));
|
||||
break;
|
||||
}
|
||||
case LINE_STYLE_WAVY: {
|
||||
|
@ -248,7 +251,9 @@ void main(void) {
|
|||
float d = min(d1, d2);
|
||||
|
||||
// Apply AA based on the thickness of the wave.
|
||||
alpha = distance_aa(aa_range, d - vParams.x);
|
||||
alpha = 1.0 - smoothstep(vParams.x - 0.5 * afwidth,
|
||||
vParams.x + 0.5 * afwidth,
|
||||
d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,10 +89,10 @@ void main(void) {
|
|||
modulate_color = alpha * vColor;
|
||||
break;
|
||||
case MODE_SUBPX_PASS0:
|
||||
modulate_color = vec4(alpha) * vColor.a;
|
||||
modulate_color = vec4(alpha);
|
||||
break;
|
||||
case MODE_SUBPX_PASS1:
|
||||
modulate_color = alpha * vColor;
|
||||
modulate_color = vColor;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,20 +2,16 @@
|
|||
* 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::{ClipId, DeviceIntRect, LayerPixel, LayerPoint, LayerRect, LayerSize};
|
||||
use api::{ClipId, LayerPixel, LayerPoint, LayerRect, LayerSize};
|
||||
use api::{LayerToScrollTransform, LayerToWorldTransform, LayerVector2D, PipelineId};
|
||||
use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollSensitivity, StickyFrameInfo};
|
||||
use api::WorldPoint;
|
||||
use clip::{ClipRegion, ClipSources, ClipSourcesHandle, ClipStore};
|
||||
use clip_scroll_tree::{CoordinateSystemId, TransformUpdateState};
|
||||
use clip_scroll_tree::TransformUpdateState;
|
||||
use geometry::ray_intersects_rect;
|
||||
use gpu_cache::GpuCache;
|
||||
use render_task::{ClipChain, ClipChainNode, ClipWorkItem};
|
||||
use resource_cache::ResourceCache;
|
||||
use spring::{DAMPING, STIFFNESS, Spring};
|
||||
use std::rc::Rc;
|
||||
use tiling::{PackedLayer, PackedLayerIndex};
|
||||
use util::{MatrixHelpers, MaxRect};
|
||||
use spring::{Spring, DAMPING, STIFFNESS};
|
||||
use tiling::PackedLayerIndex;
|
||||
use util::MatrixHelpers;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
const CAN_OVERSCROLL: bool = true;
|
||||
|
@ -31,9 +27,6 @@ pub struct ClipInfo {
|
|||
/// The packed layer index for this node, which is used to render a clip mask
|
||||
/// for it, if necessary.
|
||||
pub packed_layer_index: PackedLayerIndex,
|
||||
|
||||
/// Whether or not this clip node automatically creates a mask.
|
||||
pub is_masking: bool,
|
||||
}
|
||||
|
||||
impl ClipInfo {
|
||||
|
@ -42,13 +35,9 @@ impl ClipInfo {
|
|||
packed_layer_index: PackedLayerIndex,
|
||||
clip_store: &mut ClipStore,
|
||||
) -> ClipInfo {
|
||||
let clip_sources = ClipSources::from(clip_region);
|
||||
let is_masking = clip_sources.is_masking();
|
||||
|
||||
ClipInfo {
|
||||
clip_sources: clip_store.insert(clip_sources),
|
||||
clip_sources: clip_store.insert(ClipSources::from(clip_region)),
|
||||
packed_layer_index,
|
||||
is_masking,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -113,43 +102,9 @@ pub struct ClipScrollNode {
|
|||
|
||||
/// Whether or not this node is a reference frame.
|
||||
pub node_type: NodeType,
|
||||
|
||||
/// The node in the chain of clips that are necessary to clip display items
|
||||
/// that have this ClipScrollNode as their clip parent. This will be used to
|
||||
/// generate clip tasks.
|
||||
pub clip_chain_node: ClipChain,
|
||||
|
||||
/// The intersected outer bounds of the clips for this node.
|
||||
pub combined_clip_outer_bounds: DeviceIntRect,
|
||||
|
||||
/// The axis-aligned coordinate system id of this node.
|
||||
pub coordinate_system_id: CoordinateSystemId,
|
||||
}
|
||||
|
||||
impl ClipScrollNode {
|
||||
fn new(
|
||||
pipeline_id: PipelineId,
|
||||
parent_id: Option<ClipId>,
|
||||
rect: &LayerRect,
|
||||
node_type: NodeType
|
||||
) -> ClipScrollNode {
|
||||
ClipScrollNode {
|
||||
local_viewport_rect: *rect,
|
||||
local_clip_rect: *rect,
|
||||
combined_local_viewport_rect: LayerRect::zero(),
|
||||
world_viewport_transform: LayerToWorldTransform::identity(),
|
||||
world_content_transform: LayerToWorldTransform::identity(),
|
||||
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
|
||||
parent: parent_id,
|
||||
children: Vec::new(),
|
||||
pipeline_id,
|
||||
node_type: node_type,
|
||||
clip_chain_node: None,
|
||||
combined_clip_outer_bounds: DeviceIntRect::max_rect(),
|
||||
coordinate_system_id: CoordinateSystemId(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_scroll_frame(
|
||||
pipeline_id: PipelineId,
|
||||
parent_id: ClipId,
|
||||
|
@ -157,15 +112,24 @@ impl ClipScrollNode {
|
|||
content_size: &LayerSize,
|
||||
scroll_sensitivity: ScrollSensitivity,
|
||||
) -> ClipScrollNode {
|
||||
let node_type = NodeType::ScrollFrame(ScrollingState::new(
|
||||
scroll_sensitivity,
|
||||
LayerSize::new(
|
||||
(content_size.width - frame_rect.size.width).max(0.0),
|
||||
(content_size.height - frame_rect.size.height).max(0.0)
|
||||
)
|
||||
));
|
||||
|
||||
Self::new(pipeline_id, Some(parent_id), frame_rect, node_type)
|
||||
ClipScrollNode {
|
||||
local_viewport_rect: *frame_rect,
|
||||
local_clip_rect: *frame_rect,
|
||||
combined_local_viewport_rect: LayerRect::zero(),
|
||||
world_viewport_transform: LayerToWorldTransform::identity(),
|
||||
world_content_transform: LayerToWorldTransform::identity(),
|
||||
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
|
||||
parent: Some(parent_id),
|
||||
children: Vec::new(),
|
||||
pipeline_id,
|
||||
node_type: NodeType::ScrollFrame(ScrollingState::new(
|
||||
scroll_sensitivity,
|
||||
LayerSize::new(
|
||||
(content_size.width - frame_rect.size.width).max(0.0),
|
||||
(content_size.height - frame_rect.size.height).max(0.0)
|
||||
)
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_clip_node(
|
||||
|
@ -174,12 +138,23 @@ impl ClipScrollNode {
|
|||
clip_info: ClipInfo,
|
||||
clip_rect: LayerRect,
|
||||
) -> ClipScrollNode {
|
||||
Self::new(pipeline_id, Some(parent_id), &clip_rect, NodeType::Clip(clip_info))
|
||||
ClipScrollNode {
|
||||
local_viewport_rect: clip_rect,
|
||||
local_clip_rect: clip_rect,
|
||||
combined_local_viewport_rect: LayerRect::zero(),
|
||||
world_viewport_transform: LayerToWorldTransform::identity(),
|
||||
world_content_transform: LayerToWorldTransform::identity(),
|
||||
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
|
||||
parent: Some(parent_id),
|
||||
children: Vec::new(),
|
||||
pipeline_id,
|
||||
node_type: NodeType::Clip(clip_info),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_reference_frame(
|
||||
parent_id: Option<ClipId>,
|
||||
frame_rect: &LayerRect,
|
||||
local_viewport_rect: &LayerRect,
|
||||
transform: &LayerToScrollTransform,
|
||||
origin_in_parent_reference_frame: LayerVector2D,
|
||||
pipeline_id: PipelineId,
|
||||
|
@ -188,7 +163,19 @@ impl ClipScrollNode {
|
|||
transform: *transform,
|
||||
origin_in_parent_reference_frame,
|
||||
};
|
||||
Self::new(pipeline_id, parent_id, frame_rect, NodeType::ReferenceFrame(info))
|
||||
|
||||
ClipScrollNode {
|
||||
local_viewport_rect: *local_viewport_rect,
|
||||
local_clip_rect: *local_viewport_rect,
|
||||
combined_local_viewport_rect: LayerRect::zero(),
|
||||
world_viewport_transform: LayerToWorldTransform::identity(),
|
||||
world_content_transform: LayerToWorldTransform::identity(),
|
||||
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
|
||||
parent: parent_id,
|
||||
children: Vec::new(),
|
||||
pipeline_id,
|
||||
node_type: NodeType::ReferenceFrame(info),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_sticky_frame(
|
||||
|
@ -197,8 +184,18 @@ impl ClipScrollNode {
|
|||
sticky_frame_info: StickyFrameInfo,
|
||||
pipeline_id: PipelineId,
|
||||
) -> ClipScrollNode {
|
||||
let node_type = NodeType::StickyFrame(sticky_frame_info, LayerVector2D::zero());
|
||||
Self::new(pipeline_id, Some(parent_id), &frame_rect, node_type)
|
||||
ClipScrollNode {
|
||||
local_viewport_rect: frame_rect,
|
||||
local_clip_rect: frame_rect,
|
||||
combined_local_viewport_rect: LayerRect::zero(),
|
||||
world_viewport_transform: LayerToWorldTransform::identity(),
|
||||
world_content_transform: LayerToWorldTransform::identity(),
|
||||
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
|
||||
parent: Some(parent_id),
|
||||
children: Vec::new(),
|
||||
pipeline_id,
|
||||
node_type: NodeType::StickyFrame(sticky_frame_info, LayerVector2D::zero()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -258,79 +255,7 @@ impl ClipScrollNode {
|
|||
true
|
||||
}
|
||||
|
||||
pub fn update_clip_work_item(
|
||||
&mut self,
|
||||
state: &mut TransformUpdateState,
|
||||
screen_rect: &DeviceIntRect,
|
||||
device_pixel_ratio: f32,
|
||||
packed_layers: &mut Vec<PackedLayer>,
|
||||
clip_store: &mut ClipStore,
|
||||
resource_cache: &mut ResourceCache,
|
||||
gpu_cache: &mut GpuCache,
|
||||
) {
|
||||
self.coordinate_system_id = state.current_coordinate_system_id;
|
||||
|
||||
let current_clip_chain = state.parent_clip_chain.clone();
|
||||
let clip_info = match self.node_type {
|
||||
NodeType::Clip(ref mut info) if info.is_masking => info,
|
||||
_ => {
|
||||
self.clip_chain_node = current_clip_chain;
|
||||
self.combined_clip_outer_bounds = state.combined_outer_clip_bounds;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// The coordinates of the mask are relative to the origin of the node itself,
|
||||
// so we need to account for that origin in the transformation we assign to
|
||||
// the packed layer.
|
||||
let transform = self.world_viewport_transform
|
||||
.pre_translate(self.local_viewport_rect.origin.to_vector().to_3d());
|
||||
|
||||
let packed_layer = &mut packed_layers[clip_info.packed_layer_index.0];
|
||||
if packed_layer.set_transform(transform) {
|
||||
// Meanwhile, the combined viewport rect is relative to the reference frame, so
|
||||
// we move it into the local coordinate system of the node.
|
||||
let local_viewport_rect = self.combined_local_viewport_rect
|
||||
.translate(&-self.local_viewport_rect.origin.to_vector());
|
||||
|
||||
packed_layer.set_rect(
|
||||
&local_viewport_rect,
|
||||
screen_rect,
|
||||
device_pixel_ratio,
|
||||
);
|
||||
}
|
||||
|
||||
let clip_sources = clip_store.get_mut(&clip_info.clip_sources);
|
||||
clip_sources.update(
|
||||
&transform,
|
||||
gpu_cache,
|
||||
resource_cache,
|
||||
device_pixel_ratio,
|
||||
);
|
||||
|
||||
let outer_bounds = clip_sources.bounds.outer.as_ref().map_or_else(
|
||||
DeviceIntRect::zero,
|
||||
|rect| rect.device_rect
|
||||
);
|
||||
|
||||
self.combined_clip_outer_bounds = outer_bounds.intersection(
|
||||
&state.combined_outer_clip_bounds).unwrap_or_else(DeviceIntRect::zero);
|
||||
|
||||
// TODO: Combine rectangles in the same axis-aligned clip space here?
|
||||
self.clip_chain_node = Some(Rc::new(ClipChainNode {
|
||||
work_item: ClipWorkItem {
|
||||
layer_index: clip_info.packed_layer_index,
|
||||
clip_sources: clip_info.clip_sources.weak(),
|
||||
coordinate_system_id: state.current_coordinate_system_id,
|
||||
},
|
||||
prev: current_clip_chain,
|
||||
}));
|
||||
|
||||
state.combined_outer_clip_bounds = self.combined_clip_outer_bounds;
|
||||
state.parent_clip_chain = self.clip_chain_node.clone();
|
||||
}
|
||||
|
||||
pub fn update_transform(&mut self, state: &mut TransformUpdateState) {
|
||||
pub fn update_transform(&mut self, state: &TransformUpdateState) {
|
||||
// We calculate this here to avoid a double-borrow later.
|
||||
let sticky_offset = self.calculate_sticky_offset(
|
||||
&state.nearest_scrolling_ancestor_offset,
|
||||
|
@ -390,45 +315,6 @@ impl ClipScrollNode {
|
|||
let scroll_offset = self.scroll_offset();
|
||||
self.world_content_transform = self.world_viewport_transform
|
||||
.pre_translate(scroll_offset.to_3d());
|
||||
|
||||
// The transformation we are passing is the transformation of the parent
|
||||
// reference frame and the offset is the accumulated offset of all the nodes
|
||||
// between us and the parent reference frame. If we are a reference frame,
|
||||
// we need to reset both these values.
|
||||
match self.node_type {
|
||||
NodeType::ReferenceFrame(ref info) => {
|
||||
state.parent_reference_frame_transform = self.world_viewport_transform;
|
||||
state.parent_combined_viewport_rect = self.combined_local_viewport_rect;
|
||||
state.parent_accumulated_scroll_offset = LayerVector2D::zero();
|
||||
state.nearest_scrolling_ancestor_viewport =
|
||||
state.nearest_scrolling_ancestor_viewport
|
||||
.translate(&info.origin_in_parent_reference_frame);
|
||||
|
||||
if !info.transform.preserves_2d_axis_alignment() {
|
||||
state.current_coordinate_system_id = state.next_coordinate_system_id;
|
||||
state.next_coordinate_system_id = state.next_coordinate_system_id.next();
|
||||
}
|
||||
},
|
||||
NodeType::Clip(..) => {
|
||||
state.parent_combined_viewport_rect = self.combined_local_viewport_rect;
|
||||
},
|
||||
NodeType::ScrollFrame(ref scrolling) => {
|
||||
state.parent_combined_viewport_rect =
|
||||
self.combined_local_viewport_rect.translate(&-scrolling.offset);
|
||||
state.parent_accumulated_scroll_offset =
|
||||
scrolling.offset + state.parent_accumulated_scroll_offset;
|
||||
state.nearest_scrolling_ancestor_offset = scrolling.offset;
|
||||
state.nearest_scrolling_ancestor_viewport = self.local_viewport_rect;
|
||||
}
|
||||
NodeType::StickyFrame(_, sticky_offset) => {
|
||||
// We don't translate the combined rect by the sticky offset, because sticky
|
||||
// offsets actually adjust the node position itself, whereas scroll offsets
|
||||
// only apply to contents inside the node.
|
||||
state.parent_combined_viewport_rect = self.combined_local_viewport_rect;
|
||||
state.parent_accumulated_scroll_offset =
|
||||
sticky_offset + state.parent_accumulated_scroll_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_sticky_offset(
|
||||
|
|
|
@ -2,35 +2,16 @@
|
|||
* 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::{ClipId, DeviceIntRect, LayerPoint, LayerRect};
|
||||
use api::{LayerToScrollTransform, LayerToWorldTransform, LayerVector2D, PipelineId};
|
||||
use api::{ScrollClamping, ScrollEventPhase, ScrollLayerState, ScrollLocation, StickyFrameInfo};
|
||||
use api::WorldPoint;
|
||||
use api::{ClipId, LayerPoint, LayerRect, LayerToScrollTransform, LayerToWorldTransform};
|
||||
use api::{LayerVector2D, PipelineId, ScrollClamping, ScrollEventPhase, ScrollLayerState};
|
||||
use api::{ScrollLocation, StickyFrameInfo, WorldPoint};
|
||||
use clip::ClipStore;
|
||||
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollingState};
|
||||
use gpu_cache::GpuCache;
|
||||
use internal_types::{FastHashMap, FastHashSet};
|
||||
use print_tree::{PrintTree, PrintTreePrinter};
|
||||
use render_task::ClipChain;
|
||||
use resource_cache::ResourceCache;
|
||||
use tiling::PackedLayer;
|
||||
|
||||
pub type ScrollStates = FastHashMap<ClipId, ScrollingState>;
|
||||
|
||||
/// An id that identifies coordinate systems in the ClipScrollTree. Each
|
||||
/// coordinate system has an id and those ids will be shared when the coordinates
|
||||
/// system are the same or are in the same axis-aligned space. This allows
|
||||
/// for optimizing mask generation.
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct CoordinateSystemId(pub u32);
|
||||
|
||||
impl CoordinateSystemId {
|
||||
pub fn next(&self) -> CoordinateSystemId {
|
||||
let CoordinateSystemId(id) = *self;
|
||||
CoordinateSystemId(id + 1)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ClipScrollTree {
|
||||
pub nodes: FastHashMap<ClipId, ClipScrollNode>,
|
||||
pub pending_scroll_offsets: FastHashMap<ClipId, (LayerPoint, ScrollClamping)>,
|
||||
|
@ -57,22 +38,12 @@ pub struct ClipScrollTree {
|
|||
pub pipelines_to_discard: FastHashSet<PipelineId>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TransformUpdateState {
|
||||
pub parent_reference_frame_transform: LayerToWorldTransform,
|
||||
pub parent_combined_viewport_rect: LayerRect,
|
||||
pub parent_accumulated_scroll_offset: LayerVector2D,
|
||||
pub nearest_scrolling_ancestor_offset: LayerVector2D,
|
||||
pub nearest_scrolling_ancestor_viewport: LayerRect,
|
||||
pub parent_clip_chain: ClipChain,
|
||||
pub combined_outer_clip_bounds: DeviceIntRect,
|
||||
|
||||
/// 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
|
||||
/// display list item, since optimizations can usually only be done among
|
||||
/// coordinate systems which are relatively axis aligned.
|
||||
pub current_coordinate_system_id: CoordinateSystemId,
|
||||
pub next_coordinate_system_id: CoordinateSystemId,
|
||||
}
|
||||
|
||||
impl ClipScrollTree {
|
||||
|
@ -326,24 +297,14 @@ impl ClipScrollTree {
|
|||
.scroll(scroll_location, phase)
|
||||
}
|
||||
|
||||
pub fn update_all_node_transforms(
|
||||
&mut self,
|
||||
screen_rect: &DeviceIntRect,
|
||||
device_pixel_ratio: f32,
|
||||
packed_layers: &mut Vec<PackedLayer>,
|
||||
clip_store: &mut ClipStore,
|
||||
resource_cache: &mut ResourceCache,
|
||||
gpu_cache: &mut GpuCache,
|
||||
pan: LayerPoint,
|
||||
) {
|
||||
pub fn update_all_node_transforms(&mut self, pan: LayerPoint) {
|
||||
if self.nodes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let root_reference_frame_id = self.root_reference_frame_id();
|
||||
let root_viewport = self.nodes[&root_reference_frame_id].local_clip_rect;
|
||||
|
||||
let mut state = TransformUpdateState {
|
||||
let state = TransformUpdateState {
|
||||
parent_reference_frame_transform: LayerToWorldTransform::create_translation(
|
||||
pan.x,
|
||||
pan.y,
|
||||
|
@ -353,68 +314,63 @@ impl ClipScrollTree {
|
|||
parent_accumulated_scroll_offset: LayerVector2D::zero(),
|
||||
nearest_scrolling_ancestor_offset: LayerVector2D::zero(),
|
||||
nearest_scrolling_ancestor_viewport: LayerRect::zero(),
|
||||
parent_clip_chain: None,
|
||||
combined_outer_clip_bounds: *screen_rect,
|
||||
current_coordinate_system_id: CoordinateSystemId(0),
|
||||
next_coordinate_system_id: CoordinateSystemId(0).next(),
|
||||
};
|
||||
self.update_node_transform(
|
||||
root_reference_frame_id,
|
||||
&mut state,
|
||||
&screen_rect,
|
||||
device_pixel_ratio,
|
||||
packed_layers,
|
||||
clip_store,
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
);
|
||||
self.update_node_transform(root_reference_frame_id, &state);
|
||||
}
|
||||
|
||||
fn update_node_transform(
|
||||
&mut self,
|
||||
layer_id: ClipId,
|
||||
state: &mut TransformUpdateState,
|
||||
screen_rect: &DeviceIntRect,
|
||||
device_pixel_ratio: f32,
|
||||
packed_layers: &mut Vec<PackedLayer>,
|
||||
clip_store: &mut ClipStore,
|
||||
resource_cache: &mut ResourceCache,
|
||||
gpu_cache: &mut GpuCache,
|
||||
) {
|
||||
fn update_node_transform(&mut self, layer_id: ClipId, state: &TransformUpdateState) {
|
||||
// TODO(gw): This is an ugly borrow check workaround to clone these.
|
||||
// Restructure this to avoid the clones!
|
||||
let mut state = state.clone();
|
||||
let node_children = {
|
||||
let (state, node_children) = {
|
||||
let node = match self.nodes.get_mut(&layer_id) {
|
||||
Some(node) => node,
|
||||
None => return,
|
||||
};
|
||||
node.update_transform(&state);
|
||||
|
||||
node.update_transform(&mut state);
|
||||
node.update_clip_work_item(
|
||||
&mut state,
|
||||
screen_rect,
|
||||
device_pixel_ratio,
|
||||
packed_layers,
|
||||
clip_store,
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
);
|
||||
// The transformation we are passing is the transformation of the parent
|
||||
// reference frame and the offset is the accumulated offset of all the nodes
|
||||
// between us and the parent reference frame. If we are a reference frame,
|
||||
// we need to reset both these values.
|
||||
let state = match node.node_type {
|
||||
NodeType::ReferenceFrame(ref info) => TransformUpdateState {
|
||||
parent_reference_frame_transform: node.world_viewport_transform,
|
||||
parent_combined_viewport_rect: node.combined_local_viewport_rect,
|
||||
parent_accumulated_scroll_offset: LayerVector2D::zero(),
|
||||
nearest_scrolling_ancestor_viewport: state
|
||||
.nearest_scrolling_ancestor_viewport
|
||||
.translate(&info.origin_in_parent_reference_frame),
|
||||
..*state
|
||||
},
|
||||
NodeType::Clip(..) => TransformUpdateState {
|
||||
parent_combined_viewport_rect: node.combined_local_viewport_rect,
|
||||
..*state
|
||||
},
|
||||
NodeType::ScrollFrame(ref scrolling) => TransformUpdateState {
|
||||
parent_combined_viewport_rect:
|
||||
node.combined_local_viewport_rect.translate(&-scrolling.offset),
|
||||
parent_accumulated_scroll_offset: scrolling.offset +
|
||||
state.parent_accumulated_scroll_offset,
|
||||
nearest_scrolling_ancestor_offset: scrolling.offset,
|
||||
nearest_scrolling_ancestor_viewport: node.local_viewport_rect,
|
||||
..*state
|
||||
},
|
||||
NodeType::StickyFrame(_, sticky_offset) => TransformUpdateState {
|
||||
// We don't translate the combined rect by the sticky offset, because sticky
|
||||
// offsets actually adjust the node position itself, whereas scroll offsets
|
||||
// only apply to contents inside the node.
|
||||
parent_combined_viewport_rect: node.combined_local_viewport_rect,
|
||||
parent_accumulated_scroll_offset:
|
||||
sticky_offset + state.parent_accumulated_scroll_offset,
|
||||
..*state
|
||||
}
|
||||
};
|
||||
|
||||
node.children.clone()
|
||||
(state, node.children.clone())
|
||||
};
|
||||
|
||||
for child_layer_id in node_children {
|
||||
self.update_node_transform(
|
||||
child_layer_id,
|
||||
&mut state,
|
||||
screen_rect,
|
||||
device_pixel_ratio,
|
||||
packed_layers,
|
||||
clip_store,
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
);
|
||||
self.update_node_transform(child_layer_id, &state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -485,7 +485,8 @@ pub struct VBOId(gl::GLuint);
|
|||
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
|
||||
struct IBOId(gl::GLuint);
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
const MAX_TIMERS_PER_FRAME: usize = 256;
|
||||
const MAX_SAMPLERS_PER_FRAME: usize = 16;
|
||||
const MAX_PROFILE_FRAMES: usize = 4;
|
||||
|
||||
pub trait NamedTag {
|
||||
|
@ -504,14 +505,12 @@ pub struct GpuSampler<T> {
|
|||
pub count: u64,
|
||||
}
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
pub struct QuerySet<T> {
|
||||
set: Vec<gl::GLuint>,
|
||||
data: Vec<T>,
|
||||
pending: gl::GLuint,
|
||||
}
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
impl<T> QuerySet<T> {
|
||||
fn new(set: Vec<gl::GLuint>) -> Self {
|
||||
QuerySet {
|
||||
|
@ -544,7 +543,6 @@ impl<T> QuerySet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
pub struct GpuFrameProfile<T> {
|
||||
gl: Rc<gl::Gl>,
|
||||
timers: QuerySet<GpuTimer<T>>,
|
||||
|
@ -553,19 +551,15 @@ pub struct GpuFrameProfile<T> {
|
|||
inside_frame: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
impl<T> GpuFrameProfile<T> {
|
||||
const MAX_TIMERS_PER_FRAME: usize = 256;
|
||||
// disable samplers on OSX due to driver bugs
|
||||
#[cfg(target_os = "macos")]
|
||||
const MAX_SAMPLERS_PER_FRAME: usize = 0;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
const MAX_SAMPLERS_PER_FRAME: usize = 16;
|
||||
|
||||
fn new(gl: Rc<gl::Gl>) -> Self {
|
||||
assert_eq!(gl.get_type(), gl::GlType::Gl);
|
||||
let time_queries = gl.gen_queries(Self::MAX_TIMERS_PER_FRAME as _);
|
||||
let sample_queries = gl.gen_queries(Self::MAX_SAMPLERS_PER_FRAME as _);
|
||||
let (time_queries, sample_queries) = match gl.get_type() {
|
||||
gl::GlType::Gl => (
|
||||
gl.gen_queries(MAX_TIMERS_PER_FRAME as gl::GLint),
|
||||
gl.gen_queries(MAX_SAMPLERS_PER_FRAME as gl::GLint),
|
||||
),
|
||||
gl::GlType::Gles => (Vec::new(), Vec::new()),
|
||||
};
|
||||
|
||||
GpuFrameProfile {
|
||||
gl,
|
||||
|
@ -613,22 +607,26 @@ impl<T> GpuFrameProfile<T> {
|
|||
}
|
||||
|
||||
fn done_sampler(&mut self) {
|
||||
/* FIXME: samplers crash on MacOS
|
||||
debug_assert!(self.inside_frame);
|
||||
if self.samplers.pending != 0 {
|
||||
self.gl.end_query(gl::SAMPLES_PASSED);
|
||||
self.samplers.pending = 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
fn add_sampler(&mut self, tag: T)
|
||||
fn add_sampler(&mut self, _tag: T)
|
||||
where
|
||||
T: NamedTag,
|
||||
{
|
||||
/* FIXME: samplers crash on MacOS
|
||||
self.done_sampler();
|
||||
|
||||
if let Some(query) = self.samplers.add(GpuSampler { tag, count: 0 }) {
|
||||
self.gl.begin_query(gl::SAMPLES_PASSED, query);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> bool {
|
||||
|
@ -650,27 +648,25 @@ impl<T> GpuFrameProfile<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
impl<T> Drop for GpuFrameProfile<T> {
|
||||
fn drop(&mut self) {
|
||||
if !self.timers.set.is_empty() {
|
||||
self.gl.delete_queries(&self.timers.set);
|
||||
}
|
||||
if !self.samplers.set.is_empty() {
|
||||
self.gl.delete_queries(&self.samplers.set);
|
||||
match self.gl.get_type() {
|
||||
gl::GlType::Gl => {
|
||||
self.gl.delete_queries(&self.timers.set);
|
||||
self.gl.delete_queries(&self.samplers.set);
|
||||
}
|
||||
gl::GlType::Gles => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
pub struct GpuProfiler<T> {
|
||||
frames: [GpuFrameProfile<T>; MAX_PROFILE_FRAMES],
|
||||
next_frame: usize,
|
||||
}
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
impl<T> GpuProfiler<T> {
|
||||
pub fn new(gl: &Rc<gl::Gl>) -> Self {
|
||||
pub fn new(gl: &Rc<gl::Gl>) -> GpuProfiler<T> {
|
||||
GpuProfiler {
|
||||
next_frame: 0,
|
||||
frames: [
|
||||
|
@ -722,70 +718,44 @@ impl<T> GpuProfiler<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "query"))]
|
||||
pub struct GpuProfiler<T>(Option<T>);
|
||||
|
||||
#[cfg(not(feature = "query"))]
|
||||
impl<T> GpuProfiler<T> {
|
||||
pub fn new(_: &Rc<gl::Gl>) -> Self {
|
||||
GpuProfiler(None)
|
||||
}
|
||||
|
||||
pub fn build_samples(&mut self) -> Option<(FrameId, Vec<GpuTimer<T>>, Vec<GpuSampler<T>>)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn begin_frame(&mut self, _: FrameId) {}
|
||||
|
||||
pub fn end_frame(&mut self) {}
|
||||
|
||||
pub fn add_marker(&mut self, _: T) -> GpuMarker {
|
||||
GpuMarker {}
|
||||
}
|
||||
|
||||
pub fn add_sampler(&mut self, _: T) {}
|
||||
|
||||
pub fn done_sampler(&mut self) {}
|
||||
}
|
||||
|
||||
|
||||
#[must_use]
|
||||
pub struct GpuMarker {
|
||||
#[cfg(feature = "query")]
|
||||
gl: Rc<gl::Gl>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
impl GpuMarker {
|
||||
pub fn new(gl: &Rc<gl::Gl>, message: &str) -> Self {
|
||||
debug_assert_eq!(gl.get_type(), gl::GlType::Gl);
|
||||
gl.push_group_marker_ext(message);
|
||||
GpuMarker { gl: Rc::clone(gl) }
|
||||
pub fn new(gl: &Rc<gl::Gl>, message: &str) -> GpuMarker {
|
||||
match gl.get_type() {
|
||||
gl::GlType::Gl => {
|
||||
gl.push_group_marker_ext(message);
|
||||
GpuMarker { gl: Rc::clone(gl) }
|
||||
}
|
||||
gl::GlType::Gles => GpuMarker { gl: Rc::clone(gl) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fire(gl: &gl::Gl, message: &str) {
|
||||
debug_assert_eq!(gl.get_type(), gl::GlType::Gl);
|
||||
gl.insert_event_marker_ext(message);
|
||||
match gl.get_type() {
|
||||
gl::GlType::Gl => {
|
||||
gl.insert_event_marker_ext(message);
|
||||
}
|
||||
gl::GlType::Gles => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
|
||||
impl Drop for GpuMarker {
|
||||
fn drop(&mut self) {
|
||||
self.gl.pop_group_marker_ext();
|
||||
match self.gl.get_type() {
|
||||
gl::GlType::Gl => {
|
||||
self.gl.pop_group_marker_ext();
|
||||
}
|
||||
gl::GlType::Gles => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "query"))]
|
||||
impl GpuMarker {
|
||||
#[inline]
|
||||
pub fn new(_: &Rc<gl::Gl>, _: &str) -> Self {
|
||||
GpuMarker{}
|
||||
}
|
||||
#[inline]
|
||||
pub fn fire(_: &gl::Gl, _: &str) {}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum VertexUsageHint {
|
||||
|
|
|
@ -222,10 +222,6 @@ impl Frame {
|
|||
.finalize_and_apply_pending_scroll_offsets(old_scrolling_states);
|
||||
}
|
||||
|
||||
pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
|
||||
self.pipeline_epoch_map.insert(pipeline_id, epoch);
|
||||
}
|
||||
|
||||
fn flatten_clip<'a>(
|
||||
&mut self,
|
||||
context: &mut FlattenContext,
|
||||
|
@ -1099,7 +1095,7 @@ impl Frame {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn build_renderer_frame(
|
||||
pub fn build(
|
||||
&mut self,
|
||||
resource_cache: &mut ResourceCache,
|
||||
gpu_cache: &mut GpuCache,
|
||||
|
@ -1109,6 +1105,29 @@ impl Frame {
|
|||
output_pipelines: &FastHashSet<PipelineId>,
|
||||
texture_cache_profile: &mut TextureCacheProfileCounters,
|
||||
gpu_cache_profile: &mut GpuCacheProfileCounters,
|
||||
) -> RendererFrame {
|
||||
self.clip_scroll_tree.update_all_node_transforms(pan);
|
||||
let frame = self.build_frame(
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
pipelines,
|
||||
device_pixel_ratio,
|
||||
output_pipelines,
|
||||
texture_cache_profile,
|
||||
gpu_cache_profile,
|
||||
);
|
||||
frame
|
||||
}
|
||||
|
||||
fn build_frame(
|
||||
&mut self,
|
||||
resource_cache: &mut ResourceCache,
|
||||
gpu_cache: &mut GpuCache,
|
||||
pipelines: &FastHashMap<PipelineId, ScenePipeline>,
|
||||
device_pixel_ratio: f32,
|
||||
output_pipelines: &FastHashSet<PipelineId>,
|
||||
texture_cache_profile: &mut TextureCacheProfileCounters,
|
||||
gpu_cache_profile: &mut GpuCacheProfileCounters,
|
||||
) -> RendererFrame {
|
||||
let mut frame_builder = self.frame_builder.take();
|
||||
let frame = frame_builder.as_mut().map(|builder| {
|
||||
|
@ -1119,7 +1138,6 @@ impl Frame {
|
|||
&mut self.clip_scroll_tree,
|
||||
pipelines,
|
||||
device_pixel_ratio,
|
||||
pan,
|
||||
output_pipelines,
|
||||
texture_cache_profile,
|
||||
gpu_cache_profile,
|
||||
|
|
|
@ -3,42 +3,43 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::{BorderDetails, BorderDisplayItem, BorderRadius, BoxShadowClipMode, BuiltDisplayList};
|
||||
use api::{ComplexClipRegion, ClipAndScrollInfo, ClipId, ColorF};
|
||||
use api::{ClipAndScrollInfo, ClipId, ColorF};
|
||||
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect, DeviceUintSize};
|
||||
use api::{ExtendMode, FilterOp, FontInstance, FontRenderMode};
|
||||
use api::{ExtendMode, FIND_ALL, FilterOp, FontInstance, FontRenderMode};
|
||||
use api::{GlyphInstance, GlyphOptions, GradientStop, HitTestFlags, HitTestItem, HitTestResult};
|
||||
use api::{ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect};
|
||||
use api::{LayerPixel, LayerSize, LayerToScrollTransform, LayerVector2D, LayoutVector2D, LineOrientation};
|
||||
use api::{LineStyle, LocalClip, PipelineId, RepeatMode};
|
||||
use api::{LineStyle, LocalClip, POINT_RELATIVE_TO_PIPELINE_VIEWPORT, PipelineId, RepeatMode};
|
||||
use api::{ScrollSensitivity, Shadow, TileOffset, TransformStyle};
|
||||
use api::{WorldPixel, WorldPoint, YuvColorSpace, YuvData, device_length};
|
||||
use app_units::Au;
|
||||
use border::ImageBorderSegment;
|
||||
use clip::{ClipMode, ClipRegion, ClipSource, ClipSources, ClipStore, Contains};
|
||||
use clip_scroll_node::{ClipInfo, ClipScrollNode, NodeType};
|
||||
use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId};
|
||||
use euclid::{SideOffsets2D, TypedTransform3D, vec2, vec3};
|
||||
use clip_scroll_tree::ClipScrollTree;
|
||||
use euclid::{SideOffsets2D, vec2, vec3};
|
||||
use frame::FrameId;
|
||||
use gpu_cache::GpuCache;
|
||||
use internal_types::{FastHashMap, FastHashSet, HardwareCompositeOp};
|
||||
use picture::{PicturePrimitive};
|
||||
use picture::PicturePrimitive;
|
||||
use plane_split::{BspSplitter, Polygon, Splitter};
|
||||
use prim_store::{BrushPrimitive, TexelRect, YuvImagePrimitiveCpu};
|
||||
use prim_store::{BoxShadowPrimitiveCpu, TexelRect, YuvImagePrimitiveCpu};
|
||||
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, LinePrimitive, PrimitiveKind};
|
||||
use prim_store::{PrimitiveContainer, PrimitiveIndex};
|
||||
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu};
|
||||
use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu};
|
||||
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
|
||||
use render_task::{AlphaRenderItem, ClipChain, RenderTask, RenderTaskId, RenderTaskLocation};
|
||||
use render_task::RenderTaskTree;
|
||||
use render_task::{AlphaRenderItem, ClipWorkItem, RenderTask};
|
||||
use render_task::{RenderTaskId, RenderTaskLocation, RenderTaskTree};
|
||||
use resource_cache::ResourceCache;
|
||||
use scene::ScenePipeline;
|
||||
use std::{mem, usize, f32, i32};
|
||||
use tiling::{ClipScrollGroup, ClipScrollGroupIndex, CompositeOps, Frame};
|
||||
use tiling::{ContextIsolation, RenderTargetKind, StackingContextIndex};
|
||||
use tiling::{ContextIsolation, StackingContextIndex};
|
||||
use tiling::{PackedLayer, PackedLayerIndex, PrimitiveFlags, PrimitiveRunCmd, RenderPass};
|
||||
use tiling::{RenderTargetContext, ScrollbarPrimitive, StackingContext};
|
||||
use util::{self, pack_as_float, RectHelpers, recycle_vec};
|
||||
use util::{self, pack_as_float, recycle_vec, subtract_rect};
|
||||
use util::{MatrixHelpers, RectHelpers};
|
||||
|
||||
/// Construct a polygon from stacking context boundaries.
|
||||
/// `anchor` here is an index that's going to be preserved in all the
|
||||
|
@ -47,7 +48,7 @@ fn make_polygon(
|
|||
stacking_context: &StackingContext,
|
||||
node: &ClipScrollNode,
|
||||
anchor: usize,
|
||||
) -> Polygon<f64, WorldPixel> {
|
||||
) -> Polygon<f32, WorldPixel> {
|
||||
//TODO: only work with `isolated_items_bounds.size` worth of space
|
||||
// This can be achieved by moving the `origin` shift
|
||||
// from the primitive local coordinates into the layer transformation.
|
||||
|
@ -55,24 +56,7 @@ fn make_polygon(
|
|||
// upon rendering, possibly not limited to `write_*_vertex` implementations.
|
||||
let size = stacking_context.isolated_items_bounds.bottom_right();
|
||||
let bounds = LayerRect::new(LayerPoint::zero(), LayerSize::new(size.x, size.y));
|
||||
let mat = TypedTransform3D::row_major(
|
||||
node.world_content_transform.m11 as f64,
|
||||
node.world_content_transform.m12 as f64,
|
||||
node.world_content_transform.m13 as f64,
|
||||
node.world_content_transform.m14 as f64,
|
||||
node.world_content_transform.m21 as f64,
|
||||
node.world_content_transform.m22 as f64,
|
||||
node.world_content_transform.m23 as f64,
|
||||
node.world_content_transform.m24 as f64,
|
||||
node.world_content_transform.m31 as f64,
|
||||
node.world_content_transform.m32 as f64,
|
||||
node.world_content_transform.m33 as f64,
|
||||
node.world_content_transform.m34 as f64,
|
||||
node.world_content_transform.m41 as f64,
|
||||
node.world_content_transform.m42 as f64,
|
||||
node.world_content_transform.m43 as f64,
|
||||
node.world_content_transform.m44 as f64);
|
||||
Polygon::from_transformed_rect(bounds.cast().unwrap(), mat, anchor)
|
||||
Polygon::from_transformed_rect(bounds, node.world_content_transform, anchor)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -142,10 +126,15 @@ pub struct PrimitiveContext<'a> {
|
|||
pub packed_layer_index: PackedLayerIndex,
|
||||
pub packed_layer: &'a PackedLayer,
|
||||
pub device_pixel_ratio: f32,
|
||||
pub clip_chain: ClipChain,
|
||||
|
||||
// Clip items that apply for this primitive run.
|
||||
// In the future, we'll build these once at the
|
||||
// start of the frame when updating the
|
||||
// clip-scroll tree.
|
||||
pub current_clip_stack: Vec<ClipWorkItem>,
|
||||
pub clip_bounds: DeviceIntRect,
|
||||
pub clip_id: ClipId,
|
||||
pub coordinate_system_id: CoordinateSystemId,
|
||||
|
||||
pub display_list: &'a BuiltDisplayList,
|
||||
}
|
||||
|
||||
|
@ -154,22 +143,68 @@ impl<'a> PrimitiveContext<'a> {
|
|||
packed_layer_index: PackedLayerIndex,
|
||||
packed_layer: &'a PackedLayer,
|
||||
clip_id: ClipId,
|
||||
clip_chain: ClipChain,
|
||||
clip_bounds: DeviceIntRect,
|
||||
coordinate_system_id: CoordinateSystemId,
|
||||
screen_rect: &DeviceIntRect,
|
||||
clip_scroll_tree: &ClipScrollTree,
|
||||
clip_store: &ClipStore,
|
||||
device_pixel_ratio: f32,
|
||||
display_list: &'a BuiltDisplayList,
|
||||
) -> Self {
|
||||
PrimitiveContext {
|
||||
) -> Option<Self> {
|
||||
|
||||
let mut current_clip_stack = Vec::new();
|
||||
let mut clip_bounds = *screen_rect;
|
||||
let mut current_id = Some(clip_id);
|
||||
// Indicates if the next non-reference-frame that we encounter needs to have its
|
||||
// local combined clip rectangle backed into the clip mask.
|
||||
let mut next_node_needs_region_mask = false;
|
||||
while let Some(id) = current_id {
|
||||
let node = &clip_scroll_tree.nodes.get(&id).unwrap();
|
||||
current_id = node.parent;
|
||||
|
||||
let clip = match node.node_type {
|
||||
NodeType::ReferenceFrame(ref info) => {
|
||||
// if the transform is non-aligned, bake the next LCCR into the clip mask
|
||||
next_node_needs_region_mask |= !info.transform.preserves_2d_axis_alignment();
|
||||
continue;
|
||||
}
|
||||
NodeType::Clip(ref clip) => clip,
|
||||
NodeType::StickyFrame(..) | NodeType::ScrollFrame(..) => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let clip_sources = clip_store.get(&clip.clip_sources);
|
||||
if !clip_sources.is_masking() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// apply the outer device bounds of the clip stack
|
||||
if let Some(ref outer) = clip_sources.bounds.outer {
|
||||
clip_bounds = match clip_bounds.intersection(&outer.device_rect) {
|
||||
Some(rect) => rect,
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
|
||||
//TODO-LCCR: bake a single LCCR instead of all aligned rects?
|
||||
current_clip_stack.push(ClipWorkItem {
|
||||
layer_index: clip.packed_layer_index,
|
||||
clip_sources: clip.clip_sources.weak(),
|
||||
apply_rectangles: next_node_needs_region_mask,
|
||||
});
|
||||
next_node_needs_region_mask = false;
|
||||
}
|
||||
|
||||
current_clip_stack.reverse();
|
||||
|
||||
Some(PrimitiveContext {
|
||||
packed_layer_index,
|
||||
packed_layer,
|
||||
clip_chain,
|
||||
current_clip_stack,
|
||||
clip_bounds,
|
||||
coordinate_system_id,
|
||||
device_pixel_ratio,
|
||||
clip_id,
|
||||
display_list,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,7 +371,6 @@ impl FrameBuilder {
|
|||
clip_node_id: info.clip_node_id(),
|
||||
packed_layer_index,
|
||||
screen_bounding_rect: None,
|
||||
coordinate_system_id: CoordinateSystemId(0),
|
||||
});
|
||||
|
||||
group_id
|
||||
|
@ -557,7 +591,7 @@ impl FrameBuilder {
|
|||
clip_and_scroll: ClipAndScrollInfo,
|
||||
info: &LayerPrimitiveInfo,
|
||||
) {
|
||||
let prim = PicturePrimitive::new_shadow(shadow, RenderTargetKind::Color);
|
||||
let prim = PicturePrimitive::new_shadow(shadow);
|
||||
|
||||
// Create an empty shadow primitive. Insert it into
|
||||
// the draw lists immediately so that it will be drawn
|
||||
|
@ -1162,7 +1196,7 @@ impl FrameBuilder {
|
|||
font.variations.clone(),
|
||||
font.synthetic_italics,
|
||||
);
|
||||
let prim = TextRunPrimitiveCpu {
|
||||
let mut prim = TextRunPrimitiveCpu {
|
||||
font: prim_font,
|
||||
glyph_range,
|
||||
glyph_count,
|
||||
|
@ -1187,6 +1221,12 @@ impl FrameBuilder {
|
|||
if shadow.blur_radius == 0.0 {
|
||||
let mut text_prim = prim.clone();
|
||||
text_prim.font.color = shadow.color.into();
|
||||
// If we have translucent text, we need to ensure it won't go
|
||||
// through the subpixel blend mode, which doesn't work with
|
||||
// traditional alpha blending.
|
||||
if shadow.color.a != 1.0 {
|
||||
text_prim.font.render_mode = text_prim.font.render_mode.limit_by(FontRenderMode::Alpha);
|
||||
}
|
||||
text_prim.offset += shadow.offset;
|
||||
fast_shadow_prims.push((idx, text_prim));
|
||||
}
|
||||
|
@ -1205,6 +1245,12 @@ impl FrameBuilder {
|
|||
self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll));
|
||||
}
|
||||
|
||||
// We defer this until after fast-shadows so that shadows of transparent text
|
||||
// get subpixel-aa
|
||||
if color.a != 1.0 {
|
||||
prim.font.render_mode = FontRenderMode::Alpha;
|
||||
}
|
||||
|
||||
// Create (and add to primitive store) the primitive that will be
|
||||
// used for both the visual element and also the shadow(s).
|
||||
let prim_index = self.create_primitive(
|
||||
|
@ -1250,10 +1296,47 @@ impl FrameBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fill_box_shadow_rect(
|
||||
&mut self,
|
||||
clip_and_scroll: ClipAndScrollInfo,
|
||||
info: &LayerPrimitiveInfo,
|
||||
bs_rect: LayerRect,
|
||||
color: &ColorF,
|
||||
border_radius: f32,
|
||||
clip_mode: BoxShadowClipMode,
|
||||
) {
|
||||
// We can draw a rectangle instead with the proper border radius clipping.
|
||||
let (bs_clip_mode, rect_to_draw) = match clip_mode {
|
||||
BoxShadowClipMode::Outset | BoxShadowClipMode::None => (ClipMode::Clip, bs_rect),
|
||||
BoxShadowClipMode::Inset => (ClipMode::ClipOut, info.rect),
|
||||
};
|
||||
|
||||
let box_clip_mode = !bs_clip_mode;
|
||||
|
||||
// Clip the inside and then the outside of the box.
|
||||
let border_radius = BorderRadius::uniform(border_radius);
|
||||
let extra_clips = vec![
|
||||
ClipSource::RoundedRectangle(bs_rect, border_radius, bs_clip_mode),
|
||||
ClipSource::RoundedRectangle(info.rect, border_radius, box_clip_mode),
|
||||
];
|
||||
|
||||
let prim = RectanglePrimitive { color: *color };
|
||||
|
||||
let mut info = info.clone();
|
||||
info.rect = rect_to_draw;
|
||||
|
||||
self.add_primitive(
|
||||
clip_and_scroll,
|
||||
&info,
|
||||
extra_clips,
|
||||
PrimitiveContainer::Rectangle(prim),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn add_box_shadow(
|
||||
&mut self,
|
||||
clip_and_scroll: ClipAndScrollInfo,
|
||||
prim_info: &LayerPrimitiveInfo,
|
||||
info: &LayerPrimitiveInfo,
|
||||
box_offset: &LayerVector2D,
|
||||
color: &ColorF,
|
||||
blur_radius: f32,
|
||||
|
@ -1265,152 +1348,162 @@ impl FrameBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
let spread_amount = match clip_mode {
|
||||
BoxShadowClipMode::Outset => {
|
||||
spread_radius
|
||||
// The local space box shadow rect. It is the element rect
|
||||
// translated by the box shadow offset and inflated by the
|
||||
// box shadow spread.
|
||||
let inflate_amount = match clip_mode {
|
||||
BoxShadowClipMode::Outset | BoxShadowClipMode::None => spread_radius,
|
||||
BoxShadowClipMode::Inset => -spread_radius,
|
||||
};
|
||||
|
||||
let bs_rect = info.rect
|
||||
.translate(box_offset)
|
||||
.inflate(inflate_amount, inflate_amount);
|
||||
// If we have negative inflate amounts.
|
||||
// Have to explicitly check this since euclid::TypedRect relies on negative rects
|
||||
let bs_rect_empty = bs_rect.size.width <= 0.0 || bs_rect.size.height <= 0.0;
|
||||
|
||||
// Just draw a rectangle
|
||||
if (blur_radius == 0.0 && spread_radius == 0.0 && clip_mode == BoxShadowClipMode::None) ||
|
||||
bs_rect_empty
|
||||
{
|
||||
self.add_solid_rectangle(clip_and_scroll, info, color, PrimitiveFlags::None);
|
||||
return;
|
||||
}
|
||||
|
||||
if blur_radius == 0.0 && border_radius != 0.0 {
|
||||
self.fill_box_shadow_rect(
|
||||
clip_and_scroll,
|
||||
info,
|
||||
bs_rect,
|
||||
color,
|
||||
border_radius,
|
||||
clip_mode,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the outer rectangle, based on the blur radius.
|
||||
let outside_edge_size = 2.0 * blur_radius;
|
||||
let inside_edge_size = outside_edge_size.max(border_radius);
|
||||
let edge_size = outside_edge_size + inside_edge_size;
|
||||
let outer_rect = bs_rect.inflate(outside_edge_size, outside_edge_size);
|
||||
|
||||
// Box shadows are often used for things like text underline and other
|
||||
// simple primitives, so we want to draw these simple cases with the
|
||||
// solid rectangle shader wherever possible, to avoid invoking the
|
||||
// expensive box-shadow shader.
|
||||
enum BoxShadowKind {
|
||||
Simple(Vec<LayerRect>), // Can be drawn via simple rectangles only
|
||||
Shadow(Vec<LayerRect>), // Requires the full box-shadow code path
|
||||
}
|
||||
|
||||
let shadow_kind = match clip_mode {
|
||||
BoxShadowClipMode::Outset | BoxShadowClipMode::None => {
|
||||
// If a border radius is set, we need to draw inside
|
||||
// the original box in order to draw where the border
|
||||
// corners are. A clip-out mask applied below will
|
||||
// ensure that we don't draw on the box itself.
|
||||
let inner_box_bounds = info.rect.inflate(-border_radius, -border_radius);
|
||||
// For outset shadows, subtracting the element rectangle
|
||||
// from the outer rectangle gives the rectangles we need
|
||||
// to draw. In the simple case (no blur radius), we can
|
||||
// just draw these as solid colors.
|
||||
let mut rects = Vec::new();
|
||||
subtract_rect(&outer_rect, &inner_box_bounds, &mut rects);
|
||||
if edge_size == 0.0 {
|
||||
BoxShadowKind::Simple(rects)
|
||||
} else {
|
||||
BoxShadowKind::Shadow(rects)
|
||||
}
|
||||
}
|
||||
BoxShadowClipMode::Inset => {
|
||||
-spread_radius
|
||||
// For inset shadows, in the simple case (no blur) we
|
||||
// can draw the shadow area by subtracting the box
|
||||
// shadow rect from the element rect (since inset box
|
||||
// shadows never extend past the element rect). However,
|
||||
// in the case of an inset box shadow with blur, we
|
||||
// currently just draw the box shadow over the entire
|
||||
// rect. The opaque parts of the shadow (past the outside
|
||||
// edge of the box-shadow) are handled by the shadow
|
||||
// shader.
|
||||
// TODO(gw): We should be able to optimize the complex
|
||||
// inset shadow case to touch fewer pixels. We
|
||||
// can probably calculate the inner rect that
|
||||
// can't be affected, and subtract that from
|
||||
// the element rect?
|
||||
let mut rects = Vec::new();
|
||||
if edge_size == 0.0 {
|
||||
subtract_rect(&info.rect, &bs_rect, &mut rects);
|
||||
BoxShadowKind::Simple(rects)
|
||||
} else {
|
||||
rects.push(info.rect);
|
||||
BoxShadowKind::Shadow(rects)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Adjust the shadow box radius as per:
|
||||
// https://drafts.csswg.org/css-backgrounds-3/#shadow-shape
|
||||
let sharpness_scale = if border_radius < spread_radius {
|
||||
let r = border_radius / spread_amount;
|
||||
1.0 + (r - 1.0) * (r - 1.0) * (r - 1.0)
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
let shadow_radius = (border_radius + spread_amount * sharpness_scale).max(0.0);
|
||||
let shadow_rect = prim_info.rect
|
||||
.translate(box_offset)
|
||||
.inflate(spread_amount, spread_amount);
|
||||
match shadow_kind {
|
||||
BoxShadowKind::Simple(rects) => for rect in &rects {
|
||||
let mut info = info.clone();
|
||||
info.rect = *rect;
|
||||
self.add_solid_rectangle(clip_and_scroll, &info, color, PrimitiveFlags::None)
|
||||
},
|
||||
BoxShadowKind::Shadow(rects) => {
|
||||
assert!(blur_radius > 0.0);
|
||||
if clip_mode == BoxShadowClipMode::Inset {
|
||||
self.fill_box_shadow_rect(
|
||||
clip_and_scroll,
|
||||
info,
|
||||
bs_rect,
|
||||
color,
|
||||
border_radius,
|
||||
clip_mode,
|
||||
);
|
||||
}
|
||||
|
||||
if blur_radius == 0.0 {
|
||||
let mut clips = Vec::new();
|
||||
let inverted = match clip_mode {
|
||||
BoxShadowClipMode::Outset | BoxShadowClipMode::None => 0.0,
|
||||
BoxShadowClipMode::Inset => 1.0,
|
||||
};
|
||||
|
||||
let fast_info = match clip_mode {
|
||||
BoxShadowClipMode::Outset => {
|
||||
// TODO(gw): Add a fast path for ClipOut + zero border radius!
|
||||
clips.push(ClipSource::RoundedRectangle(
|
||||
prim_info.rect,
|
||||
// Outset box shadows with border radius
|
||||
// need a clip out of the center box.
|
||||
let extra_clip_mode = match clip_mode {
|
||||
BoxShadowClipMode::Outset | BoxShadowClipMode::None => ClipMode::ClipOut,
|
||||
BoxShadowClipMode::Inset => ClipMode::Clip,
|
||||
};
|
||||
|
||||
let mut extra_clips = Vec::new();
|
||||
if border_radius >= 0.0 {
|
||||
extra_clips.push(ClipSource::RoundedRectangle(
|
||||
info.rect,
|
||||
BorderRadius::uniform(border_radius),
|
||||
ClipMode::ClipOut
|
||||
extra_clip_mode,
|
||||
));
|
||||
|
||||
LayerPrimitiveInfo::with_clip(
|
||||
shadow_rect,
|
||||
LocalClip::RoundedRect(
|
||||
shadow_rect,
|
||||
ComplexClipRegion::new(shadow_rect, BorderRadius::uniform(shadow_radius)),
|
||||
),
|
||||
)
|
||||
}
|
||||
BoxShadowClipMode::Inset => {
|
||||
clips.push(ClipSource::RoundedRectangle(
|
||||
shadow_rect,
|
||||
BorderRadius::uniform(shadow_radius),
|
||||
ClipMode::ClipOut
|
||||
));
|
||||
|
||||
LayerPrimitiveInfo::with_clip(
|
||||
prim_info.rect,
|
||||
LocalClip::RoundedRect(
|
||||
prim_info.rect,
|
||||
ComplexClipRegion::new(prim_info.rect, BorderRadius::uniform(border_radius)),
|
||||
),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
self.add_primitive(
|
||||
clip_and_scroll,
|
||||
&fast_info,
|
||||
clips,
|
||||
PrimitiveContainer::Rectangle(RectanglePrimitive {
|
||||
let prim_cpu = BoxShadowPrimitiveCpu {
|
||||
src_rect: info.rect,
|
||||
bs_rect,
|
||||
color: *color,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
let shadow = Shadow {
|
||||
blur_radius,
|
||||
color: *color,
|
||||
offset: LayerVector2D::zero(),
|
||||
};
|
||||
blur_radius,
|
||||
border_radius,
|
||||
edge_size,
|
||||
inverted,
|
||||
rects,
|
||||
render_task_id: None,
|
||||
};
|
||||
|
||||
let blur_offset = 2.0 * blur_radius;
|
||||
let mut extra_clips = vec![];
|
||||
let mut pic_prim = PicturePrimitive::new_shadow(shadow, RenderTargetKind::Alpha);
|
||||
|
||||
let pic_info = match clip_mode {
|
||||
BoxShadowClipMode::Outset => {
|
||||
let brush_prim = BrushPrimitive {
|
||||
clip_mode: ClipMode::Clip,
|
||||
radius: shadow_radius,
|
||||
};
|
||||
|
||||
let brush_rect = LayerRect::new(LayerPoint::new(blur_offset, blur_offset),
|
||||
shadow_rect.size);
|
||||
|
||||
let brush_info = LayerPrimitiveInfo::new(brush_rect);
|
||||
|
||||
let brush_prim_index = self.create_primitive(
|
||||
clip_and_scroll,
|
||||
&brush_info,
|
||||
Vec::new(),
|
||||
PrimitiveContainer::Brush(brush_prim),
|
||||
);
|
||||
|
||||
pic_prim.add_primitive(brush_prim_index, clip_and_scroll);
|
||||
|
||||
extra_clips.push(ClipSource::RoundedRectangle(
|
||||
prim_info.rect,
|
||||
BorderRadius::uniform(border_radius),
|
||||
ClipMode::ClipOut,
|
||||
));
|
||||
|
||||
let pic_rect = shadow_rect.inflate(blur_offset, blur_offset);
|
||||
LayerPrimitiveInfo::new(pic_rect)
|
||||
}
|
||||
BoxShadowClipMode::Inset => {
|
||||
let brush_prim = BrushPrimitive {
|
||||
clip_mode: ClipMode::ClipOut,
|
||||
radius: shadow_radius,
|
||||
};
|
||||
|
||||
let mut brush_rect = shadow_rect;
|
||||
brush_rect.origin.x = brush_rect.origin.x - prim_info.rect.origin.x + blur_offset;
|
||||
brush_rect.origin.y = brush_rect.origin.y - prim_info.rect.origin.y + blur_offset;
|
||||
|
||||
let brush_info = LayerPrimitiveInfo::new(brush_rect);
|
||||
|
||||
let brush_prim_index = self.create_primitive(
|
||||
clip_and_scroll,
|
||||
&brush_info,
|
||||
Vec::new(),
|
||||
PrimitiveContainer::Brush(brush_prim),
|
||||
);
|
||||
|
||||
pic_prim.add_primitive(brush_prim_index, clip_and_scroll);
|
||||
|
||||
extra_clips.push(ClipSource::RoundedRectangle(
|
||||
prim_info.rect,
|
||||
BorderRadius::uniform(border_radius),
|
||||
ClipMode::Clip,
|
||||
));
|
||||
|
||||
let pic_rect = prim_info.rect.inflate(blur_offset, blur_offset);
|
||||
LayerPrimitiveInfo::with_clip_rect(pic_rect, prim_info.rect)
|
||||
}
|
||||
};
|
||||
|
||||
self.add_primitive(
|
||||
clip_and_scroll,
|
||||
&pic_info,
|
||||
extra_clips,
|
||||
PrimitiveContainer::Picture(pic_prim),
|
||||
);
|
||||
let mut info = info.clone();
|
||||
info.rect = outer_rect;
|
||||
self.add_primitive(
|
||||
clip_and_scroll,
|
||||
&info,
|
||||
extra_clips,
|
||||
PrimitiveContainer::BoxShadow(prim_cpu),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1516,7 +1609,7 @@ impl FrameBuilder {
|
|||
point: WorldPoint,
|
||||
flags: HitTestFlags
|
||||
) -> HitTestResult {
|
||||
let point = if flags.contains(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT) {
|
||||
let point = if flags.contains(POINT_RELATIVE_TO_PIPELINE_VIEWPORT) {
|
||||
let point = LayerPoint::new(point.x, point.y);
|
||||
clip_scroll_tree.make_node_relative_point_absolute(pipeline_id, &point)
|
||||
} else {
|
||||
|
@ -1566,9 +1659,8 @@ impl FrameBuilder {
|
|||
pipeline: clip_and_scroll.clip_node_id().pipeline_id(),
|
||||
tag: item.tag,
|
||||
point_in_viewport,
|
||||
point_relative_to_item: point_in_layer - item.rect.origin.to_vector(),
|
||||
});
|
||||
if !flags.contains(HitTestFlags::FIND_ALL) {
|
||||
if !flags.contains(FIND_ALL) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1589,6 +1681,7 @@ impl FrameBuilder {
|
|||
resource_cache: &mut ResourceCache,
|
||||
pipelines: &FastHashMap<PipelineId, ScenePipeline>,
|
||||
clip_scroll_tree: &ClipScrollTree,
|
||||
screen_rect: &DeviceIntRect,
|
||||
device_pixel_ratio: f32,
|
||||
profile_counters: &mut FrameProfileCounters,
|
||||
) -> bool {
|
||||
|
@ -1602,27 +1695,9 @@ impl FrameBuilder {
|
|||
}
|
||||
};
|
||||
|
||||
let (clip_chain, clip_bounds, coordinate_system_id) =
|
||||
match clip_scroll_tree.nodes.get(&clip_and_scroll.clip_node_id()) {
|
||||
Some(node) if node.combined_clip_outer_bounds != DeviceIntRect::zero() => {
|
||||
let group_id = self.clip_scroll_group_indices[&clip_and_scroll];
|
||||
(
|
||||
node.clip_chain_node.clone(),
|
||||
node.combined_clip_outer_bounds,
|
||||
self.clip_scroll_group_store[group_id].coordinate_system_id,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let group_id = self.clip_scroll_group_indices[&clip_and_scroll];
|
||||
self.clip_scroll_group_store[group_id].screen_bounding_rect = None;
|
||||
|
||||
debug!("{:?} of clipped out {:?}", base_prim_index, stacking_context_index);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
let stacking_context = &mut self.stacking_context_store[stacking_context_index.0];
|
||||
let pipeline_id = {
|
||||
let stacking_context =
|
||||
&mut self.stacking_context_store[stacking_context_index.0];
|
||||
if !stacking_context.can_contribute_to_scene() {
|
||||
return false;
|
||||
}
|
||||
|
@ -1640,6 +1715,8 @@ impl FrameBuilder {
|
|||
packed_layer_index
|
||||
);
|
||||
|
||||
let stacking_context =
|
||||
&mut self.stacking_context_store[stacking_context_index.0];
|
||||
let packed_layer = &self.packed_layers[packed_layer_index.0];
|
||||
let display_list = &pipelines
|
||||
.get(&pipeline_id)
|
||||
|
@ -1654,13 +1731,22 @@ impl FrameBuilder {
|
|||
packed_layer_index,
|
||||
packed_layer,
|
||||
clip_and_scroll.clip_node_id(),
|
||||
clip_chain,
|
||||
clip_bounds,
|
||||
coordinate_system_id,
|
||||
screen_rect,
|
||||
clip_scroll_tree,
|
||||
&self.clip_store,
|
||||
device_pixel_ratio,
|
||||
display_list,
|
||||
);
|
||||
|
||||
let prim_context = match prim_context {
|
||||
Some(prim_context) => prim_context,
|
||||
None => {
|
||||
let group_id = self.clip_scroll_group_indices[&clip_and_scroll];
|
||||
self.clip_scroll_group_store[group_id].screen_bounding_rect = None;
|
||||
return false
|
||||
},
|
||||
};
|
||||
|
||||
debug!(
|
||||
"\tclip_bounds {:?}, layer_local_clip {:?}",
|
||||
prim_context.clip_bounds,
|
||||
|
@ -1750,6 +1836,52 @@ impl FrameBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
fn recalculate_clip_scroll_nodes(
|
||||
&mut self,
|
||||
clip_scroll_tree: &mut ClipScrollTree,
|
||||
gpu_cache: &mut GpuCache,
|
||||
resource_cache: &mut ResourceCache,
|
||||
screen_rect: &DeviceIntRect,
|
||||
device_pixel_ratio: f32
|
||||
) {
|
||||
for (_, ref mut node) in clip_scroll_tree.nodes.iter_mut() {
|
||||
let node_clip_info = match node.node_type {
|
||||
NodeType::Clip(ref mut clip_info) => clip_info,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let packed_layer_index = node_clip_info.packed_layer_index;
|
||||
let packed_layer = &mut self.packed_layers[packed_layer_index.0];
|
||||
|
||||
// The coordinates of the mask are relative to the origin of the node itself,
|
||||
// so we need to account for that origin in the transformation we assign to
|
||||
// the packed layer.
|
||||
let transform = node.world_viewport_transform
|
||||
.pre_translate(node.local_viewport_rect.origin.to_vector().to_3d());
|
||||
|
||||
if packed_layer.set_transform(transform) {
|
||||
// Meanwhile, the combined viewport rect is relative to the reference frame, so
|
||||
// we move it into the local coordinate system of the node.
|
||||
let local_viewport_rect = node.combined_local_viewport_rect
|
||||
.translate(&-node.local_viewport_rect.origin.to_vector());
|
||||
|
||||
packed_layer.set_rect(
|
||||
&local_viewport_rect,
|
||||
screen_rect,
|
||||
device_pixel_ratio,
|
||||
);
|
||||
}
|
||||
|
||||
let clip_sources = self.clip_store.get_mut(&node_clip_info.clip_sources);
|
||||
clip_sources.update(
|
||||
&transform,
|
||||
gpu_cache,
|
||||
resource_cache,
|
||||
device_pixel_ratio,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn recalculate_clip_scroll_groups(
|
||||
&mut self,
|
||||
clip_scroll_tree: &ClipScrollTree,
|
||||
|
@ -1788,8 +1920,6 @@ impl FrameBuilder {
|
|||
device_pixel_ratio,
|
||||
);
|
||||
|
||||
group.coordinate_system_id = scroll_node.coordinate_system_id;
|
||||
|
||||
debug!(
|
||||
"\t\tlocal viewport {:?} screen bound {:?}",
|
||||
local_viewport_rect,
|
||||
|
@ -1813,6 +1943,13 @@ impl FrameBuilder {
|
|||
) {
|
||||
profile_scope!("cull");
|
||||
|
||||
self.recalculate_clip_scroll_nodes(
|
||||
clip_scroll_tree,
|
||||
gpu_cache,
|
||||
resource_cache,
|
||||
screen_rect,
|
||||
device_pixel_ratio
|
||||
);
|
||||
self.recalculate_clip_scroll_groups(
|
||||
clip_scroll_tree,
|
||||
screen_rect,
|
||||
|
@ -1836,6 +1973,7 @@ impl FrameBuilder {
|
|||
resource_cache,
|
||||
pipelines,
|
||||
clip_scroll_tree,
|
||||
screen_rect,
|
||||
device_pixel_ratio,
|
||||
profile_counters,
|
||||
);
|
||||
|
@ -2038,13 +2176,10 @@ impl FrameBuilder {
|
|||
match *filter {
|
||||
FilterOp::Blur(blur_radius) => {
|
||||
let blur_radius = device_length(blur_radius, device_pixel_ratio);
|
||||
render_tasks.get_mut(current_task_id)
|
||||
.inflate(blur_radius.0);
|
||||
let blur_render_task = RenderTask::new_blur(
|
||||
blur_radius,
|
||||
current_task_id,
|
||||
render_tasks,
|
||||
RenderTargetKind::Color,
|
||||
);
|
||||
let blur_render_task_id = render_tasks.add(blur_render_task);
|
||||
let item = AlphaRenderItem::HardwareComposite(
|
||||
|
@ -2128,9 +2263,9 @@ impl FrameBuilder {
|
|||
debug!("\t\tproduce {:?} -> {:?} for {:?}", sc_index, poly, task_id);
|
||||
let pp = &poly.points;
|
||||
let gpu_blocks = [
|
||||
[pp[0].x as f32, pp[0].y as f32, pp[0].z as f32, pp[1].x as f32].into(),
|
||||
[pp[1].y as f32, pp[1].z as f32, pp[2].x as f32, pp[2].y as f32].into(),
|
||||
[pp[2].z as f32, pp[3].x as f32, pp[3].y as f32, pp[3].z as f32].into(),
|
||||
[pp[0].x, pp[0].y, pp[0].z, pp[1].x].into(),
|
||||
[pp[1].y, pp[1].z, pp[2].x, pp[2].y].into(),
|
||||
[pp[2].z, pp[3].x, pp[3].y, pp[3].z].into(),
|
||||
];
|
||||
let handle = gpu_cache.push_per_frame_blocks(&gpu_blocks);
|
||||
let item =
|
||||
|
@ -2208,7 +2343,6 @@ impl FrameBuilder {
|
|||
clip_scroll_tree: &mut ClipScrollTree,
|
||||
pipelines: &FastHashMap<PipelineId, ScenePipeline>,
|
||||
device_pixel_ratio: f32,
|
||||
pan: LayerPoint,
|
||||
output_pipelines: &FastHashSet<PipelineId>,
|
||||
texture_cache_profile: &mut TextureCacheProfileCounters,
|
||||
gpu_cache_profile: &mut GpuCacheProfileCounters,
|
||||
|
@ -2231,16 +2365,6 @@ impl FrameBuilder {
|
|||
),
|
||||
);
|
||||
|
||||
clip_scroll_tree.update_all_node_transforms(
|
||||
&screen_rect,
|
||||
device_pixel_ratio,
|
||||
&mut self.packed_layers,
|
||||
&mut self.clip_store,
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
pan
|
||||
);
|
||||
|
||||
self.update_scroll_bars(clip_scroll_tree, gpu_cache);
|
||||
|
||||
let mut render_tasks = RenderTaskTree::new();
|
||||
|
|
|
@ -188,7 +188,7 @@ impl GlyphRasterizer {
|
|||
for key in glyph_keys {
|
||||
match glyph_key_cache.entry(key.clone()) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
if let Ok(Some(ref mut glyph_info)) = *entry.get_mut() {
|
||||
if let Some(ref mut glyph_info) = *entry.get_mut() {
|
||||
if texture_cache.request(&mut glyph_info.texture_cache_handle, gpu_cache) {
|
||||
// This case gets hit when we have already rasterized
|
||||
// the glyph and stored it in CPU memory, the the glyph
|
||||
|
@ -352,7 +352,7 @@ impl GlyphRasterizer {
|
|||
|
||||
let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font_mut(job.request.font);
|
||||
|
||||
glyph_key_cache.insert(job.request.key, Ok(glyph_info));
|
||||
glyph_key_cache.insert(job.request.key, glyph_info);
|
||||
}
|
||||
|
||||
// Now that we are done with the critical path (rendering the glyphs),
|
||||
|
|
|
@ -17,6 +17,14 @@ impl From<PackedLayerIndex> for PackedLayerAddress {
|
|||
}
|
||||
}
|
||||
|
||||
// Instance structure for box shadows being drawn into target cache.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct BoxShadowCacheInstance {
|
||||
pub prim_address: GpuCacheAddress,
|
||||
pub task_index: RenderTaskAddress,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum BlurDirection {
|
||||
|
@ -137,38 +145,3 @@ impl From<CompositePrimitiveInstance> for PrimitiveInstance {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct BrushInstance {
|
||||
picture_address: RenderTaskAddress,
|
||||
prim_address: GpuCacheAddress,
|
||||
}
|
||||
|
||||
impl BrushInstance {
|
||||
pub fn new(
|
||||
picture_address: RenderTaskAddress,
|
||||
prim_address: GpuCacheAddress
|
||||
) -> BrushInstance {
|
||||
BrushInstance {
|
||||
picture_address,
|
||||
prim_address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BrushInstance> for PrimitiveInstance {
|
||||
fn from(instance: BrushInstance) -> PrimitiveInstance {
|
||||
PrimitiveInstance {
|
||||
data: [
|
||||
instance.picture_address.0 as i32,
|
||||
instance.prim_address.as_int(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ extern crate gamma_lut;
|
|||
|
||||
#[doc(hidden)]
|
||||
pub use device::build_shader_strings;
|
||||
pub use renderer::{ALPHA_PRIM_DBG, PROFILER_DBG, RENDER_TARGET_DBG, TEXTURE_CACHE_DBG};
|
||||
pub use renderer::{CpuProfile, DebugFlags, GpuProfile, OutputImageHandler, RendererKind};
|
||||
pub use renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
|
||||
pub use renderer::{GraphicsApi, GraphicsApiInfo, ReadPixelsFormat, Renderer, RendererOptions};
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
use api::{ClipAndScrollInfo, Shadow};
|
||||
use prim_store::PrimitiveIndex;
|
||||
use render_task::RenderTaskId;
|
||||
use tiling::RenderTargetKind;
|
||||
|
||||
/*
|
||||
A picture represents a dynamically rendered image. It consists of:
|
||||
|
@ -37,7 +36,6 @@ pub struct PicturePrimitive {
|
|||
pub prim_runs: Vec<PrimitiveRun>,
|
||||
pub composite_op: CompositeOp,
|
||||
pub render_task_id: Option<RenderTaskId>,
|
||||
pub kind: RenderTargetKind,
|
||||
|
||||
// TODO(gw): Add a mode that specifies if this
|
||||
// picture should be rasterized in
|
||||
|
@ -45,15 +43,11 @@ pub struct PicturePrimitive {
|
|||
}
|
||||
|
||||
impl PicturePrimitive {
|
||||
pub fn new_shadow(
|
||||
shadow: Shadow,
|
||||
kind: RenderTargetKind,
|
||||
) -> PicturePrimitive {
|
||||
pub fn new_shadow(shadow: Shadow) -> PicturePrimitive {
|
||||
PicturePrimitive {
|
||||
prim_runs: Vec::new(),
|
||||
composite_op: CompositeOp::Shadow(shadow),
|
||||
render_task_id: None,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -278,6 +278,12 @@ impl FontContext {
|
|||
) -> Option<GlyphDimensions> {
|
||||
let metrics = unsafe { &(*slot).metrics };
|
||||
|
||||
// If there's no advance, no need to consider this glyph
|
||||
// for layout.
|
||||
if metrics.horiAdvance == 0 {
|
||||
return None
|
||||
}
|
||||
|
||||
let advance = metrics.horiAdvance as f32 / 64.0;
|
||||
match unsafe { (*slot).format } {
|
||||
FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
|
||||
|
|
|
@ -7,17 +7,18 @@ use api::{DevicePoint, ExtendMode, FontInstance, FontRenderMode, GlyphInstance,
|
|||
use api::{GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerRect};
|
||||
use api::{LayerSize, LayerVector2D, LineOrientation, LineStyle};
|
||||
use api::{TileOffset, YuvColorSpace, YuvFormat, device_length};
|
||||
use app_units::Au;
|
||||
use border::BorderCornerInstance;
|
||||
use clip::{ClipMode, ClipSourcesHandle, ClipStore, Geometry};
|
||||
use euclid::Size2D;
|
||||
use frame_builder::PrimitiveContext;
|
||||
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
|
||||
ToGpuBlocks};
|
||||
use picture::PicturePrimitive;
|
||||
use render_task::{ClipWorkItem, ClipChainNode, RenderTask, RenderTaskId, RenderTaskTree};
|
||||
use render_task::{ClipWorkItem, RenderTask, RenderTaskId, RenderTaskTree};
|
||||
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
|
||||
use resource_cache::{ImageProperties, ResourceCache};
|
||||
use std::{mem, usize};
|
||||
use std::rc::Rc;
|
||||
use util::{MatrixHelpers, pack_as_float, recycle_vec, TransformedRect};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -109,9 +110,9 @@ pub enum PrimitiveKind {
|
|||
AlignedGradient,
|
||||
AngleGradient,
|
||||
RadialGradient,
|
||||
BoxShadow,
|
||||
Line,
|
||||
Picture,
|
||||
Brush,
|
||||
}
|
||||
|
||||
impl GpuCacheHandle {
|
||||
|
@ -164,23 +165,6 @@ impl ToGpuBlocks for RectanglePrimitive {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BrushPrimitive {
|
||||
pub clip_mode: ClipMode,
|
||||
pub radius: f32,
|
||||
}
|
||||
|
||||
impl ToGpuBlocks for BrushPrimitive {
|
||||
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
|
||||
request.push([
|
||||
self.clip_mode as u32 as f32,
|
||||
self.radius,
|
||||
0.0,
|
||||
0.0
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct LinePrimitive {
|
||||
|
@ -247,6 +231,46 @@ impl ToGpuBlocks for BorderPrimitiveCpu {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct BoxShadowPrimitiveCacheKey {
|
||||
pub shadow_rect_size: Size2D<Au>,
|
||||
pub border_radius: Au,
|
||||
pub blur_radius: Au,
|
||||
pub inverted: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BoxShadowPrimitiveCpu {
|
||||
// todo(gw): generate on demand
|
||||
// gpu data
|
||||
pub src_rect: LayerRect,
|
||||
pub bs_rect: LayerRect,
|
||||
pub color: ColorF,
|
||||
pub border_radius: f32,
|
||||
pub edge_size: f32,
|
||||
pub blur_radius: f32,
|
||||
pub inverted: f32,
|
||||
pub rects: Vec<LayerRect>,
|
||||
pub render_task_id: Option<RenderTaskId>,
|
||||
}
|
||||
|
||||
impl ToGpuBlocks for BoxShadowPrimitiveCpu {
|
||||
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
|
||||
request.push(self.src_rect);
|
||||
request.push(self.bs_rect);
|
||||
request.push(self.color);
|
||||
request.push([
|
||||
self.border_radius,
|
||||
self.edge_size,
|
||||
self.blur_radius,
|
||||
self.inverted,
|
||||
]);
|
||||
for &rect in &self.rects {
|
||||
request.push(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GradientPrimitiveCpu {
|
||||
pub stops_range: ItemRange<GradientStop>,
|
||||
|
@ -780,15 +804,14 @@ pub enum PrimitiveContainer {
|
|||
AlignedGradient(GradientPrimitiveCpu),
|
||||
AngleGradient(GradientPrimitiveCpu),
|
||||
RadialGradient(RadialGradientPrimitiveCpu),
|
||||
BoxShadow(BoxShadowPrimitiveCpu),
|
||||
Picture(PicturePrimitive),
|
||||
Line(LinePrimitive),
|
||||
Brush(BrushPrimitive),
|
||||
}
|
||||
|
||||
pub struct PrimitiveStore {
|
||||
/// CPU side information only.
|
||||
pub cpu_rectangles: Vec<RectanglePrimitive>,
|
||||
pub cpu_brushes: Vec<BrushPrimitive>,
|
||||
pub cpu_text_runs: Vec<TextRunPrimitiveCpu>,
|
||||
pub cpu_pictures: Vec<PicturePrimitive>,
|
||||
pub cpu_images: Vec<ImagePrimitiveCpu>,
|
||||
|
@ -797,6 +820,7 @@ pub struct PrimitiveStore {
|
|||
pub cpu_radial_gradients: Vec<RadialGradientPrimitiveCpu>,
|
||||
pub cpu_metadata: Vec<PrimitiveMetadata>,
|
||||
pub cpu_borders: Vec<BorderPrimitiveCpu>,
|
||||
pub cpu_box_shadows: Vec<BoxShadowPrimitiveCpu>,
|
||||
pub cpu_lines: Vec<LinePrimitive>,
|
||||
}
|
||||
|
||||
|
@ -805,7 +829,6 @@ impl PrimitiveStore {
|
|||
PrimitiveStore {
|
||||
cpu_metadata: Vec::new(),
|
||||
cpu_rectangles: Vec::new(),
|
||||
cpu_brushes: Vec::new(),
|
||||
cpu_text_runs: Vec::new(),
|
||||
cpu_pictures: Vec::new(),
|
||||
cpu_images: Vec::new(),
|
||||
|
@ -813,6 +836,7 @@ impl PrimitiveStore {
|
|||
cpu_gradients: Vec::new(),
|
||||
cpu_radial_gradients: Vec::new(),
|
||||
cpu_borders: Vec::new(),
|
||||
cpu_box_shadows: Vec::new(),
|
||||
cpu_lines: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
@ -821,7 +845,6 @@ impl PrimitiveStore {
|
|||
PrimitiveStore {
|
||||
cpu_metadata: recycle_vec(self.cpu_metadata),
|
||||
cpu_rectangles: recycle_vec(self.cpu_rectangles),
|
||||
cpu_brushes: recycle_vec(self.cpu_brushes),
|
||||
cpu_text_runs: recycle_vec(self.cpu_text_runs),
|
||||
cpu_pictures: recycle_vec(self.cpu_pictures),
|
||||
cpu_images: recycle_vec(self.cpu_images),
|
||||
|
@ -829,6 +852,7 @@ impl PrimitiveStore {
|
|||
cpu_gradients: recycle_vec(self.cpu_gradients),
|
||||
cpu_radial_gradients: recycle_vec(self.cpu_radial_gradients),
|
||||
cpu_borders: recycle_vec(self.cpu_borders),
|
||||
cpu_box_shadows: recycle_vec(self.cpu_box_shadows),
|
||||
cpu_lines: recycle_vec(self.cpu_lines),
|
||||
}
|
||||
}
|
||||
|
@ -872,18 +896,6 @@ impl PrimitiveStore {
|
|||
|
||||
metadata
|
||||
}
|
||||
PrimitiveContainer::Brush(brush) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
prim_kind: PrimitiveKind::Brush,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_brushes.len()),
|
||||
..base_metadata
|
||||
};
|
||||
|
||||
self.cpu_brushes.push(brush);
|
||||
|
||||
metadata
|
||||
}
|
||||
PrimitiveContainer::Line(line) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
|
@ -985,6 +997,17 @@ impl PrimitiveStore {
|
|||
self.cpu_radial_gradients.push(radial_gradient_cpu);
|
||||
metadata
|
||||
}
|
||||
PrimitiveContainer::BoxShadow(box_shadow) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
prim_kind: PrimitiveKind::BoxShadow,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_box_shadows.len()),
|
||||
..base_metadata
|
||||
};
|
||||
|
||||
self.cpu_box_shadows.push(box_shadow);
|
||||
metadata
|
||||
}
|
||||
};
|
||||
|
||||
self.cpu_metadata.push(metadata);
|
||||
|
@ -1006,6 +1029,10 @@ impl PrimitiveStore {
|
|||
let metadata = &self.cpu_metadata[prim_index.0];
|
||||
|
||||
let render_task_id = match metadata.prim_kind {
|
||||
PrimitiveKind::BoxShadow => {
|
||||
let box_shadow = &self.cpu_box_shadows[metadata.cpu_prim_index.0];
|
||||
box_shadow.render_task_id
|
||||
}
|
||||
PrimitiveKind::Picture => {
|
||||
let picture = &self.cpu_pictures[metadata.cpu_prim_index.0];
|
||||
picture.render_task_id
|
||||
|
@ -1018,8 +1045,7 @@ impl PrimitiveStore {
|
|||
PrimitiveKind::Border |
|
||||
PrimitiveKind::AngleGradient |
|
||||
PrimitiveKind::RadialGradient |
|
||||
PrimitiveKind::Line |
|
||||
PrimitiveKind::Brush => None,
|
||||
PrimitiveKind::Line => None,
|
||||
};
|
||||
|
||||
if let Some(render_task_id) = render_task_id {
|
||||
|
@ -1031,6 +1057,7 @@ impl PrimitiveStore {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the bounding box needs to be updated.
|
||||
fn prepare_prim_for_render_inner(
|
||||
&mut self,
|
||||
prim_index: PrimitiveIndex,
|
||||
|
@ -1046,6 +1073,45 @@ impl PrimitiveStore {
|
|||
let metadata = &mut self.cpu_metadata[prim_index.0];
|
||||
match metadata.prim_kind {
|
||||
PrimitiveKind::Rectangle | PrimitiveKind::Border | PrimitiveKind::Line => {}
|
||||
PrimitiveKind::BoxShadow => {
|
||||
// TODO(gw): Account for zoom factor!
|
||||
// Here, we calculate the size of the patch required in order
|
||||
// to create the box shadow corner. First, scale it by the
|
||||
// device pixel ratio since the cache shader expects vertices
|
||||
// in device space. The shader adds a 1-pixel border around
|
||||
// the patch, in order to prevent bilinear filter artifacts as
|
||||
// the patch is clamped / mirrored across the box shadow rect.
|
||||
let box_shadow = &mut self.cpu_box_shadows[metadata.cpu_prim_index.0];
|
||||
let edge_size = box_shadow.edge_size.ceil() * prim_context.device_pixel_ratio;
|
||||
let edge_size = edge_size as i32 + 2; // Account for bilinear filtering
|
||||
let cache_size = DeviceIntSize::new(edge_size, edge_size);
|
||||
|
||||
let cache_key = BoxShadowPrimitiveCacheKey {
|
||||
blur_radius: Au::from_f32_px(box_shadow.blur_radius),
|
||||
border_radius: Au::from_f32_px(box_shadow.border_radius),
|
||||
inverted: box_shadow.inverted != 0.0,
|
||||
shadow_rect_size: Size2D::new(
|
||||
Au::from_f32_px(box_shadow.bs_rect.size.width),
|
||||
Au::from_f32_px(box_shadow.bs_rect.size.height),
|
||||
),
|
||||
};
|
||||
|
||||
// Create a render task for this box shadow primitive. This renders a small
|
||||
// portion of the box shadow to a render target. That portion is then
|
||||
// stretched over the actual primitive rect by the box shadow primitive
|
||||
// shader, to reduce the number of pixels that the expensive box
|
||||
// shadow shader needs to run on.
|
||||
// TODO(gw): In the future, we can probably merge the box shadow
|
||||
// primitive (stretch) shader with the generic cached primitive shader.
|
||||
let render_task = RenderTask::new_box_shadow(
|
||||
cache_key,
|
||||
cache_size,
|
||||
prim_index
|
||||
);
|
||||
|
||||
// ignore the new task if we are in a dependency context
|
||||
box_shadow.render_task_id = render_tasks.map(|rt| rt.add(render_task));
|
||||
}
|
||||
PrimitiveKind::Picture => {
|
||||
let picture = &mut self.cpu_pictures[metadata.cpu_prim_index.0];
|
||||
|
||||
|
@ -1063,18 +1129,10 @@ impl PrimitiveStore {
|
|||
|
||||
// ignore new tasks if we are in a dependency context
|
||||
picture.render_task_id = render_tasks.map(|rt| {
|
||||
let picture_task = RenderTask::new_picture(
|
||||
cache_size,
|
||||
prim_index,
|
||||
picture.kind,
|
||||
);
|
||||
let picture_task = RenderTask::new_picture(cache_size, prim_index);
|
||||
let picture_task_id = rt.add(picture_task);
|
||||
let render_task = RenderTask::new_blur(
|
||||
blur_radius,
|
||||
picture_task_id,
|
||||
rt,
|
||||
picture.kind
|
||||
);
|
||||
let render_task =
|
||||
RenderTask::new_blur(blur_radius, picture_task_id, rt);
|
||||
rt.add(render_task)
|
||||
});
|
||||
}
|
||||
|
@ -1126,8 +1184,7 @@ impl PrimitiveStore {
|
|||
}
|
||||
PrimitiveKind::AlignedGradient |
|
||||
PrimitiveKind::AngleGradient |
|
||||
PrimitiveKind::RadialGradient |
|
||||
PrimitiveKind::Brush => {}
|
||||
PrimitiveKind::RadialGradient => {}
|
||||
}
|
||||
|
||||
// Mark this GPU resource as required for this frame.
|
||||
|
@ -1148,6 +1205,10 @@ impl PrimitiveStore {
|
|||
let border = &self.cpu_borders[metadata.cpu_prim_index.0];
|
||||
border.write_gpu_blocks(request);
|
||||
}
|
||||
PrimitiveKind::BoxShadow => {
|
||||
let box_shadow = &self.cpu_box_shadows[metadata.cpu_prim_index.0];
|
||||
box_shadow.write_gpu_blocks(request);
|
||||
}
|
||||
PrimitiveKind::Image => {
|
||||
let image = &self.cpu_images[metadata.cpu_prim_index.0];
|
||||
image.write_gpu_blocks(request);
|
||||
|
@ -1183,10 +1244,6 @@ impl PrimitiveStore {
|
|||
0.0,
|
||||
]);
|
||||
}
|
||||
PrimitiveKind::Brush => {
|
||||
let brush = &self.cpu_brushes[metadata.cpu_prim_index.0];
|
||||
brush.write_gpu_blocks(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1226,26 +1283,22 @@ impl PrimitiveStore {
|
|||
_ => prim_screen_rect,
|
||||
};
|
||||
|
||||
let extra_clip = Some(Rc::new(ClipChainNode {
|
||||
work_item: ClipWorkItem {
|
||||
layer_index: prim_context.packed_layer_index,
|
||||
clip_sources: metadata.clip_sources.weak(),
|
||||
coordinate_system_id: prim_context.coordinate_system_id,
|
||||
},
|
||||
prev: None,
|
||||
}));
|
||||
let extra = ClipWorkItem {
|
||||
layer_index: prim_context.packed_layer_index,
|
||||
clip_sources: metadata.clip_sources.weak(),
|
||||
apply_rectangles: false,
|
||||
};
|
||||
|
||||
RenderTask::new_mask(
|
||||
None,
|
||||
mask_rect,
|
||||
prim_context.clip_chain.clone(),
|
||||
extra_clip,
|
||||
&prim_context.current_clip_stack,
|
||||
Some(extra),
|
||||
prim_screen_rect,
|
||||
clip_store,
|
||||
is_axis_aligned,
|
||||
prim_context.coordinate_system_id,
|
||||
)
|
||||
} else if prim_context.clip_chain.is_some() {
|
||||
} else if !prim_context.current_clip_stack.is_empty() {
|
||||
// If the primitive doesn't have a specific clip, key the task ID off the
|
||||
// stacking context. This means that two primitives which are only clipped
|
||||
// by the stacking context stack can share clip masks during render task
|
||||
|
@ -1253,12 +1306,11 @@ impl PrimitiveStore {
|
|||
RenderTask::new_mask(
|
||||
Some(prim_context.clip_id),
|
||||
prim_context.clip_bounds,
|
||||
prim_context.clip_chain.clone(),
|
||||
&prim_context.current_clip_stack,
|
||||
None,
|
||||
prim_screen_rect,
|
||||
clip_store,
|
||||
is_axis_aligned,
|
||||
prim_context.coordinate_system_id,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
|
@ -1268,6 +1320,7 @@ impl PrimitiveStore {
|
|||
true
|
||||
}
|
||||
|
||||
/// Returns true if the bounding box needs to be updated.
|
||||
pub fn prepare_prim_for_render(
|
||||
&mut self,
|
||||
prim_index: PrimitiveIndex,
|
||||
|
|
|
@ -103,7 +103,7 @@ impl Document {
|
|||
self.pan.x as f32 / accumulated_scale_factor,
|
||||
self.pan.y as f32 / accumulated_scale_factor,
|
||||
);
|
||||
self.frame.build_renderer_frame(
|
||||
self.frame.build(
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
&self.scene.pipelines,
|
||||
|
@ -297,17 +297,6 @@ impl RenderBackend {
|
|||
|
||||
DocumentOp::Built
|
||||
}
|
||||
DocumentMsg::UpdatePipelineResources { resources, pipeline_id, epoch } => {
|
||||
profile_scope!("UpdateResources");
|
||||
|
||||
self.resource_cache
|
||||
.update_resources(resources, &mut profile_counters.resources);
|
||||
|
||||
doc.scene.update_epoch(pipeline_id, epoch);
|
||||
doc.frame.update_epoch(pipeline_id, epoch);
|
||||
|
||||
DocumentOp::Nop
|
||||
}
|
||||
DocumentMsg::SetRootPipeline(pipeline_id) => {
|
||||
profile_scope!("SetRootPipeline");
|
||||
|
||||
|
|
|
@ -6,12 +6,10 @@ use api::{ClipId, DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize}
|
|||
use api::{FilterOp, MixBlendMode};
|
||||
use api::PipelineId;
|
||||
use clip::{ClipSource, ClipSourcesWeakHandle, ClipStore};
|
||||
use clip_scroll_tree::CoordinateSystemId;
|
||||
use gpu_cache::GpuCacheHandle;
|
||||
use internal_types::HardwareCompositeOp;
|
||||
use prim_store::PrimitiveIndex;
|
||||
use prim_store::{BoxShadowPrimitiveCacheKey, PrimitiveIndex};
|
||||
use std::{cmp, usize, f32, i32};
|
||||
use std::rc::Rc;
|
||||
use tiling::{ClipScrollGroupIndex, PackedLayerIndex, RenderPass, RenderTargetIndex};
|
||||
use tiling::{RenderTargetKind, StackingContextIndex};
|
||||
|
||||
|
@ -30,31 +28,6 @@ pub struct RenderTaskTree {
|
|||
pub task_data: Vec<RenderTaskData>,
|
||||
}
|
||||
|
||||
pub type ClipChain = Option<Rc<ClipChainNode>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ClipChainNode {
|
||||
pub work_item: ClipWorkItem,
|
||||
pub prev: ClipChain,
|
||||
}
|
||||
|
||||
struct ClipChainNodeIter {
|
||||
current: ClipChain,
|
||||
}
|
||||
|
||||
impl Iterator for ClipChainNodeIter {
|
||||
type Item = Rc<ClipChainNode>;
|
||||
|
||||
fn next(&mut self) -> ClipChain {
|
||||
let previous = self.current.clone();
|
||||
self.current = match self.current {
|
||||
Some(ref item) => item.prev.clone(),
|
||||
None => return None,
|
||||
};
|
||||
previous
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderTaskTree {
|
||||
pub fn new() -> RenderTaskTree {
|
||||
RenderTaskTree {
|
||||
|
@ -139,6 +112,8 @@ impl RenderTaskTree {
|
|||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum RenderTaskKey {
|
||||
/// Draw this box shadow to a cache target.
|
||||
BoxShadow(BoxShadowPrimitiveCacheKey),
|
||||
/// Draw the alpha mask for a shared clip.
|
||||
CacheMask(ClipId),
|
||||
}
|
||||
|
@ -202,15 +177,11 @@ pub enum MaskGeometryKind {
|
|||
pub struct ClipWorkItem {
|
||||
pub layer_index: PackedLayerIndex,
|
||||
pub clip_sources: ClipSourcesWeakHandle,
|
||||
pub coordinate_system_id: CoordinateSystemId,
|
||||
pub apply_rectangles: bool,
|
||||
}
|
||||
|
||||
impl ClipWorkItem {
|
||||
fn get_geometry_kind(
|
||||
&self,
|
||||
clip_store: &ClipStore,
|
||||
prim_coordinate_system_id: CoordinateSystemId
|
||||
) -> MaskGeometryKind {
|
||||
fn get_geometry_kind(&self, clip_store: &ClipStore) -> MaskGeometryKind {
|
||||
let clips = clip_store
|
||||
.get_opt(&self.clip_sources)
|
||||
.expect("bug: clip handle should be valid")
|
||||
|
@ -219,10 +190,8 @@ impl ClipWorkItem {
|
|||
|
||||
for &(ref clip, _) in clips {
|
||||
match *clip {
|
||||
ClipSource::Rectangle(..) => {
|
||||
if self.has_compatible_coordinate_system(prim_coordinate_system_id) {
|
||||
return MaskGeometryKind::Default;
|
||||
}
|
||||
ClipSource::Rectangle(..) => if self.apply_rectangles {
|
||||
return MaskGeometryKind::Default;
|
||||
},
|
||||
ClipSource::RoundedRectangle(..) => {
|
||||
rounded_rect_count += 1;
|
||||
|
@ -239,10 +208,6 @@ impl ClipWorkItem {
|
|||
MaskGeometryKind::Default
|
||||
}
|
||||
}
|
||||
|
||||
fn has_compatible_coordinate_system(&self, other_id: CoordinateSystemId) -> bool {
|
||||
self.coordinate_system_id == other_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -251,19 +216,6 @@ pub struct CacheMaskTask {
|
|||
inner_rect: DeviceIntRect,
|
||||
pub clips: Vec<ClipWorkItem>,
|
||||
pub geometry_kind: MaskGeometryKind,
|
||||
pub coordinate_system_id: CoordinateSystemId,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PictureTask {
|
||||
pub prim_index: PrimitiveIndex,
|
||||
pub target_kind: RenderTargetKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlurTask {
|
||||
pub blur_radius: DeviceIntLength,
|
||||
pub target_kind: RenderTargetKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -274,10 +226,11 @@ pub struct RenderTaskData {
|
|||
#[derive(Debug)]
|
||||
pub enum RenderTaskKind {
|
||||
Alpha(AlphaRenderTask),
|
||||
Picture(PictureTask),
|
||||
Picture(PrimitiveIndex),
|
||||
BoxShadow(PrimitiveIndex),
|
||||
CacheMask(CacheMaskTask),
|
||||
VerticalBlur(BlurTask),
|
||||
HorizontalBlur(BlurTask),
|
||||
VerticalBlur(DeviceIntLength),
|
||||
HorizontalBlur(DeviceIntLength),
|
||||
Readback(DeviceIntRect),
|
||||
Alias(RenderTaskId),
|
||||
}
|
||||
|
@ -316,19 +269,25 @@ impl RenderTask {
|
|||
Self::new_alpha_batch(rect.origin, location, frame_output_pipeline_id)
|
||||
}
|
||||
|
||||
pub fn new_picture(
|
||||
size: DeviceIntSize,
|
||||
prim_index: PrimitiveIndex,
|
||||
target_kind: RenderTargetKind,
|
||||
) -> RenderTask {
|
||||
pub fn new_picture(size: DeviceIntSize, prim_index: PrimitiveIndex) -> RenderTask {
|
||||
RenderTask {
|
||||
cache_key: None,
|
||||
children: Vec::new(),
|
||||
location: RenderTaskLocation::Dynamic(None, size),
|
||||
kind: RenderTaskKind::Picture(PictureTask {
|
||||
prim_index,
|
||||
target_kind,
|
||||
}),
|
||||
kind: RenderTaskKind::Picture(prim_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_box_shadow(
|
||||
key: BoxShadowPrimitiveCacheKey,
|
||||
size: DeviceIntSize,
|
||||
prim_index: PrimitiveIndex,
|
||||
) -> RenderTask {
|
||||
RenderTask {
|
||||
cache_key: Some(RenderTaskKey::BoxShadow(key)),
|
||||
children: Vec::new(),
|
||||
location: RenderTaskLocation::Dynamic(None, size),
|
||||
kind: RenderTaskKind::BoxShadow(prim_index),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,46 +303,46 @@ impl RenderTask {
|
|||
pub fn new_mask(
|
||||
key: Option<ClipId>,
|
||||
task_rect: DeviceIntRect,
|
||||
raw_clips: ClipChain,
|
||||
extra_clip: ClipChain,
|
||||
raw_clips: &[ClipWorkItem],
|
||||
extra_clip: Option<ClipWorkItem>,
|
||||
prim_rect: DeviceIntRect,
|
||||
clip_store: &ClipStore,
|
||||
is_axis_aligned: bool,
|
||||
prim_coordinate_system_id: CoordinateSystemId,
|
||||
) -> Option<RenderTask> {
|
||||
// Filter out all the clip instances that don't contribute to the result
|
||||
let mut current_coordinate_system_id = prim_coordinate_system_id;
|
||||
let mut inner_rect = Some(task_rect);
|
||||
let clips: Vec<_> = ClipChainNodeIter { current: raw_clips }
|
||||
.chain(ClipChainNodeIter { current: extra_clip })
|
||||
.filter_map(|node| {
|
||||
let work_item = node.work_item.clone();
|
||||
|
||||
// FIXME(1828): This is a workaround until we can fix the inconsistency between
|
||||
// the shader and the CPU code around how inner_rects are handled.
|
||||
if !node.work_item.has_compatible_coordinate_system(current_coordinate_system_id) {
|
||||
current_coordinate_system_id = node.work_item.coordinate_system_id;
|
||||
inner_rect = None;
|
||||
return Some(work_item)
|
||||
}
|
||||
|
||||
let clips: Vec<_> = raw_clips
|
||||
.iter()
|
||||
.chain(extra_clip.iter())
|
||||
.filter(|work_item| {
|
||||
let clip_info = clip_store
|
||||
.get_opt(&node.work_item.clip_sources)
|
||||
.get_opt(&work_item.clip_sources)
|
||||
.expect("bug: clip item should exist");
|
||||
debug_assert!(clip_info.is_masking());
|
||||
|
||||
// If this clip does not contribute to a mask, then ensure
|
||||
// it gets filtered out here. Otherwise, if a mask is
|
||||
// created (by a different clip in the list), the allocated
|
||||
// rectangle for the mask could end up being much bigger
|
||||
// than is actually required.
|
||||
if !clip_info.is_masking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
match clip_info.bounds.inner {
|
||||
Some(ref inner) if !inner.device_rect.is_empty() => {
|
||||
// Inner rects aren't valid if the item is not axis-aligned, which can
|
||||
// be determined by the apply_rectangles field. This is mostly a band-aid
|
||||
// until we have better handling of inner rectangles for transformed clips.
|
||||
Some(ref inner) if !work_item.apply_rectangles && !inner.device_rect.is_empty() => {
|
||||
inner_rect = inner_rect.and_then(|r| r.intersection(&inner.device_rect));
|
||||
if inner.device_rect.contains_rect(&task_rect) {
|
||||
return None;
|
||||
}
|
||||
!inner.device_rect.contains_rect(&task_rect)
|
||||
}
|
||||
_ => {
|
||||
inner_rect = None;
|
||||
true
|
||||
}
|
||||
_ => inner_rect = None,
|
||||
}
|
||||
|
||||
Some(work_item)
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
// Nothing to do, all clips are irrelevant for this case
|
||||
|
@ -391,7 +350,6 @@ impl RenderTask {
|
|||
return None;
|
||||
}
|
||||
|
||||
|
||||
// TODO(gw): This optimization is very conservative for now.
|
||||
// For now, only draw optimized geometry if it is
|
||||
// a single aligned rect mask with rounded corners.
|
||||
|
@ -405,7 +363,7 @@ impl RenderTask {
|
|||
return None;
|
||||
}
|
||||
if is_axis_aligned && clips.len() == 1 {
|
||||
geometry_kind = clips[0].get_geometry_kind(clip_store, prim_coordinate_system_id);
|
||||
geometry_kind = clips[0].get_geometry_kind(clip_store);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,7 +376,6 @@ impl RenderTask {
|
|||
inner_rect: inner_rect.unwrap_or(DeviceIntRect::zero()),
|
||||
clips,
|
||||
geometry_kind,
|
||||
coordinate_system_id: prim_coordinate_system_id,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
@ -442,18 +399,16 @@ impl RenderTask {
|
|||
blur_radius: DeviceIntLength,
|
||||
src_task_id: RenderTaskId,
|
||||
render_tasks: &mut RenderTaskTree,
|
||||
target_kind: RenderTargetKind,
|
||||
) -> RenderTask {
|
||||
let blur_target_size = render_tasks.get(src_task_id).get_dynamic_size();
|
||||
let src_size = render_tasks.get(src_task_id).get_dynamic_size();
|
||||
|
||||
let blur_target_size = src_size + DeviceIntSize::new(2 * blur_radius.0, 2 * blur_radius.0);
|
||||
|
||||
let blur_task_v = RenderTask {
|
||||
cache_key: None,
|
||||
children: vec![src_task_id],
|
||||
location: RenderTaskLocation::Dynamic(None, blur_target_size),
|
||||
kind: RenderTaskKind::VerticalBlur(BlurTask {
|
||||
blur_radius,
|
||||
target_kind,
|
||||
}),
|
||||
kind: RenderTaskKind::VerticalBlur(blur_radius),
|
||||
};
|
||||
|
||||
let blur_task_v_id = render_tasks.add(blur_task_v);
|
||||
|
@ -462,10 +417,7 @@ impl RenderTask {
|
|||
cache_key: None,
|
||||
children: vec![blur_task_v_id],
|
||||
location: RenderTaskLocation::Dynamic(None, blur_target_size),
|
||||
kind: RenderTaskKind::HorizontalBlur(BlurTask {
|
||||
blur_radius,
|
||||
target_kind,
|
||||
}),
|
||||
kind: RenderTaskKind::HorizontalBlur(blur_radius),
|
||||
};
|
||||
|
||||
blur_task_h
|
||||
|
@ -475,6 +427,7 @@ impl RenderTask {
|
|||
match self.kind {
|
||||
RenderTaskKind::Alpha(ref mut task) => task,
|
||||
RenderTaskKind::Picture(..) |
|
||||
RenderTaskKind::BoxShadow(..) |
|
||||
RenderTaskKind::CacheMask(..) |
|
||||
RenderTaskKind::VerticalBlur(..) |
|
||||
RenderTaskKind::Readback(..) |
|
||||
|
@ -487,6 +440,7 @@ impl RenderTask {
|
|||
match self.kind {
|
||||
RenderTaskKind::Alpha(ref task) => task,
|
||||
RenderTaskKind::Picture(..) |
|
||||
RenderTaskKind::BoxShadow(..) |
|
||||
RenderTaskKind::CacheMask(..) |
|
||||
RenderTaskKind::VerticalBlur(..) |
|
||||
RenderTaskKind::Readback(..) |
|
||||
|
@ -527,7 +481,7 @@ impl RenderTask {
|
|||
],
|
||||
}
|
||||
}
|
||||
RenderTaskKind::Picture(..) => {
|
||||
RenderTaskKind::Picture(..) | RenderTaskKind::BoxShadow(..) => {
|
||||
let (target_rect, target_index) = self.get_target_rect();
|
||||
RenderTaskData {
|
||||
data: [
|
||||
|
@ -565,8 +519,8 @@ impl RenderTask {
|
|||
],
|
||||
}
|
||||
}
|
||||
RenderTaskKind::VerticalBlur(ref task_info) |
|
||||
RenderTaskKind::HorizontalBlur(ref task_info) => {
|
||||
RenderTaskKind::VerticalBlur(blur_radius) |
|
||||
RenderTaskKind::HorizontalBlur(blur_radius) => {
|
||||
let (target_rect, target_index) = self.get_target_rect();
|
||||
RenderTaskData {
|
||||
data: [
|
||||
|
@ -575,7 +529,7 @@ impl RenderTask {
|
|||
target_rect.size.width as f32,
|
||||
target_rect.size.height as f32,
|
||||
target_index.0 as f32,
|
||||
task_info.blur_radius.0 as f32,
|
||||
blur_radius.0 as f32,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
|
@ -608,33 +562,6 @@ impl RenderTask {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn inflate(&mut self, device_radius: i32) {
|
||||
match self.kind {
|
||||
RenderTaskKind::Alpha(ref mut info) => {
|
||||
match self.location {
|
||||
RenderTaskLocation::Fixed => {
|
||||
panic!("bug: inflate only supported for dynamic tasks");
|
||||
}
|
||||
RenderTaskLocation::Dynamic(_, ref mut size) => {
|
||||
size.width += device_radius * 2;
|
||||
size.height += device_radius * 2;
|
||||
info.screen_origin.x -= device_radius;
|
||||
info.screen_origin.y -= device_radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RenderTaskKind::Readback(..) |
|
||||
RenderTaskKind::CacheMask(..) |
|
||||
RenderTaskKind::VerticalBlur(..) |
|
||||
RenderTaskKind::HorizontalBlur(..) |
|
||||
RenderTaskKind::Picture(..) |
|
||||
RenderTaskKind::Alias(..) => {
|
||||
panic!("bug: inflate only supported for alpha tasks");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_dynamic_size(&self) -> DeviceIntSize {
|
||||
match self.location {
|
||||
RenderTaskLocation::Fixed => DeviceIntSize::zero(),
|
||||
|
@ -656,21 +583,15 @@ impl RenderTask {
|
|||
pub fn target_kind(&self) -> RenderTargetKind {
|
||||
match self.kind {
|
||||
RenderTaskKind::Alpha(..) |
|
||||
RenderTaskKind::Readback(..) => RenderTargetKind::Color,
|
||||
RenderTaskKind::Picture(..) |
|
||||
RenderTaskKind::VerticalBlur(..) |
|
||||
RenderTaskKind::Readback(..) |
|
||||
RenderTaskKind::HorizontalBlur(..) => RenderTargetKind::Color,
|
||||
|
||||
RenderTaskKind::CacheMask(..) => {
|
||||
RenderTaskKind::CacheMask(..) | RenderTaskKind::BoxShadow(..) => {
|
||||
RenderTargetKind::Alpha
|
||||
}
|
||||
|
||||
RenderTaskKind::VerticalBlur(ref task_info) |
|
||||
RenderTaskKind::HorizontalBlur(ref task_info) => {
|
||||
task_info.target_kind
|
||||
}
|
||||
|
||||
RenderTaskKind::Picture(ref task_info) => {
|
||||
task_info.target_kind
|
||||
}
|
||||
|
||||
RenderTaskKind::Alias(..) => {
|
||||
panic!("BUG: target_kind() called on invalidated task");
|
||||
}
|
||||
|
@ -691,7 +612,7 @@ impl RenderTask {
|
|||
RenderTaskKind::Readback(..) |
|
||||
RenderTaskKind::HorizontalBlur(..) => false,
|
||||
|
||||
RenderTaskKind::CacheMask(..) => true,
|
||||
RenderTaskKind::CacheMask(..) | RenderTaskKind::BoxShadow(..) => true,
|
||||
|
||||
RenderTaskKind::Alias(..) => {
|
||||
panic!("BUG: is_shared() called on aliased task");
|
||||
|
|
|
@ -67,8 +67,8 @@ use util::TransformedRectKind;
|
|||
|
||||
pub const MAX_VERTEX_TEXTURE_WIDTH: usize = 1024;
|
||||
|
||||
const GPU_TAG_BRUSH_MASK: GpuProfileTag = GpuProfileTag {
|
||||
label: "B_Mask",
|
||||
const GPU_TAG_CACHE_BOX_SHADOW: GpuProfileTag = GpuProfileTag {
|
||||
label: "C_BoxShadow",
|
||||
color: debug_colors::BLACK,
|
||||
};
|
||||
const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag {
|
||||
|
@ -139,6 +139,10 @@ const GPU_TAG_PRIM_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag {
|
|||
label: "RadialGradient",
|
||||
color: debug_colors::LIGHTPINK,
|
||||
};
|
||||
const GPU_TAG_PRIM_BOX_SHADOW: GpuProfileTag = GpuProfileTag {
|
||||
label: "BoxShadow",
|
||||
color: debug_colors::CYAN,
|
||||
};
|
||||
const GPU_TAG_PRIM_BORDER_CORNER: GpuProfileTag = GpuProfileTag {
|
||||
label: "BorderCorner",
|
||||
color: debug_colors::DARKSLATEGREY,
|
||||
|
@ -190,7 +194,8 @@ impl BatchKind {
|
|||
TransformBatchKind::AlignedGradient => "AlignedGradient",
|
||||
TransformBatchKind::AngleGradient => "AngleGradient",
|
||||
TransformBatchKind::RadialGradient => "RadialGradient",
|
||||
TransformBatchKind::CacheImage(..) => "CacheImage",
|
||||
TransformBatchKind::BoxShadow => "BoxShadow",
|
||||
TransformBatchKind::CacheImage => "CacheImage",
|
||||
TransformBatchKind::BorderCorner => "BorderCorner",
|
||||
TransformBatchKind::BorderEdge => "BorderEdge",
|
||||
TransformBatchKind::Line => "Line",
|
||||
|
@ -360,11 +365,35 @@ const DESC_CLIP: VertexDescriptor = VertexDescriptor {
|
|||
],
|
||||
};
|
||||
|
||||
const DESC_CACHE_BOX_SHADOW: VertexDescriptor = VertexDescriptor {
|
||||
vertex_attributes: &[
|
||||
VertexAttribute {
|
||||
name: "aPosition",
|
||||
count: 2,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
],
|
||||
instance_attributes: &[
|
||||
VertexAttribute {
|
||||
name: "aPrimAddress",
|
||||
count: 2,
|
||||
kind: VertexAttributeKind::U16,
|
||||
},
|
||||
VertexAttribute {
|
||||
name: "aTaskIndex",
|
||||
count: 1,
|
||||
kind: VertexAttributeKind::I32,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum VertexArrayKind {
|
||||
Primitive,
|
||||
Blur,
|
||||
Clip,
|
||||
|
||||
CacheBoxShadow,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -835,7 +864,6 @@ enum ShaderKind {
|
|||
Primitive,
|
||||
Cache(VertexArrayKind),
|
||||
ClipCache,
|
||||
Brush,
|
||||
}
|
||||
|
||||
struct LazilyCompiledShader {
|
||||
|
@ -889,7 +917,7 @@ impl LazilyCompiledShader {
|
|||
if self.program.is_none() {
|
||||
let program = try!{
|
||||
match self.kind {
|
||||
ShaderKind::Primitive | ShaderKind::Brush => {
|
||||
ShaderKind::Primitive => {
|
||||
create_prim_shader(self.name,
|
||||
device,
|
||||
&self.features,
|
||||
|
@ -1016,6 +1044,7 @@ fn create_prim_shader(
|
|||
VertexArrayKind::Primitive => DESC_PRIM_INSTANCES,
|
||||
VertexArrayKind::Blur => DESC_BLUR,
|
||||
VertexArrayKind::Clip => DESC_CLIP,
|
||||
VertexArrayKind::CacheBoxShadow => DESC_CACHE_BOX_SHADOW,
|
||||
};
|
||||
|
||||
let program = device.create_program(name, &prefix, &vertex_descriptor);
|
||||
|
@ -1093,11 +1122,10 @@ pub struct Renderer {
|
|||
// These are "cache shaders". These shaders are used to
|
||||
// draw intermediate results to cache targets. The results
|
||||
// of these shaders are then used by the primitive shaders.
|
||||
cs_box_shadow: LazilyCompiledShader,
|
||||
cs_text_run: LazilyCompiledShader,
|
||||
cs_line: LazilyCompiledShader,
|
||||
cs_blur_a8: LazilyCompiledShader,
|
||||
cs_blur_rgba8: LazilyCompiledShader,
|
||||
brush_mask: LazilyCompiledShader,
|
||||
cs_blur: LazilyCompiledShader,
|
||||
|
||||
/// These are "cache clip shaders". These shaders are used to
|
||||
/// draw clip instances into the cached clip mask. The results
|
||||
|
@ -1123,8 +1151,8 @@ pub struct Renderer {
|
|||
ps_gradient: PrimitiveShader,
|
||||
ps_angle_gradient: PrimitiveShader,
|
||||
ps_radial_gradient: PrimitiveShader,
|
||||
ps_cache_image_rgba8: PrimitiveShader,
|
||||
ps_cache_image_a8: PrimitiveShader,
|
||||
ps_box_shadow: PrimitiveShader,
|
||||
ps_cache_image: PrimitiveShader,
|
||||
ps_line: PrimitiveShader,
|
||||
|
||||
ps_blend: LazilyCompiledShader,
|
||||
|
@ -1155,6 +1183,7 @@ pub struct Renderer {
|
|||
prim_vao: VAO,
|
||||
blur_vao: VAO,
|
||||
clip_vao: VAO,
|
||||
box_shadow_vao: VAO,
|
||||
|
||||
layer_texture: VertexDataTexture,
|
||||
render_task_texture: VertexDataTexture,
|
||||
|
@ -1275,6 +1304,14 @@ impl Renderer {
|
|||
// device-pixel ratio doesn't matter here - we are just creating resources.
|
||||
device.begin_frame(1.0);
|
||||
|
||||
let cs_box_shadow = try!{
|
||||
LazilyCompiledShader::new(ShaderKind::Cache(VertexArrayKind::CacheBoxShadow),
|
||||
"cs_box_shadow",
|
||||
&[],
|
||||
&mut device,
|
||||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let cs_text_run = try!{
|
||||
LazilyCompiledShader::new(ShaderKind::Cache(VertexArrayKind::Primitive),
|
||||
"cs_text_run",
|
||||
|
@ -1291,30 +1328,14 @@ impl Renderer {
|
|||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let brush_mask = try!{
|
||||
LazilyCompiledShader::new(ShaderKind::Brush,
|
||||
"brush_mask",
|
||||
let cs_blur = try!{
|
||||
LazilyCompiledShader::new(ShaderKind::Cache(VertexArrayKind::Blur),
|
||||
"cs_blur",
|
||||
&[],
|
||||
&mut device,
|
||||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let cs_blur_a8 = try!{
|
||||
LazilyCompiledShader::new(ShaderKind::Cache(VertexArrayKind::Blur),
|
||||
"cs_blur",
|
||||
&["ALPHA"],
|
||||
&mut device,
|
||||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let cs_blur_rgba8 = try!{
|
||||
LazilyCompiledShader::new(ShaderKind::Cache(VertexArrayKind::Blur),
|
||||
"cs_blur",
|
||||
&["COLOR"],
|
||||
&mut device,
|
||||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let cs_clip_rectangle = try!{
|
||||
LazilyCompiledShader::new(ShaderKind::ClipCache,
|
||||
"cs_clip_rectangle",
|
||||
|
@ -1449,6 +1470,13 @@ impl Renderer {
|
|||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let ps_box_shadow = try!{
|
||||
PrimitiveShader::new("ps_box_shadow",
|
||||
&mut device,
|
||||
&[],
|
||||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let dithering_feature = ["DITHERING"];
|
||||
|
||||
let ps_gradient = try!{
|
||||
|
@ -1484,17 +1512,10 @@ impl Renderer {
|
|||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let ps_cache_image_a8 = try!{
|
||||
let ps_cache_image = try!{
|
||||
PrimitiveShader::new("ps_cache_image",
|
||||
&mut device,
|
||||
&["ALPHA"],
|
||||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let ps_cache_image_rgba8 = try!{
|
||||
PrimitiveShader::new("ps_cache_image",
|
||||
&mut device,
|
||||
&["COLOR"],
|
||||
&[],
|
||||
options.precache_shaders)
|
||||
};
|
||||
|
||||
|
@ -1642,6 +1663,8 @@ impl Renderer {
|
|||
|
||||
let blur_vao = device.create_vao_with_new_instances(&DESC_BLUR, &prim_vao);
|
||||
let clip_vao = device.create_vao_with_new_instances(&DESC_CLIP, &prim_vao);
|
||||
let box_shadow_vao =
|
||||
device.create_vao_with_new_instances(&DESC_CACHE_BOX_SHADOW, &prim_vao);
|
||||
|
||||
let texture_cache_upload_pbo = device.create_pbo();
|
||||
|
||||
|
@ -1710,11 +1733,10 @@ impl Renderer {
|
|||
pending_texture_updates: Vec::new(),
|
||||
pending_gpu_cache_updates: Vec::new(),
|
||||
pending_shader_updates: Vec::new(),
|
||||
cs_box_shadow,
|
||||
cs_text_run,
|
||||
cs_line,
|
||||
cs_blur_a8,
|
||||
cs_blur_rgba8,
|
||||
brush_mask,
|
||||
cs_blur,
|
||||
cs_clip_rectangle,
|
||||
cs_clip_border,
|
||||
cs_clip_image,
|
||||
|
@ -1725,11 +1747,11 @@ impl Renderer {
|
|||
ps_yuv_image,
|
||||
ps_border_corner,
|
||||
ps_border_edge,
|
||||
ps_box_shadow,
|
||||
ps_gradient,
|
||||
ps_angle_gradient,
|
||||
ps_radial_gradient,
|
||||
ps_cache_image_rgba8,
|
||||
ps_cache_image_a8,
|
||||
ps_cache_image,
|
||||
ps_blend,
|
||||
ps_hw_composite,
|
||||
ps_split_composite,
|
||||
|
@ -1753,6 +1775,7 @@ impl Renderer {
|
|||
gpu_profile,
|
||||
prim_vao,
|
||||
blur_vao,
|
||||
box_shadow_vao,
|
||||
clip_vao,
|
||||
layer_texture,
|
||||
render_task_texture,
|
||||
|
@ -1909,29 +1932,19 @@ impl Renderer {
|
|||
"Borders",
|
||||
target.clip_batcher.borders.len(),
|
||||
);
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Cache,
|
||||
"Vertical Blur",
|
||||
target.vertical_blurs.len(),
|
||||
);
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Cache,
|
||||
"Horizontal Blur",
|
||||
target.horizontal_blurs.len(),
|
||||
);
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Clip,
|
||||
"Rectangles",
|
||||
target.clip_batcher.rectangles.len(),
|
||||
);
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Cache,
|
||||
"Rectangle Brush",
|
||||
target.rect_cache_prims.len(),
|
||||
);
|
||||
for (_, items) in target.clip_batcher.images.iter() {
|
||||
debug_target.add(debug_server::BatchKind::Clip, "Image mask", items.len());
|
||||
}
|
||||
debug_target.add(
|
||||
debug_server::BatchKind::Cache,
|
||||
"Box Shadow",
|
||||
target.box_shadow_cache_prims.len(),
|
||||
);
|
||||
|
||||
debug_pass.add(debug_target);
|
||||
}
|
||||
|
@ -1998,24 +2011,24 @@ impl Renderer {
|
|||
fn handle_debug_command(&mut self, command: DebugCommand) {
|
||||
match command {
|
||||
DebugCommand::EnableProfiler(enable) => if enable {
|
||||
self.debug_flags.insert(DebugFlags::PROFILER_DBG);
|
||||
self.debug_flags.insert(PROFILER_DBG);
|
||||
} else {
|
||||
self.debug_flags.remove(DebugFlags::PROFILER_DBG);
|
||||
self.debug_flags.remove(PROFILER_DBG);
|
||||
},
|
||||
DebugCommand::EnableTextureCacheDebug(enable) => if enable {
|
||||
self.debug_flags.insert(DebugFlags::TEXTURE_CACHE_DBG);
|
||||
self.debug_flags.insert(TEXTURE_CACHE_DBG);
|
||||
} else {
|
||||
self.debug_flags.remove(DebugFlags::TEXTURE_CACHE_DBG);
|
||||
self.debug_flags.remove(TEXTURE_CACHE_DBG);
|
||||
},
|
||||
DebugCommand::EnableRenderTargetDebug(enable) => if enable {
|
||||
self.debug_flags.insert(DebugFlags::RENDER_TARGET_DBG);
|
||||
self.debug_flags.insert(RENDER_TARGET_DBG);
|
||||
} else {
|
||||
self.debug_flags.remove(DebugFlags::RENDER_TARGET_DBG);
|
||||
self.debug_flags.remove(RENDER_TARGET_DBG);
|
||||
},
|
||||
DebugCommand::EnableAlphaRectsDebug(enable) => if enable {
|
||||
self.debug_flags.insert(DebugFlags::ALPHA_PRIM_DBG);
|
||||
self.debug_flags.insert(ALPHA_PRIM_DBG);
|
||||
} else {
|
||||
self.debug_flags.remove(DebugFlags::ALPHA_PRIM_DBG);
|
||||
self.debug_flags.remove(ALPHA_PRIM_DBG);
|
||||
},
|
||||
DebugCommand::FetchDocuments => {}
|
||||
DebugCommand::FetchClipScrollTree => {}
|
||||
|
@ -2120,7 +2133,7 @@ impl Renderer {
|
|||
self.cpu_profiles.push_back(cpu_profile);
|
||||
}
|
||||
|
||||
if self.debug_flags.contains(DebugFlags::PROFILER_DBG) {
|
||||
if self.debug_flags.contains(PROFILER_DBG) {
|
||||
let screen_fraction = 1.0 / //TODO: take device/pixel ratio into equation?
|
||||
(framebuffer_size.width as f32 * framebuffer_size.height as f32);
|
||||
self.profiler.draw_profile(
|
||||
|
@ -2301,6 +2314,7 @@ impl Renderer {
|
|||
VertexArrayKind::Primitive => &self.prim_vao,
|
||||
VertexArrayKind::Clip => &self.clip_vao,
|
||||
VertexArrayKind::Blur => &self.blur_vao,
|
||||
VertexArrayKind::CacheBoxShadow => &self.box_shadow_vao,
|
||||
};
|
||||
|
||||
self.device.bind_vao(vao);
|
||||
|
@ -2478,27 +2492,24 @@ impl Renderer {
|
|||
);
|
||||
GPU_TAG_PRIM_RADIAL_GRADIENT
|
||||
}
|
||||
TransformBatchKind::CacheImage(target_kind) => {
|
||||
match target_kind {
|
||||
RenderTargetKind::Alpha => {
|
||||
self.ps_cache_image_a8.bind(
|
||||
&mut self.device,
|
||||
transform_kind,
|
||||
projection,
|
||||
0,
|
||||
&mut self.renderer_errors,
|
||||
);
|
||||
}
|
||||
RenderTargetKind::Color => {
|
||||
self.ps_cache_image_rgba8.bind(
|
||||
&mut self.device,
|
||||
transform_kind,
|
||||
projection,
|
||||
0,
|
||||
&mut self.renderer_errors,
|
||||
);
|
||||
}
|
||||
}
|
||||
TransformBatchKind::BoxShadow => {
|
||||
self.ps_box_shadow.bind(
|
||||
&mut self.device,
|
||||
transform_kind,
|
||||
projection,
|
||||
0,
|
||||
&mut self.renderer_errors,
|
||||
);
|
||||
GPU_TAG_PRIM_BOX_SHADOW
|
||||
}
|
||||
TransformBatchKind::CacheImage => {
|
||||
self.ps_cache_image.bind(
|
||||
&mut self.device,
|
||||
transform_kind,
|
||||
projection,
|
||||
0,
|
||||
&mut self.renderer_errors,
|
||||
);
|
||||
GPU_TAG_PRIM_CACHE_IMAGE
|
||||
}
|
||||
},
|
||||
|
@ -2628,7 +2639,7 @@ impl Renderer {
|
|||
let _gm = self.gpu_profile.add_marker(GPU_TAG_BLUR);
|
||||
|
||||
self.device.set_blend(false);
|
||||
self.cs_blur_rgba8
|
||||
self.cs_blur
|
||||
.bind(&mut self.device, projection, 0, &mut self.renderer_errors);
|
||||
|
||||
if !target.vertical_blurs.is_empty() {
|
||||
|
@ -2723,7 +2734,7 @@ impl Renderer {
|
|||
self.gpu_profile.add_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
|
||||
|
||||
for batch in &target.alpha_batcher.batch_list.alpha_batch_list.batches {
|
||||
if self.debug_flags.contains(DebugFlags::ALPHA_PRIM_DBG) {
|
||||
if self.debug_flags.contains(ALPHA_PRIM_DBG) {
|
||||
let color = match batch.key.blend_mode {
|
||||
BlendMode::None => ColorF::new(0.3, 0.3, 0.3, 1.0),
|
||||
BlendMode::Alpha => ColorF::new(0.0, 0.9, 0.1, 1.0),
|
||||
|
@ -2910,45 +2921,15 @@ impl Renderer {
|
|||
.clear_target_rect(Some(clear_color), None, target.used_rect());
|
||||
}
|
||||
|
||||
// Draw any blurs for this target.
|
||||
// Blurs are rendered as a standard 2-pass
|
||||
// separable implementation.
|
||||
// TODO(gw): In the future, consider having
|
||||
// fast path blur shaders for common
|
||||
// blur radii with fixed weights.
|
||||
if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
|
||||
let _gm = self.gpu_profile.add_marker(GPU_TAG_BLUR);
|
||||
|
||||
// Draw any box-shadow caches for this target.
|
||||
if !target.box_shadow_cache_prims.is_empty() {
|
||||
self.device.set_blend(false);
|
||||
self.cs_blur_a8
|
||||
.bind(&mut self.device, projection, 0, &mut self.renderer_errors);
|
||||
|
||||
if !target.vertical_blurs.is_empty() {
|
||||
self.draw_instanced_batch(
|
||||
&target.vertical_blurs,
|
||||
VertexArrayKind::Blur,
|
||||
&BatchTextures::no_texture(),
|
||||
);
|
||||
}
|
||||
|
||||
if !target.horizontal_blurs.is_empty() {
|
||||
self.draw_instanced_batch(
|
||||
&target.horizontal_blurs,
|
||||
VertexArrayKind::Blur,
|
||||
&BatchTextures::no_texture(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if !target.rect_cache_prims.is_empty() {
|
||||
self.device.set_blend(false);
|
||||
|
||||
let _gm = self.gpu_profile.add_marker(GPU_TAG_BRUSH_MASK);
|
||||
self.brush_mask
|
||||
let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_BOX_SHADOW);
|
||||
self.cs_box_shadow
|
||||
.bind(&mut self.device, projection, 0, &mut self.renderer_errors);
|
||||
self.draw_instanced_batch(
|
||||
&target.rect_cache_prims,
|
||||
VertexArrayKind::Primitive,
|
||||
&target.box_shadow_cache_prims,
|
||||
VertexArrayKind::CacheBoxShadow,
|
||||
&BatchTextures::no_texture(),
|
||||
);
|
||||
}
|
||||
|
@ -3349,7 +3330,7 @@ impl Renderer {
|
|||
}
|
||||
|
||||
fn draw_render_target_debug(&mut self, framebuffer_size: DeviceUintSize) {
|
||||
if !self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) {
|
||||
if !self.debug_flags.contains(RENDER_TARGET_DBG) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3389,7 +3370,7 @@ impl Renderer {
|
|||
}
|
||||
|
||||
fn draw_texture_cache_debug(&mut self, framebuffer_size: DeviceUintSize) {
|
||||
if !self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
|
||||
if !self.debug_flags.contains(TEXTURE_CACHE_DBG) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3410,7 +3391,7 @@ impl Renderer {
|
|||
|
||||
let mut i = 0;
|
||||
for texture in &self.texture_resolver.cache_texture_map {
|
||||
let y = spacing + if self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) {
|
||||
let y = spacing + if self.debug_flags.contains(RENDER_TARGET_DBG) {
|
||||
528
|
||||
} else {
|
||||
0
|
||||
|
@ -3492,12 +3473,12 @@ impl Renderer {
|
|||
self.device.delete_vao(self.prim_vao);
|
||||
self.device.delete_vao(self.clip_vao);
|
||||
self.device.delete_vao(self.blur_vao);
|
||||
self.device.delete_vao(self.box_shadow_vao);
|
||||
self.debug.deinit(&mut self.device);
|
||||
self.cs_box_shadow.deinit(&mut self.device);
|
||||
self.cs_text_run.deinit(&mut self.device);
|
||||
self.cs_line.deinit(&mut self.device);
|
||||
self.cs_blur_a8.deinit(&mut self.device);
|
||||
self.cs_blur_rgba8.deinit(&mut self.device);
|
||||
self.brush_mask.deinit(&mut self.device);
|
||||
self.cs_blur.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);
|
||||
|
@ -3522,8 +3503,8 @@ impl Renderer {
|
|||
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_cache_image_rgba8.deinit(&mut self.device);
|
||||
self.ps_cache_image_a8.deinit(&mut self.device);
|
||||
self.ps_box_shadow.deinit(&mut self.device);
|
||||
self.ps_cache_image.deinit(&mut self.device);
|
||||
self.ps_line.deinit(&mut self.device);
|
||||
self.ps_blend.deinit(&mut self.device);
|
||||
self.ps_hw_composite.deinit(&mut self.device);
|
||||
|
|
|
@ -22,7 +22,6 @@ use internal_types::{FastHashMap, FastHashSet, SourceTexture, TextureUpdateList}
|
|||
use profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
|
||||
use rayon::ThreadPool;
|
||||
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
|
||||
use std::cmp;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::mem;
|
||||
|
@ -114,15 +113,8 @@ struct CachedImageInfo {
|
|||
epoch: Epoch,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ResourceClassCacheError {
|
||||
OverLimitSize,
|
||||
}
|
||||
|
||||
pub type ResourceCacheResult<V> = Result<V, ResourceClassCacheError>;
|
||||
|
||||
pub struct ResourceClassCache<K, V> {
|
||||
resources: FastHashMap<K, ResourceCacheResult<V>>,
|
||||
resources: FastHashMap<K, V>,
|
||||
}
|
||||
|
||||
impl<K, V> ResourceClassCache<K, V>
|
||||
|
@ -135,21 +127,21 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn get(&self, key: &K) -> &ResourceCacheResult<V> {
|
||||
self.resources.get(key)
|
||||
fn get(&self, key: &K) -> &V {
|
||||
self.resources
|
||||
.get(key)
|
||||
.expect("Didn't find a cached resource with that ID!")
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: K, value: ResourceCacheResult<V>) {
|
||||
pub fn insert(&mut self, key: K, value: V) {
|
||||
self.resources.insert(key, value);
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, key: &K) -> &mut ResourceCacheResult<V> {
|
||||
pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
|
||||
self.resources.get_mut(key)
|
||||
.expect("Didn't find a cached resource with that ID!")
|
||||
}
|
||||
|
||||
pub fn entry(&mut self, key: K) -> Entry<K, ResourceCacheResult<V>> {
|
||||
pub fn entry(&mut self, key: K) -> Entry<K, V> {
|
||||
self.resources.entry(key)
|
||||
}
|
||||
|
||||
|
@ -167,7 +159,7 @@ where
|
|||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
for key in resources_to_destroy {
|
||||
let _ = self.resources.remove(&key).unwrap();
|
||||
self.resources.remove(&key).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -491,38 +483,25 @@ impl ResourceCache {
|
|||
return;
|
||||
}
|
||||
|
||||
let side_size =
|
||||
template.tiling.map_or(cmp::max(template.descriptor.width, template.descriptor.height),
|
||||
|tile_size| tile_size as u32);
|
||||
if side_size > self.texture_cache.max_texture_size() {
|
||||
// The image or tiling size is too big for hardware texture size.
|
||||
warn!("Dropping image, image:(w:{},h:{}, tile:{}) is too big for hardware!",
|
||||
template.descriptor.width, template.descriptor.height, template.tiling.unwrap_or(0));
|
||||
self.cached_images.insert(request, Err(ResourceClassCacheError::OverLimitSize));
|
||||
return;
|
||||
}
|
||||
|
||||
// If this image exists in the texture cache, *and* the epoch
|
||||
// in the cache matches that of the template, then it is
|
||||
// valid to use as-is.
|
||||
let (entry, needs_update) = match self.cached_images.entry(request) {
|
||||
Occupied(entry) => {
|
||||
let needs_update = entry.get().as_ref().unwrap().epoch != template.epoch;
|
||||
let needs_update = entry.get().epoch != template.epoch;
|
||||
(entry.into_mut(), needs_update)
|
||||
}
|
||||
Vacant(entry) => (
|
||||
entry.insert(Ok(
|
||||
CachedImageInfo {
|
||||
epoch: template.epoch,
|
||||
texture_cache_handle: TextureCacheHandle::new(),
|
||||
}
|
||||
)),
|
||||
entry.insert(CachedImageInfo {
|
||||
epoch: template.epoch,
|
||||
texture_cache_handle: TextureCacheHandle::new(),
|
||||
}),
|
||||
true,
|
||||
),
|
||||
};
|
||||
|
||||
let needs_upload = self.texture_cache
|
||||
.request(&mut entry.as_mut().unwrap().texture_cache_handle, gpu_cache);
|
||||
.request(&mut entry.texture_cache_handle, gpu_cache);
|
||||
|
||||
if !needs_upload && !needs_update {
|
||||
return;
|
||||
|
@ -621,7 +600,7 @@ impl ResourceCache {
|
|||
debug_assert!(fetch_buffer.is_empty());
|
||||
|
||||
for (loop_index, key) in glyph_keys.iter().enumerate() {
|
||||
if let Ok(Some(ref glyph)) = *glyph_key_cache.get(key) {
|
||||
if let Some(ref glyph) = *glyph_key_cache.get(key) {
|
||||
let cache_item = self.texture_cache.get(&glyph.texture_cache_handle);
|
||||
if current_texture_id != cache_item.texture_id {
|
||||
if !fetch_buffer.is_empty() {
|
||||
|
@ -669,24 +648,15 @@ impl ResourceCache {
|
|||
image_key: ImageKey,
|
||||
image_rendering: ImageRendering,
|
||||
tile: Option<TileOffset>,
|
||||
) -> Result<CacheItem, ()> {
|
||||
) -> CacheItem {
|
||||
debug_assert_eq!(self.state, State::QueryResources);
|
||||
let key = ImageRequest {
|
||||
key: image_key,
|
||||
rendering: image_rendering,
|
||||
tile,
|
||||
};
|
||||
|
||||
// TODO(Jerry): add a debug option to visualize the corresponding area for
|
||||
// the Err() case of CacheItem.
|
||||
match *self.cached_images.get(&key) {
|
||||
Ok(ref image_info) => {
|
||||
Ok(self.texture_cache.get(&image_info.texture_cache_handle))
|
||||
}
|
||||
Err(_) => {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
let image_info = &self.cached_images.get(&key);
|
||||
self.texture_cache.get(&image_info.texture_cache_handle)
|
||||
}
|
||||
|
||||
pub fn get_image_properties(&self, image_key: ImageKey) -> Option<ImageProperties> {
|
||||
|
@ -846,7 +816,7 @@ impl ResourceCache {
|
|||
image_template.descriptor.clone()
|
||||
};
|
||||
|
||||
let entry = self.cached_images.get_mut(&request).as_mut().unwrap();
|
||||
let entry = self.cached_images.get_mut(&request).unwrap();
|
||||
self.texture_cache.update(
|
||||
&mut entry.texture_cache_handle,
|
||||
descriptor,
|
||||
|
|
|
@ -133,12 +133,6 @@ impl Scene {
|
|||
}
|
||||
self.pipelines.remove(&pipeline_id);
|
||||
}
|
||||
|
||||
pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
|
||||
if let Some(pipeline) = self.pipelines.get_mut(&pipeline_id) {
|
||||
pipeline.epoch = epoch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FilterOpHelpers {
|
||||
|
|
|
@ -9,10 +9,9 @@ use api::{LayerToWorldTransform, MixBlendMode, PipelineId, PropertyBinding, Tran
|
|||
use api::{LayerVector2D, TileOffset, WorldToLayerTransform, YuvColorSpace, YuvFormat};
|
||||
use border::{BorderCornerInstance, BorderCornerSide};
|
||||
use clip::{ClipSource, ClipStore};
|
||||
use clip_scroll_tree::CoordinateSystemId;
|
||||
use device::Texture;
|
||||
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuCacheUpdateList};
|
||||
use gpu_types::{BlurDirection, BlurInstance, BrushInstance, ClipMaskInstance};
|
||||
use gpu_types::{BlurDirection, BlurInstance, BoxShadowCacheInstance, ClipMaskInstance};
|
||||
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
|
||||
use internal_types::{FastHashMap, SourceTexture};
|
||||
use internal_types::BatchTextures;
|
||||
|
@ -401,9 +400,6 @@ impl AlphaRenderItem {
|
|||
let blend_mode = ctx.prim_store.get_blend_mode(prim_metadata, transform_kind);
|
||||
|
||||
match prim_metadata.prim_kind {
|
||||
PrimitiveKind::Brush => {
|
||||
panic!("BUG: brush type not expected in an alpha task (yet)");
|
||||
}
|
||||
PrimitiveKind::Border => {
|
||||
let border_cpu =
|
||||
&ctx.prim_store.cpu_borders[prim_metadata.cpu_prim_index.0];
|
||||
|
@ -485,7 +481,6 @@ impl AlphaRenderItem {
|
|||
);
|
||||
|
||||
if color_texture_id == SourceTexture::Invalid {
|
||||
warn!("Warnings: skip a PrimitiveKind::Image at {:?}.\n", item_bounding_rect);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -544,8 +539,6 @@ impl AlphaRenderItem {
|
|||
glyph_fetch_buffer,
|
||||
gpu_cache,
|
||||
|texture_id, glyphs| {
|
||||
debug_assert_ne!(texture_id, SourceTexture::Invalid);
|
||||
|
||||
let textures = BatchTextures {
|
||||
colors: [
|
||||
texture_id,
|
||||
|
@ -580,7 +573,7 @@ impl AlphaRenderItem {
|
|||
let textures = BatchTextures::render_target_cache();
|
||||
let kind = BatchKind::Transformable(
|
||||
transform_kind,
|
||||
TransformBatchKind::CacheImage(picture.kind),
|
||||
TransformBatchKind::CacheImage,
|
||||
);
|
||||
let key = BatchKey::new(kind, blend_mode, textures);
|
||||
let batch = batch_list.get_suitable_batch(key, item_bounding_rect);
|
||||
|
@ -639,7 +632,6 @@ impl AlphaRenderItem {
|
|||
);
|
||||
|
||||
if texture == SourceTexture::Invalid {
|
||||
warn!("Warnings: skip a PrimitiveKind::YuvImage at {:?}.\n", item_bounding_rect);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -699,6 +691,26 @@ impl AlphaRenderItem {
|
|||
uv_rect_addresses[2],
|
||||
));
|
||||
}
|
||||
PrimitiveKind::BoxShadow => {
|
||||
let box_shadow =
|
||||
&ctx.prim_store.cpu_box_shadows[prim_metadata.cpu_prim_index.0];
|
||||
let cache_task_id = box_shadow.render_task_id.unwrap();
|
||||
let cache_task_address = render_tasks.get_task_address(cache_task_id);
|
||||
let textures = BatchTextures::render_target_cache();
|
||||
|
||||
let kind =
|
||||
BatchKind::Transformable(transform_kind, TransformBatchKind::BoxShadow);
|
||||
let key = BatchKey::new(kind, blend_mode, textures);
|
||||
let batch = batch_list.get_suitable_batch(key, item_bounding_rect);
|
||||
|
||||
for rect_index in 0 .. box_shadow.rects.len() {
|
||||
batch.push(base_instance.build(
|
||||
rect_index as i32,
|
||||
cache_task_address.0 as i32,
|
||||
0,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AlphaRenderItem::SplitComposite(sc_index, task_id, gpu_handle, z) => {
|
||||
|
@ -800,13 +812,11 @@ impl ClipBatcher {
|
|||
&mut self,
|
||||
task_address: RenderTaskAddress,
|
||||
clips: &[ClipWorkItem],
|
||||
coordinate_system_id: CoordinateSystemId,
|
||||
resource_cache: &ResourceCache,
|
||||
gpu_cache: &GpuCache,
|
||||
geometry_kind: MaskGeometryKind,
|
||||
clip_store: &ClipStore,
|
||||
) {
|
||||
let mut coordinate_system_id = coordinate_system_id;
|
||||
for work_item in clips.iter() {
|
||||
let instance = ClipMaskInstance {
|
||||
render_task_address: task_address,
|
||||
|
@ -824,29 +834,23 @@ impl ClipBatcher {
|
|||
|
||||
match *source {
|
||||
ClipSource::Image(ref mask) => {
|
||||
if let Ok(cache_item) = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None) {
|
||||
self.images
|
||||
.entry(cache_item.texture_id)
|
||||
.or_insert(Vec::new())
|
||||
.push(ClipMaskInstance {
|
||||
clip_data_address: gpu_address,
|
||||
resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle),
|
||||
..instance
|
||||
});
|
||||
} else {
|
||||
warn!("Warnings: skip a image mask. Key:{:?} Rect::{:?}.\n", mask.image, mask.rect);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ClipSource::Rectangle(..) => {
|
||||
if work_item.coordinate_system_id != coordinate_system_id {
|
||||
self.rectangles.push(ClipMaskInstance {
|
||||
let cache_item =
|
||||
resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None);
|
||||
self.images
|
||||
.entry(cache_item.texture_id)
|
||||
.or_insert(Vec::new())
|
||||
.push(ClipMaskInstance {
|
||||
clip_data_address: gpu_address,
|
||||
segment: MaskSegment::All as i32,
|
||||
resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle),
|
||||
..instance
|
||||
});
|
||||
coordinate_system_id = work_item.coordinate_system_id;
|
||||
}
|
||||
}
|
||||
ClipSource::Rectangle(..) => if work_item.apply_rectangles {
|
||||
self.rectangles.push(ClipMaskInstance {
|
||||
clip_data_address: gpu_address,
|
||||
segment: MaskSegment::All as i32,
|
||||
..instance
|
||||
});
|
||||
},
|
||||
ClipSource::RoundedRectangle(..) => match geometry_kind {
|
||||
MaskGeometryKind::Default => {
|
||||
|
@ -967,7 +971,7 @@ pub trait RenderTarget {
|
|||
fn used_rect(&self) -> DeviceIntRect;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum RenderTargetKind {
|
||||
Color, // RGBA32
|
||||
Alpha, // R8
|
||||
|
@ -1155,8 +1159,8 @@ impl RenderTarget for ColorRenderTarget {
|
|||
blur_direction: BlurDirection::Horizontal,
|
||||
});
|
||||
}
|
||||
RenderTaskKind::Picture(ref task_info) => {
|
||||
let prim_metadata = ctx.prim_store.get_metadata(task_info.prim_index);
|
||||
RenderTaskKind::Picture(prim_index) => {
|
||||
let prim_metadata = ctx.prim_store.get_metadata(prim_index);
|
||||
let prim_address = prim_metadata.gpu_location.as_int(gpu_cache);
|
||||
|
||||
match prim_metadata.prim_kind {
|
||||
|
@ -1228,7 +1232,7 @@ impl RenderTarget for ColorRenderTarget {
|
|||
}
|
||||
}
|
||||
}
|
||||
RenderTaskKind::CacheMask(..) => {
|
||||
RenderTaskKind::CacheMask(..) | RenderTaskKind::BoxShadow(..) => {
|
||||
panic!("Should not be added to color target!");
|
||||
}
|
||||
RenderTaskKind::Readback(device_rect) => {
|
||||
|
@ -1240,10 +1244,7 @@ impl RenderTarget for ColorRenderTarget {
|
|||
|
||||
pub struct AlphaRenderTarget {
|
||||
pub clip_batcher: ClipBatcher,
|
||||
pub rect_cache_prims: Vec<PrimitiveInstance>,
|
||||
// List of blur operations to apply for this render target.
|
||||
pub vertical_blurs: Vec<BlurInstance>,
|
||||
pub horizontal_blurs: Vec<BlurInstance>,
|
||||
pub box_shadow_cache_prims: Vec<BoxShadowCacheInstance>,
|
||||
allocator: TextureAllocator,
|
||||
}
|
||||
|
||||
|
@ -1255,9 +1256,7 @@ impl RenderTarget for AlphaRenderTarget {
|
|||
fn new(size: Option<DeviceUintSize>) -> AlphaRenderTarget {
|
||||
AlphaRenderTarget {
|
||||
clip_batcher: ClipBatcher::new(),
|
||||
rect_cache_prims: Vec::new(),
|
||||
vertical_blurs: Vec::new(),
|
||||
horizontal_blurs: Vec::new(),
|
||||
box_shadow_cache_prims: Vec::new(),
|
||||
allocator: TextureAllocator::new(size.expect("bug: alpha targets need size")),
|
||||
}
|
||||
}
|
||||
|
@ -1280,59 +1279,24 @@ impl RenderTarget for AlphaRenderTarget {
|
|||
panic!("BUG: add_task() called on invalidated task");
|
||||
}
|
||||
RenderTaskKind::Alpha(..) |
|
||||
RenderTaskKind::VerticalBlur(..) |
|
||||
RenderTaskKind::HorizontalBlur(..) |
|
||||
RenderTaskKind::Picture(..) |
|
||||
RenderTaskKind::Readback(..) => {
|
||||
panic!("Should not be added to alpha target!");
|
||||
}
|
||||
RenderTaskKind::VerticalBlur(..) => {
|
||||
// Find the child render task that we are applying
|
||||
// a vertical blur on.
|
||||
self.vertical_blurs.push(BlurInstance {
|
||||
task_address: render_tasks.get_task_address(task_id),
|
||||
src_task_address: render_tasks.get_task_address(task.children[0]),
|
||||
blur_direction: BlurDirection::Vertical,
|
||||
});
|
||||
}
|
||||
RenderTaskKind::HorizontalBlur(..) => {
|
||||
// Find the child render task that we are applying
|
||||
// a horizontal blur on.
|
||||
self.horizontal_blurs.push(BlurInstance {
|
||||
task_address: render_tasks.get_task_address(task_id),
|
||||
src_task_address: render_tasks.get_task_address(task.children[0]),
|
||||
blur_direction: BlurDirection::Horizontal,
|
||||
});
|
||||
}
|
||||
RenderTaskKind::Picture(ref task_info) => {
|
||||
let prim_metadata = ctx.prim_store.get_metadata(task_info.prim_index);
|
||||
RenderTaskKind::BoxShadow(prim_index) => {
|
||||
let prim_metadata = ctx.prim_store.get_metadata(prim_index);
|
||||
|
||||
match prim_metadata.prim_kind {
|
||||
PrimitiveKind::Picture => {
|
||||
let prim = &ctx.prim_store.cpu_pictures[prim_metadata.cpu_prim_index.0];
|
||||
|
||||
let task_index = render_tasks.get_task_address(task_id);
|
||||
|
||||
for run in &prim.prim_runs {
|
||||
for i in 0 .. run.count {
|
||||
let sub_prim_index = PrimitiveIndex(run.prim_index.0 + i);
|
||||
|
||||
let sub_metadata = ctx.prim_store.get_metadata(sub_prim_index);
|
||||
let sub_prim_address =
|
||||
gpu_cache.get_address(&sub_metadata.gpu_location);
|
||||
|
||||
match sub_metadata.prim_kind {
|
||||
PrimitiveKind::Brush => {
|
||||
let instance = BrushInstance::new(task_index, sub_prim_address);
|
||||
self.rect_cache_prims.push(PrimitiveInstance::from(instance));
|
||||
}
|
||||
_ => {
|
||||
unreachable!("Unexpected sub primitive type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PrimitiveKind::BoxShadow => {
|
||||
self.box_shadow_cache_prims.push(BoxShadowCacheInstance {
|
||||
prim_address: gpu_cache.get_address(&prim_metadata.gpu_location),
|
||||
task_index: render_tasks.get_task_address(task_id),
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
// No other primitives make use of primitive caching yet!
|
||||
unreachable!()
|
||||
panic!("BUG: invalid prim kind");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1341,7 +1305,6 @@ impl RenderTarget for AlphaRenderTarget {
|
|||
self.clip_batcher.add(
|
||||
task_address,
|
||||
&task_info.clips,
|
||||
task_info.coordinate_system_id,
|
||||
&ctx.resource_cache,
|
||||
gpu_cache,
|
||||
task_info.geometry_kind,
|
||||
|
@ -1525,7 +1488,8 @@ pub enum TransformBatchKind {
|
|||
AlignedGradient,
|
||||
AngleGradient,
|
||||
RadialGradient,
|
||||
CacheImage(RenderTargetKind),
|
||||
BoxShadow,
|
||||
CacheImage,
|
||||
BorderCorner,
|
||||
BorderEdge,
|
||||
Line,
|
||||
|
@ -1722,7 +1686,6 @@ pub struct ClipScrollGroup {
|
|||
pub clip_node_id: ClipId,
|
||||
pub packed_layer_index: PackedLayerIndex,
|
||||
pub screen_bounding_rect: Option<(TransformedRectKind, DeviceIntRect)>,
|
||||
pub coordinate_system_id: CoordinateSystemId,
|
||||
}
|
||||
|
||||
impl ClipScrollGroup {
|
||||
|
@ -1861,12 +1824,10 @@ fn resolve_image(
|
|||
(SourceTexture::External(external_image), cache_handle)
|
||||
}
|
||||
None => {
|
||||
if let Ok(cache_item) = resource_cache.get_cached_image(image_key, image_rendering, tile_offset) {
|
||||
(cache_item.texture_id, cache_item.uv_rect_handle)
|
||||
} else {
|
||||
// There is no usable texture entry for the image key. Just return an invalid texture here.
|
||||
(SourceTexture::Invalid, GpuCacheHandle::new())
|
||||
}
|
||||
let cache_item =
|
||||
resource_cache.get_cached_image(image_key, image_rendering, tile_offset);
|
||||
|
||||
(cache_item.texture_id, cache_item.uv_rect_handle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
* 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, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
||||
use api::{DevicePoint, DeviceRect, DeviceSize, LayerRect, LayerToWorldTransform, LayoutRect};
|
||||
use api::WorldPoint3D;
|
||||
use api::{BorderRadius, ComplexClipRegion, DeviceIntRect, DevicePoint, DeviceRect, DeviceSize};
|
||||
use api::{LayerRect, LayerToWorldTransform, LayoutRect, WorldPoint3D};
|
||||
use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D};
|
||||
use euclid::TypedTransform3D;
|
||||
use num_traits::Zero;
|
||||
use std::f32::consts::FRAC_1_SQRT_2;
|
||||
use std::i32;
|
||||
|
||||
// Matches the definition of SK_ScalarNearlyZero in Skia.
|
||||
const NEARLY_ZERO: f32 = 1.0 / 4096.0;
|
||||
|
@ -209,6 +207,13 @@ pub struct TransformedRect {
|
|||
pub kind: TransformedRectKind,
|
||||
}
|
||||
|
||||
// Having an unlimited bounding box is fine up until we try
|
||||
// to cast it to `i32`, where we get `-2147483648` for any
|
||||
// values larger than or equal to 2^31.
|
||||
//Note: clamping to i32::MIN and i32::MAX is not a solution,
|
||||
// with explanation left as an exercise for the reader.
|
||||
const MAX_COORD: f32 = 1.0e9;
|
||||
|
||||
impl TransformedRect {
|
||||
pub fn new(
|
||||
rect: &LayerRect,
|
||||
|
@ -244,7 +249,10 @@ impl TransformedRect {
|
|||
let inner_min_dp = (DevicePoint::new(xs[1], ys[1]) * device_pixel_ratio).ceil();
|
||||
let inner_max_dp = (DevicePoint::new(xs[2], ys[2]) * device_pixel_ratio).floor();
|
||||
|
||||
let max_rect = DeviceRect::max_rect();
|
||||
let max_rect = DeviceRect::new(
|
||||
DevicePoint::new(-MAX_COORD, -MAX_COORD),
|
||||
DeviceSize::new(2.0 * MAX_COORD, 2.0 * MAX_COORD),
|
||||
);
|
||||
let bounding_rect = DeviceRect::new(outer_min_dp, (outer_max_dp - outer_min_dp).to_size())
|
||||
.intersection(&max_rect)
|
||||
.unwrap_or(max_rect)
|
||||
|
@ -354,33 +362,3 @@ pub mod test {
|
|||
assert_eq!(m1.inverse_project(&p0), Some(Point2D::new(2.0, 2.0)));
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MaxRect {
|
||||
fn max_rect() -> Self;
|
||||
}
|
||||
|
||||
impl MaxRect for DeviceIntRect {
|
||||
fn max_rect() -> Self {
|
||||
DeviceIntRect::new(
|
||||
DeviceIntPoint::new(i32::MIN / 2, i32::MIN / 2),
|
||||
DeviceIntSize::new(i32::MAX, i32::MAX),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl MaxRect for DeviceRect {
|
||||
fn max_rect() -> Self {
|
||||
// Having an unlimited bounding box is fine up until we try
|
||||
// to cast it to `i32`, where we get `-2147483648` for any
|
||||
// values larger than or equal to 2^31.
|
||||
//
|
||||
// Note: clamping to i32::MIN and i32::MAX is not a solution,
|
||||
// with explanation left as an exercise for the reader.
|
||||
const MAX_COORD: f32 = 1.0e9;
|
||||
|
||||
DeviceRect::new(
|
||||
DevicePoint::new(-MAX_COORD, -MAX_COORD),
|
||||
DeviceSize::new(2.0 * MAX_COORD, 2.0 * MAX_COORD),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,10 @@ const SHADERS: &[Shader] = &[
|
|||
name: "cs_text_run",
|
||||
features: CACHE_FEATURES,
|
||||
},
|
||||
Shader {
|
||||
name: "cs_box_shadow",
|
||||
features: CACHE_FEATURES,
|
||||
},
|
||||
// Prim shaders
|
||||
Shader {
|
||||
name: "ps_line",
|
||||
|
@ -54,6 +58,10 @@ const SHADERS: &[Shader] = &[
|
|||
name: "ps_border_edge",
|
||||
features: PRIM_FEATURES,
|
||||
},
|
||||
Shader {
|
||||
name: "ps_box_shadow",
|
||||
features: PRIM_FEATURES,
|
||||
},
|
||||
Shader {
|
||||
name: "ps_gradient",
|
||||
features: PRIM_FEATURES,
|
||||
|
@ -68,7 +76,7 @@ const SHADERS: &[Shader] = &[
|
|||
},
|
||||
Shader {
|
||||
name: "ps_cache_image",
|
||||
features: &["COLOR", "ALPHA"],
|
||||
features: PRIM_FEATURES,
|
||||
},
|
||||
Shader {
|
||||
name: "ps_blend",
|
||||
|
@ -102,11 +110,6 @@ const SHADERS: &[Shader] = &[
|
|||
name: "ps_rectangle",
|
||||
features: &["", "TRANSFORM", "CLIP_FEATURE", "TRANSFORM,CLIP_FEATURE"],
|
||||
},
|
||||
// Brush shaders
|
||||
Shader {
|
||||
name: "brush_mask",
|
||||
features: &[],
|
||||
},
|
||||
];
|
||||
|
||||
const VERSION_STRING: &str = "#version 300 es\n";
|
||||
|
|
|
@ -11,8 +11,8 @@ ipc = ["ipc-channel"]
|
|||
|
||||
[dependencies]
|
||||
app_units = "0.5.6"
|
||||
bitflags = "1.0"
|
||||
bincode = "0.9"
|
||||
bitflags = "0.9"
|
||||
byteorder = "1.0"
|
||||
euclid = "0.15"
|
||||
heapsize = ">= 0.3.6, < 0.5"
|
||||
|
|
|
@ -154,10 +154,6 @@ pub struct HitTestItem {
|
|||
/// viewport is the scroll node formed by the root reference frame of the display item's
|
||||
/// pipeline.
|
||||
pub point_in_viewport: LayoutPoint,
|
||||
|
||||
/// The coordinates of the original hit test point relative to the origin of this item.
|
||||
/// This is useful for calculating things like text offsets in the client.
|
||||
pub point_relative_to_item: LayoutPoint,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
|
@ -196,11 +192,6 @@ pub enum DocumentMsg {
|
|||
preserve_frame_state: bool,
|
||||
resources: ResourceUpdates,
|
||||
},
|
||||
UpdatePipelineResources {
|
||||
resources: ResourceUpdates,
|
||||
pipeline_id: PipelineId,
|
||||
epoch: Epoch,
|
||||
},
|
||||
SetPageZoom(ZoomFactor),
|
||||
SetPinchZoom(ZoomFactor),
|
||||
SetPan(DeviceIntPoint),
|
||||
|
@ -223,7 +214,6 @@ impl fmt::Debug for DocumentMsg {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(match *self {
|
||||
DocumentMsg::SetDisplayList { .. } => "DocumentMsg::SetDisplayList",
|
||||
DocumentMsg::UpdatePipelineResources { .. } => "DocumentMsg::UpdatePipelineResources",
|
||||
DocumentMsg::HitTest(..) => "DocumentMsg::HitTest",
|
||||
DocumentMsg::SetPageZoom(..) => "DocumentMsg::SetPageZoom",
|
||||
DocumentMsg::SetPinchZoom(..) => "DocumentMsg::SetPinchZoom",
|
||||
|
@ -471,7 +461,7 @@ impl RenderApi {
|
|||
ImageKey::new(self.namespace_id, new_id)
|
||||
}
|
||||
|
||||
/// Add/remove/update resources such as images and fonts.
|
||||
/// Adds an image identified by the `ImageKey`.
|
||||
pub fn update_resources(&self, resources: ResourceUpdates) {
|
||||
if resources.updates.is_empty() {
|
||||
return;
|
||||
|
@ -481,24 +471,6 @@ impl RenderApi {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
/// Add/remove/update resources such as images and fonts.
|
||||
///
|
||||
/// This is similar to update_resources with the addition that it allows updating
|
||||
/// a pipeline's epoch.
|
||||
pub fn update_pipeline_resources(
|
||||
&self,
|
||||
resources: ResourceUpdates,
|
||||
document_id: DocumentId,
|
||||
pipeline_id: PipelineId,
|
||||
epoch: Epoch,
|
||||
) {
|
||||
self.send(document_id, DocumentMsg::UpdatePipelineResources {
|
||||
resources,
|
||||
pipeline_id,
|
||||
epoch,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_external_event(&self, evt: ExternalEvent) {
|
||||
let msg = ApiMsg::ExternalEvent(evt);
|
||||
self.api_sender.send(msg).unwrap();
|
||||
|
|
|
@ -286,8 +286,9 @@ pub enum BorderStyle {
|
|||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub enum BoxShadowClipMode {
|
||||
Outset = 0,
|
||||
Inset = 1,
|
||||
None = 0,
|
||||
Outset = 1,
|
||||
Inset = 2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
|
|
|
@ -399,7 +399,7 @@ impl<'a, T: for<'de> Deserialize<'de>> Iterator for AuxIter<'a, T> {
|
|||
impl<'a, T: for<'de> Deserialize<'de>> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {}
|
||||
|
||||
|
||||
// This is purely for the JSON/RON writers in wrench
|
||||
// This is purely for the JSON writer in wrench
|
||||
impl Serialize for BuiltDisplayList {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut seq = serializer.serialize_seq(None)?;
|
||||
|
|
Загрузка…
Ссылка в новой задаче