Test xf AA change. try: -b do -p linux64 -u all[linux64-qr] -t none
Test xf AA change. try: -b do -p linux64 -u all[linux64-qr] -t none
--- a/gfx/webrender/res/brush.glsl
+++ b/gfx/webrender/res/brush.glsl
@@ -62,32 +62,51 @@ void main(void) {
// Right now - pictures only support local positions. In the future, this
// will be expanded to support transform picture types (the common kind).
device_pos = pic_task.common_data.task_rect.p0 +
uDevicePixelRatio * (local_pos - pic_task.content_origin);
// Write the final position transformed by the orthographic device-pixel projection.
gl_Position = uTransform * vec4(device_pos, 0.0, 1.0);
} else {
+ VertexInfo vi;
Layer layer = fetch_layer(brush.clip_node_id, brush.scroll_node_id);
ClipArea clip_area = fetch_clip_area(brush.clip_address);
// Write the normal vertex information out.
- // TODO(gw): Support transform types in brushes. For now,
- // the old cache image shader didn't support
- // them yet anyway, so we're not losing any
- // existing functionality.
- VertexInfo vi = write_vertex(
- geom.local_rect,
- geom.local_clip_rect,
- float(brush.z),
- layer,
- pic_task,
- geom.local_rect
- );
+ if (layer.is_axis_aligned) {
+ vi = write_vertex(
+ geom.local_rect,
+ geom.local_clip_rect,
+ float(brush.z),
+ layer,
+ pic_task,
+ geom.local_rect
+ );
+
+ // TODO(gw): vLocalBounds may be referenced by
+ // the fragment shader when running in
+ // the alpha pass, even on non-transformed
+ // items. For now, just ensure it has no
+ // effect. We can tidy this up as we move
+ // more items to be brush shaders.
+ vLocalBounds = vec4(
+ geom.local_clip_rect.p0,
+ geom.local_clip_rect.p0 + geom.local_clip_rect.size
+ );
+ } else {
+ vi = write_transform_vertex(geom.local_rect,
+ geom.local_rect,
+ geom.local_clip_rect,
+ vec4(1.0),
+ float(brush.z),
+ layer,
+ pic_task
+ );
+ }
local_pos = vi.local_pos;
// For brush instances in the alpha pass, always write
// out clip information.
// TODO(gw): It's possible that we might want alpha
// shaders that don't clip in the future,
// but it's reasonable to assume that one
--- a/gfx/webrender/res/brush_image.glsl
+++ b/gfx/webrender/res/brush_image.glsl
@@ -1,14 +1,18 @@
/* 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,brush
+#ifdef WR_FEATURE_ALPHA_PASS
+varying vec2 vLocalPos;
+#endif
+
varying vec3 vUv;
flat varying int vImageKind;
flat varying vec4 vUvBounds;
flat varying vec4 vUvBounds_NoClamp;
flat varying vec4 vParams;
#if defined WR_FEATURE_ALPHA_TARGET
flat varying vec4 vColor;
@@ -71,16 +75,20 @@ void brush_vs(
vUv.xy = (local_pos - local_rect.p0) / local_src_size;
vParams.xy = 0.5 * local_rect.size / local_src_size;
break;
}
}
vUvBounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) / texture_size.xyxy;
vUvBounds_NoClamp = vec4(uv0, uv1) / texture_size.xyxy;
+
+#ifdef WR_FEATURE_ALPHA_PASS
+ vLocalPos = local_pos;
+#endif
}
#endif
#ifdef WR_FRAGMENT_SHADER
vec4 brush_fs() {
vec2 uv;
switch (vImageKind) {
@@ -111,11 +119,15 @@ vec4 brush_fs() {
}
#if defined WR_FEATURE_COLOR_TARGET
vec4 color = texture(sColor0, vec3(uv, vUv.z));
#else
vec4 color = vColor * texture(sColor1, vec3(uv, vUv.z)).r;
#endif
+#ifdef WR_FEATURE_ALPHA_PASS
+ color *= init_transform_fs(vLocalPos);
+#endif
+
return color;
}
#endif
--- a/gfx/webrender/res/prim_shared.glsl
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -31,19 +31,17 @@ vec2 clamp_rect(vec2 point, RectWithSize
float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
vec2 dir_to_p0 = p0 - p;
return dot(normalize(perp_dir), dir_to_p0);
}
// TODO: convert back to RectWithEndPoint if driver issues are resolved, if ever.
flat varying vec4 vClipMaskUvBounds;
varying vec3 vClipMaskUv;
-#ifdef WR_FEATURE_TRANSFORM
- flat varying vec4 vLocalBounds;
-#endif
+flat varying vec4 vLocalBounds;
// TODO(gw): This is here temporarily while we have
// both GPU store and cache. When the GPU
// store code is removed, we can change the
// PrimitiveInstance instance structure to
// use 2x unsigned shorts as vertex attributes
// instead of an int, and encode the UV directly
// in the vertices.
@@ -66,17 +64,17 @@ vec4[2] fetch_from_resource_cache_2(int
return vec4[2](
TEXEL_FETCH(sResourceCache, uv, 0, ivec2(0, 0)),
TEXEL_FETCH(sResourceCache, uv, 0, ivec2(1, 0))
);
}
#ifdef WR_VERTEX_SHADER
-#define VECS_PER_LAYER 10
+#define VECS_PER_LAYER 11
#define VECS_PER_RENDER_TASK 3
#define VECS_PER_PRIM_HEADER 2
#define VECS_PER_TEXT_RUN 3
#define VECS_PER_GRADIENT 3
#define VECS_PER_GRADIENT_STOP 2
uniform HIGHP_SAMPLER_FLOAT sampler2D sClipScrollNodes;
uniform HIGHP_SAMPLER_FLOAT sampler2D sRenderTasks;
@@ -144,16 +142,17 @@ vec4 fetch_from_resource_cache_1(int add
}
struct ClipScrollNode {
mat4 transform;
mat4 inv_transform;
vec4 local_clip_rect;
vec2 reference_frame_relative_scroll_offset;
vec2 scroll_offset;
+ bool is_axis_aligned;
};
ClipScrollNode fetch_clip_scroll_node(int index) {
ClipScrollNode node;
// Create a UV base coord for each 8 texels.
// This is required because trying to use an offset
// of more than 8 texels doesn't work on some versions
@@ -174,39 +173,44 @@ ClipScrollNode fetch_clip_scroll_node(in
vec4 clip_rect = TEXEL_FETCH(sClipScrollNodes, uv1, 0, ivec2(0, 0));
node.local_clip_rect = clip_rect;
vec4 offsets = TEXEL_FETCH(sClipScrollNodes, uv1, 0, ivec2(1, 0));
node.reference_frame_relative_scroll_offset = offsets.xy;
node.scroll_offset = offsets.zw;
+ vec4 misc = TEXEL_FETCH(sClipScrollNodes, uv1, 0, ivec2(2, 0));
+ node.is_axis_aligned = misc.x == 0.0;
+
return node;
}
struct Layer {
mat4 transform;
mat4 inv_transform;
RectWithSize local_clip_rect;
+ bool is_axis_aligned;
};
Layer fetch_layer(int clip_node_id, int scroll_node_id) {
ClipScrollNode clip_node = fetch_clip_scroll_node(clip_node_id);
ClipScrollNode scroll_node = fetch_clip_scroll_node(scroll_node_id);
Layer layer;
layer.transform = scroll_node.transform;
layer.inv_transform = scroll_node.inv_transform;
vec4 local_clip_rect = clip_node.local_clip_rect;
local_clip_rect.xy += clip_node.reference_frame_relative_scroll_offset;
local_clip_rect.xy -= scroll_node.reference_frame_relative_scroll_offset;
local_clip_rect.xy -= scroll_node.scroll_offset;
layer.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw);
+ layer.is_axis_aligned = scroll_node.is_axis_aligned;
return layer;
}
struct RenderTaskCommonData {
RectWithSize task_rect;
float texture_layer_index;
};
@@ -610,18 +614,16 @@ VertexInfo write_vertex(RectWithSize ins
task.common_data.task_rect.p0;
gl_Position = uTransform * vec4(final_pos, z, 1.0);
VertexInfo vi = VertexInfo(clamped_local_pos, device_pos);
return vi;
}
-#ifdef WR_FEATURE_TRANSFORM
-
float cross2(vec2 v0, vec2 v1) {
return v0.x * v1.y - v0.y * v1.x;
}
// Return intersection of line (p0,p1) and line (p2,p3)
vec2 intersect_lines(vec2 p0, vec2 p1, vec2 p2, vec2 p3) {
vec2 d0 = p0 - p1;
vec2 d1 = p2 - p3;
@@ -631,46 +633,52 @@ vec2 intersect_lines(vec2 p0, vec2 p1, v
float d = cross2(d0, d1);
float nx = s0 * d1.x - d0.x * s1;
float ny = s0 * d1.y - d0.y * s1;
return vec2(nx / d, ny / d);
}
-VertexInfo write_transform_vertex(RectWithSize instance_rect,
+VertexInfo write_transform_vertex(RectWithSize local_segment_rect,
+ RectWithSize local_prim_rect,
RectWithSize local_clip_rect,
vec4 clip_edge_mask,
float z,
Layer layer,
PictureTask task) {
// Calculate a clip rect from local clip + layer clip.
RectWithEndpoint clip_rect = to_rect_with_endpoint(local_clip_rect);
clip_rect.p0 = clamp_rect(clip_rect.p0, layer.local_clip_rect);
clip_rect.p1 = clamp_rect(clip_rect.p1, layer.local_clip_rect);
// Calculate a clip rect from local_rect + local clip + layer clip.
- RectWithEndpoint local_rect = to_rect_with_endpoint(instance_rect);
- local_rect.p0 = clamp(local_rect.p0, clip_rect.p0, clip_rect.p1);
- local_rect.p1 = clamp(local_rect.p1, clip_rect.p0, clip_rect.p1);
+ RectWithEndpoint segment_rect = to_rect_with_endpoint(local_segment_rect);
+ segment_rect.p0 = clamp(segment_rect.p0, clip_rect.p0, clip_rect.p1);
+ segment_rect.p1 = clamp(segment_rect.p1, clip_rect.p0, clip_rect.p1);
+
+ // Calculate a clip rect from local_rect + local clip + layer clip.
+ RectWithEndpoint prim_rect = to_rect_with_endpoint(local_prim_rect);
+ prim_rect.p0 = clamp(prim_rect.p0, clip_rect.p0, clip_rect.p1);
+ prim_rect.p1 = clamp(prim_rect.p1, clip_rect.p0, clip_rect.p1);
// As this is a transform shader, extrude by 2 (local space) pixels
// in each direction. This gives enough space around the edge to
// apply distance anti-aliasing. Technically, it:
// (a) slightly over-estimates the number of required pixels in the simple case.
// (b) might not provide enough edge in edge case perspective projections.
// However, it's fast and simple. If / when we ever run into issues, we
// can do some math on the projection matrix to work out a variable
// amount to extrude.
float extrude_distance = 2.0;
- instance_rect.p0 -= vec2(extrude_distance);
- instance_rect.size += vec2(2.0 * extrude_distance);
+ local_segment_rect.p0 -= vec2(extrude_distance);
+ local_segment_rect.size += vec2(2.0 * extrude_distance);
// Select the corner of the local rect that we are processing.
- vec2 local_pos = instance_rect.p0 + instance_rect.size * aPosition.xy;
+ vec2 local_pos = local_segment_rect.p0 + local_segment_rect.size * aPosition.xy;
// Transform the current vertex to the world cpace.
vec4 world_pos = layer.transform * vec4(local_pos, 0.0, 1.0);
// Convert the world positions to device pixel space.
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
// We want the world space coords to be perspective divided by W.
@@ -678,38 +686,37 @@ VertexInfo write_transform_vertex(RectWi
// want a constant Z across the primitive, since we're using it
// for draw ordering - so scale by the W coord to ensure this.
vec4 final_pos = vec4(world_pos.xy + task.common_data.task_rect.p0 - task.content_origin,
z * world_pos.w,
world_pos.w);
gl_Position = uTransform * final_pos;
vLocalBounds = mix(
- vec4(clip_rect.p0, clip_rect.p1),
- vec4(local_rect.p0, local_rect.p1),
+ vec4(prim_rect.p0, prim_rect.p1),
+ vec4(segment_rect.p0, segment_rect.p1),
clip_edge_mask
);
VertexInfo vi = VertexInfo(local_pos, device_pos);
return vi;
}
VertexInfo write_transform_vertex_primitive(Primitive prim) {
return write_transform_vertex(
prim.local_rect,
+ prim.local_rect,
prim.local_clip_rect,
- vec4(1.0),
+ vec4(0.0),
prim.z,
prim.layer,
prim.task
);
}
-#endif //WR_FEATURE_TRANSFORM
-
struct GlyphResource {
vec4 uv_rect;
float layer;
vec2 offset;
float scale;
};
GlyphResource fetch_glyph_resource(int address) {
@@ -804,17 +811,16 @@ float compute_aa_range(vec2 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);
return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y));
}
float init_transform_fs(vec2 local_pos) {
// Get signed distance from local rect bounds.
float d = signed_distance_rect(
@@ -824,17 +830,16 @@ float init_transform_fs(vec2 local_pos)
);
// Find the appropriate distance to apply the AA smoothstep over.
float aa_range = compute_aa_range(local_pos);
// Only apply AA to fragments outside the signed distance field.
return distance_aa(aa_range, d);
}
-#endif //WR_FEATURE_TRANSFORM
float do_clip() {
// anything outside of the mask is considered transparent
bvec4 inside = lessThanEqual(
vec4(vClipMaskUvBounds.xy, vClipMaskUv.xy),
vec4(vClipMaskUv.xy, vClipMaskUvBounds.zw));
// check for the dummy bounds, which are given to the opaque objects
return vClipMaskUvBounds.xy == vClipMaskUvBounds.zw ? 1.0:
--- a/gfx/webrender/res/ps_border_corner.glsl
+++ b/gfx/webrender/res/ps_border_corner.glsl
@@ -294,16 +294,17 @@ void main(void) {
write_color(color0, color1, style, color_delta, prim.user_data1);
RectWithSize segment_rect;
segment_rect.p0 = p0;
segment_rect.size = p1 - p0;
#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex(segment_rect,
+ prim.local_rect,
prim.local_clip_rect,
vec4(1.0),
prim.z,
prim.layer,
prim.task);
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,
--- a/gfx/webrender/res/ps_border_edge.glsl
+++ b/gfx/webrender/res/ps_border_edge.glsl
@@ -212,16 +212,17 @@ void main(void) {
}
write_alpha_select(style);
write_color0(color, style, color_flip);
write_color1(color, style, color_flip);
#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex(segment_rect,
+ prim.local_rect,
prim.local_clip_rect,
vec4(1.0),
prim.z,
prim.layer,
prim.task);
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,
--- a/gfx/webrender/res/ps_composite.glsl
+++ b/gfx/webrender/res/ps_composite.glsl
@@ -202,29 +202,29 @@ const int MixBlendMode_Hue = 12;
const int MixBlendMode_Saturation = 13;
const int MixBlendMode_Color = 14;
const int MixBlendMode_Luminosity = 15;
void main(void) {
vec4 Cb = texture(sCacheRGBA8, vUv0);
vec4 Cs = texture(sCacheRGBA8, vUv1);
- // The mix-blend-mode functions assume no premultiplied alpha
- Cb.rgb /= Cb.a;
- Cs.rgb /= Cs.a;
-
if (Cb.a == 0.0) {
oFragColor = Cs;
return;
}
if (Cs.a == 0.0) {
oFragColor = vec4(0.0, 0.0, 0.0, 0.0);
return;
}
+ // The mix-blend-mode functions assume no premultiplied alpha
+ Cb.rgb /= Cb.a;
+ Cs.rgb /= Cs.a;
+
// Return yellow if none of the branches match (shouldn't happen).
vec4 result = vec4(1.0, 1.0, 0.0, 1.0);
switch (vOp) {
case MixBlendMode_Multiply:
result.rgb = Multiply(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Screen:
--- a/gfx/webrender/res/ps_gradient.glsl
+++ b/gfx/webrender/res/ps_gradient.glsl
@@ -63,16 +63,17 @@ void main(void) {
// Adjust the stop colors by how much they were clamped
vec2 adjusted_offset = (g01_y_clamped - g01_y.xx) / (g01_y.y - g01_y.x);
adjusted_color_g0 = mix(g0.color, g1.color, adjusted_offset.x);
adjusted_color_g1 = mix(g0.color, g1.color, adjusted_offset.y);
}
#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex(segment_rect,
+ prim.local_rect,
prim.local_clip_rect,
vec4(1.0),
prim.z,
prim.layer,
prim.task);
vLocalPos = vi.local_pos;
vec2 f = (vi.local_pos.xy - prim.local_rect.p0) / prim.local_rect.size;
#else
--- a/gfx/webrender/res/ps_rectangle.glsl
+++ b/gfx/webrender/res/ps_rectangle.glsl
@@ -12,16 +12,17 @@ varying vec2 vLocalPos;
#ifdef WR_VERTEX_SHADER
void main(void) {
Primitive prim = load_primitive();
Rectangle rect = fetch_rectangle(prim.specific_prim_address);
vColor = rect.color;
#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex(prim.local_rect,
+ prim.local_rect,
prim.local_clip_rect,
rect.edge_aa_segment_mask,
prim.z,
prim.layer,
prim.task);
vLocalPos = vi.local_pos;
#else
VertexInfo vi = write_vertex(prim.local_rect,
--- a/gfx/webrender/src/clip.rs
+++ b/gfx/webrender/src/clip.rs
@@ -98,25 +98,27 @@ impl From<ClipRegion> for ClipSources {
}
ClipSources::new(clips)
}
}
impl ClipSource {
pub fn contains(&self, point: &LayerPoint) -> bool {
- // We currently do not handle all types of clip sources, because they
- // aren't used for ClipScrollNodes and this method is only used during hit testing.
+ // We currently do not handle all BorderCorners, because they aren't used for
+ // ClipScrollNodes and this method is only used during hit testing.
match self {
&ClipSource::Rectangle(ref rectangle) => rectangle.contains(point),
&ClipSource::RoundedRectangle(rect, radii, ClipMode::Clip) =>
rounded_rectangle_contains_point(point, &rect, &radii),
&ClipSource::RoundedRectangle(rect, radii, ClipMode::ClipOut) =>
!rounded_rectangle_contains_point(point, &rect, &radii),
- _ => unreachable!("Tried to call contains on an unsupported ClipSource."),
+ &ClipSource::Image(mask) => mask.rect.contains(point),
+ &ClipSource::BorderCorner(_) =>
+ unreachable!("Tried to call contains on a BorderCornerr."),
}
}
}
#[derive(Debug)]
pub struct ClipSources {
pub clips: Vec<(ClipSource, GpuCacheHandle)>,
--- a/gfx/webrender/src/clip_scroll_node.rs
+++ b/gfx/webrender/src/clip_scroll_node.rs
@@ -12,17 +12,17 @@ use euclid::SideOffsets2D;
use geometry::ray_intersects_rect;
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use render_task::{ClipChain, ClipChainNode, ClipWorkItem};
use resource_cache::ResourceCache;
use scene::SceneProperties;
use spring::{DAMPING, STIFFNESS, Spring};
use std::rc::Rc;
-use util::{MatrixHelpers, MaxRect};
+use util::{MatrixHelpers, MaxRect, TransformedRectKind};
#[cfg(target_os = "macos")]
const CAN_OVERSCROLL: bool = true;
#[cfg(not(target_os = "macos"))]
const CAN_OVERSCROLL: bool = false;
const MAX_LOCAL_VIEWPORT: f32 = 1000000.0;
@@ -299,23 +299,31 @@ impl ClipScrollNode {
LayerSize::new(2.0 * MAX_LOCAL_VIEWPORT, 2.0 * MAX_LOCAL_VIEWPORT)
)
} else {
self.combined_local_viewport_rect
};
let data = match self.world_content_transform.inverse() {
Some(inverse) => {
+ let transform_kind = if self.world_content_transform.preserves_2d_axis_alignment() {
+ TransformedRectKind::AxisAligned
+ } else {
+ TransformedRectKind::Complex
+ };
+
ClipScrollNodeData {
transform: self.world_content_transform,
inv_transform: inverse,
local_clip_rect,
reference_frame_relative_scroll_offset:
self.reference_frame_relative_scroll_offset,
scroll_offset: self.scroll_offset(),
+ transform_kind: transform_kind as u32 as f32,
+ padding: [0.0; 3],
}
}
None => {
state.combined_outer_clip_bounds = DeviceIntRect::zero();
self.combined_clip_outer_bounds = DeviceIntRect::zero();
ClipScrollNodeData::invalid()
}
};
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -386,17 +386,16 @@ impl ExternalTexture {
pub struct Texture {
id: gl::GLuint,
target: gl::GLuint,
layer_count: i32,
format: ImageFormat,
width: u32,
height: u32,
-
filter: TextureFilter,
render_target: Option<RenderTargetInfo>,
fbo_ids: Vec<FBOId>,
depth_rb: Option<RBOId>,
}
impl Texture {
pub fn get_dimensions(&self) -> DeviceUintSize {
@@ -406,16 +405,20 @@ impl Texture {
pub fn get_render_target_layer_count(&self) -> usize {
self.fbo_ids.len()
}
pub fn get_layer_count(&self) -> i32 {
self.layer_count
}
+ pub fn get_format(&self) -> ImageFormat {
+ self.format
+ }
+
pub fn get_bpp(&self) -> u32 {
match self.format {
ImageFormat::A8 => 1,
ImageFormat::RGB8 => 3,
ImageFormat::BGRA8 => 4,
ImageFormat::RG8 => 2,
ImageFormat::RGBAF32 => 16,
ImageFormat::Invalid => unreachable!(),
@@ -880,37 +883,39 @@ impl Device {
format: ImageFormat,
filter: TextureFilter,
render_target: Option<RenderTargetInfo>,
layer_count: i32,
pixels: Option<&[u8]>,
) {
debug_assert!(self.inside_frame);
- let resized = texture.width != width || texture.height != height;
+ let resized = texture.width != width ||
+ texture.height != height ||
+ texture.format != format;
texture.format = format;
texture.width = width;
texture.height = height;
texture.filter = filter;
texture.layer_count = layer_count;
texture.render_target = render_target;
- let (internal_format, gl_format) = gl_texture_formats_for_image_format(self.gl(), format);
- let type_ = gl_type_for_texture_format(format);
-
self.bind_texture(DEFAULT_TEXTURE, texture);
self.set_texture_parameters(texture.target, filter);
match render_target {
Some(info) => {
assert!(pixels.is_none());
self.update_texture_storage(texture, &info, resized);
}
None => {
+ let (internal_format, gl_format) = gl_texture_formats_for_image_format(self.gl(), format);
+ let type_ = gl_type_for_texture_format(format);
+
let expanded_data: Vec<u8>;
let actual_pixels = if pixels.is_some() && format == ImageFormat::A8 &&
cfg!(any(target_arch = "arm", target_arch = "aarch64"))
{
expanded_data = pixels
.unwrap()
.iter()
.flat_map(|&byte| repeat(byte).take(4))
--- a/gfx/webrender/src/glyph_rasterizer.rs
+++ b/gfx/webrender/src/glyph_rasterizer.rs
@@ -174,33 +174,35 @@ impl FontInstance {
pub fn get_subpx_offset(&self, glyph: &GlyphKey) -> (f64, f64) {
match self.subpx_dir {
SubpixelDirection::None => (0.0, 0.0),
SubpixelDirection::Horizontal => (glyph.subpixel_offset.into(), 0.0),
SubpixelDirection::Vertical => (0.0, glyph.subpixel_offset.into()),
}
}
- pub fn get_subpixel_glyph_format(&self) -> GlyphFormat {
- if self.transform.is_identity() { GlyphFormat::Subpixel } else { GlyphFormat::TransformedSubpixel }
- }
-
- #[allow(dead_code)]
- pub fn get_glyph_format(&self) -> GlyphFormat {
+ pub fn get_glyph_format(&self, color_bitmaps: bool) -> GlyphFormat {
match self.render_mode {
- FontRenderMode::Mono | FontRenderMode::Alpha => GlyphFormat::Alpha,
- FontRenderMode::Subpixel => self.get_subpixel_glyph_format(),
- FontRenderMode::Bitmap => GlyphFormat::ColorBitmap,
+ FontRenderMode::Mono | FontRenderMode::Alpha => {
+ if self.transform.is_identity() { GlyphFormat::Alpha } else { GlyphFormat::TransformedAlpha }
+ }
+ FontRenderMode::Subpixel => {
+ if self.transform.is_identity() { GlyphFormat::Subpixel } else { GlyphFormat::TransformedSubpixel }
+ }
+ FontRenderMode::Bitmap => {
+ if color_bitmaps { GlyphFormat::ColorBitmap } else { GlyphFormat::Alpha }
+ }
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum GlyphFormat {
Alpha,
+ TransformedAlpha,
Subpixel,
TransformedSubpixel,
ColorBitmap,
}
pub struct RasterizedGlyph {
pub top: f32,
pub left: f32,
--- a/gfx/webrender/src/gpu_types.rs
+++ b/gfx/webrender/src/gpu_types.rs
@@ -193,21 +193,25 @@ pub struct ClipScrollNodeIndex(pub u32);
#[derive(Debug)]
#[repr(C)]
pub struct ClipScrollNodeData {
pub transform: LayerToWorldTransform,
pub inv_transform: WorldToLayerTransform,
pub local_clip_rect: LayerRect,
pub reference_frame_relative_scroll_offset: LayerVector2D,
pub scroll_offset: LayerVector2D,
+ pub transform_kind: f32,
+ pub padding: [f32; 3],
}
impl ClipScrollNodeData {
pub fn invalid() -> ClipScrollNodeData {
ClipScrollNodeData {
transform: LayerToWorldTransform::identity(),
inv_transform: WorldToLayerTransform::identity(),
local_clip_rect: LayerRect::zero(),
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
scroll_offset: LayerVector2D::zero(),
+ transform_kind: 0.0,
+ padding: [0.0; 3],
}
}
}
--- a/gfx/webrender/src/picture.rs
+++ b/gfx/webrender/src/picture.rs
@@ -35,17 +35,17 @@ pub enum PictureCompositeMode {
/// Draw to intermediate surface, copy straight across. This
/// is used for CSS isolation, and plane splitting.
Blit,
}
/// Configure whether the primitives on this picture
/// should be rasterized in screen space or local space.
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum RasterizationSpace {
Local = 0,
Screen = 1,
}
#[derive(Debug)]
pub enum PictureKind {
TextShadow {
--- a/gfx/webrender/src/platform/macos/font.rs
+++ b/gfx/webrender/src/platform/macos/font.rs
@@ -652,13 +652,13 @@ impl FontContext {
}
Some(RasterizedGlyph {
left: metrics.rasterized_left as f32,
top: metrics.rasterized_ascent as f32,
width: metrics.rasterized_width,
height: metrics.rasterized_height,
scale: 1.0,
- format: font.get_glyph_format(),
+ format: font.get_glyph_format(true),
bytes: rasterized_pixels,
})
}
}
--- a/gfx/webrender/src/platform/unix/font.rs
+++ b/gfx/webrender/src/platform/unix/font.rs
@@ -14,17 +14,17 @@ use freetype::freetype::{FT_F26Dot6, FT_
use freetype::freetype::{FT_GlyphSlot, FT_LcdFilter, FT_New_Face, FT_New_Memory_Face};
use freetype::freetype::{FT_Init_FreeType, FT_Load_Glyph, FT_Render_Glyph};
use freetype::freetype::{FT_Library, FT_Outline_Get_CBox, FT_Set_Char_Size, FT_Select_Size};
use freetype::freetype::{FT_Fixed, FT_Matrix, FT_Set_Transform};
use freetype::freetype::{FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_LOAD_FORCE_AUTOHINT};
use freetype::freetype::{FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH, FT_LOAD_NO_AUTOHINT};
use freetype::freetype::{FT_LOAD_NO_BITMAP, FT_LOAD_NO_HINTING, FT_LOAD_VERTICAL_LAYOUT};
use freetype::freetype::{FT_FACE_FLAG_SCALABLE, FT_FACE_FLAG_FIXED_SIZES, FT_Err_Cannot_Render_Glyph};
-use glyph_rasterizer::{FontInstance, GlyphFormat, RasterizedGlyph};
+use glyph_rasterizer::{FontInstance, RasterizedGlyph};
use internal_types::FastHashMap;
use std::{cmp, mem, ptr, slice};
use std::cmp::max;
use std::ffi::CString;
use std::sync::Arc;
// These constants are not present in the freetype
// bindings due to bindgen not handling the way
@@ -529,33 +529,29 @@ impl FontContext {
let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
info!(
"Rasterizing {:?} as {:?} with dimensions {:?}",
key,
font.render_mode,
dimensions
);
- let (format, actual_width, actual_height) = match pixel_mode {
+ let (actual_width, actual_height) = match pixel_mode {
FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
assert!(bitmap.width % 3 == 0);
- (font.get_subpixel_glyph_format(), (bitmap.width / 3) as i32, bitmap.rows as i32)
+ ((bitmap.width / 3) as i32, bitmap.rows as i32)
}
FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V => {
assert!(bitmap.rows % 3 == 0);
- (font.get_subpixel_glyph_format(), bitmap.width as i32, (bitmap.rows / 3) as i32)
- }
- FT_Pixel_Mode::FT_PIXEL_MODE_MONO => {
- (GlyphFormat::Alpha, bitmap.width as i32, bitmap.rows as i32)
+ (bitmap.width as i32, (bitmap.rows / 3) as i32)
}
- FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
- (GlyphFormat::Alpha, bitmap.width as i32, bitmap.rows as i32)
- }
+ FT_Pixel_Mode::FT_PIXEL_MODE_MONO |
+ FT_Pixel_Mode::FT_PIXEL_MODE_GRAY |
FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
- (GlyphFormat::ColorBitmap, bitmap.width as i32, bitmap.rows as i32)
+ (bitmap.width as i32, bitmap.rows as i32)
}
_ => panic!("Unsupported {:?}", pixel_mode),
};
let (left, top) = unsafe { ((*slot).bitmap_left, (*slot).bitmap_top) };
let mut final_buffer = vec![0; (actual_width * actual_height * 4) as usize];
// Extract the final glyph from FT format into RGBA8 format, which is
// what WR expects.
@@ -639,17 +635,17 @@ impl FontContext {
}
Some(RasterizedGlyph {
left: (dimensions.left + left) as f32,
top: (dimensions.top + top - actual_height) as f32,
width: actual_width as u32,
height: actual_height as u32,
scale,
- format,
+ format: font.get_glyph_format(pixel_mode == FT_Pixel_Mode::FT_PIXEL_MODE_BGRA),
bytes: final_buffer,
})
}
}
impl Drop for FontContext {
fn drop(&mut self) {
unsafe {
--- a/gfx/webrender/src/platform/windows/font.rs
+++ b/gfx/webrender/src/platform/windows/font.rs
@@ -26,51 +26,53 @@ pub struct FontContext {
}
// DirectWrite is safe to use on multiple threads and non-shareable resources are
// all hidden inside their font context.
unsafe impl Send for FontContext {}
fn dwrite_texture_type(render_mode: FontRenderMode) -> dwrote::DWRITE_TEXTURE_TYPE {
match render_mode {
- FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_TEXTURE_ALIASED_1x1,
- FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1,
+ FontRenderMode::Mono => dwrote::DWRITE_TEXTURE_ALIASED_1x1,
+ FontRenderMode::Bitmap |
+ FontRenderMode::Alpha |
+ FontRenderMode::Subpixel => dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1,
}
}
fn dwrite_measure_mode(
render_mode: FontRenderMode,
options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_MEASURING_MODE {
- let FontInstancePlatformOptions { force_gdi_rendering, use_embedded_bitmap, .. } =
+ let FontInstancePlatformOptions { force_gdi_rendering, .. } =
options.unwrap_or_default();
- if force_gdi_rendering || use_embedded_bitmap {
- return dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC;
- }
-
- match render_mode {
- FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
- FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_MEASURING_MODE_NATURAL,
+ if force_gdi_rendering {
+ dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC
+ } else {
+ match render_mode {
+ FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC,
+ FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_MEASURING_MODE_NATURAL,
+ }
}
}
fn dwrite_render_mode(
font_face: &dwrote::FontFace,
render_mode: FontRenderMode,
em_size: f32,
measure_mode: dwrote::DWRITE_MEASURING_MODE,
options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_RENDERING_MODE {
- let FontInstancePlatformOptions { force_gdi_rendering, use_embedded_bitmap, .. } =
- options.unwrap_or_default();
-
let dwrite_render_mode = match render_mode {
- FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_RENDERING_MODE_ALIASED,
+ FontRenderMode::Bitmap => dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC,
+ FontRenderMode::Mono => dwrote::DWRITE_RENDERING_MODE_ALIASED,
FontRenderMode::Alpha | FontRenderMode::Subpixel => {
- if force_gdi_rendering || use_embedded_bitmap {
+ let FontInstancePlatformOptions { force_gdi_rendering, .. } =
+ options.unwrap_or_default();
+ if force_gdi_rendering {
dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC
} else {
font_face.get_recommended_rendering_mode_default_params(em_size, 1.0, measure_mode)
}
}
};
if dwrite_render_mode == dwrote::DWRITE_RENDERING_MODE_OUTLINE {
@@ -252,31 +254,28 @@ impl FontContext {
advance: advance,
}
})
}
// DWrite ClearType gives us values in RGB, but WR expects BGRA.
fn convert_to_bgra(&self, pixels: &[u8], render_mode: FontRenderMode) -> Vec<u8> {
match render_mode {
- FontRenderMode::Bitmap => {
- unreachable!("TODO: bitmap fonts");
- }
FontRenderMode::Mono => {
let mut bgra_pixels: Vec<u8> = vec![0; pixels.len() * 4];
for i in 0 .. pixels.len() {
let alpha = pixels[i];
bgra_pixels[i * 4 + 0] = alpha;
bgra_pixels[i * 4 + 1] = alpha;
bgra_pixels[i * 4 + 2] = alpha;
bgra_pixels[i * 4 + 3] = alpha;
}
bgra_pixels
}
- FontRenderMode::Alpha => {
+ FontRenderMode::Alpha | FontRenderMode::Bitmap => {
let length = pixels.len() / 3;
let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
for i in 0 .. length {
// Only take the G channel, as its closest to D2D
let alpha = pixels[i * 3 + 1] as u8;
bgra_pixels[i * 4 + 0] = alpha;
bgra_pixels[i * 4 + 1] = alpha;
bgra_pixels[i * 4 + 2] = alpha;
@@ -293,19 +292,21 @@ impl FontContext {
bgra_pixels[i * 4 + 2] = pixels[i * 3 + 0];
bgra_pixels[i * 4 + 3] = 0xff;
}
bgra_pixels
}
}
}
- pub fn is_bitmap_font(&mut self, _font: &FontInstance) -> bool {
- // TODO(gw): Support bitmap fonts in DWrite.
- false
+ pub fn is_bitmap_font(&mut self, font: &FontInstance) -> bool {
+ // If bitmaps are requested, then treat as a bitmap font to disable transforms.
+ // If mono AA is requested, let that take priority over using bitmaps.
+ font.render_mode != FontRenderMode::Mono &&
+ font.platform_options.unwrap_or_default().use_embedded_bitmap
}
pub fn prepare_font(font: &mut FontInstance) {
match font.render_mode {
FontRenderMode::Mono | FontRenderMode::Bitmap => {
// In mono/bitmap modes the color of the font is irrelevant.
font.color = ColorU::new(255, 255, 255, 255);
// Subpixel positioning is disabled in mono and bitmap modes.
@@ -336,35 +337,33 @@ impl FontContext {
// Such as for spaces
if width == 0 || height == 0 {
return None;
}
let pixels = analysis.create_alpha_texture(texture_type, bounds);
let mut bgra_pixels = self.convert_to_bgra(&pixels, font.render_mode);
- match font.render_mode {
- FontRenderMode::Mono | FontRenderMode::Bitmap => {}
+ let lut_correction = match font.render_mode {
+ FontRenderMode::Mono | FontRenderMode::Bitmap => &self.gdi_gamma_lut,
FontRenderMode::Alpha | FontRenderMode::Subpixel => {
- let lut_correction = match font.platform_options {
- Some(option) => if option.force_gdi_rendering {
- &self.gdi_gamma_lut
- } else {
- &self.gamma_lut
- },
- None => &self.gamma_lut,
- };
-
- lut_correction.preblend(&mut bgra_pixels, font.color);
+ let FontInstancePlatformOptions { force_gdi_rendering, .. } =
+ font.platform_options.unwrap_or_default();
+ if force_gdi_rendering {
+ &self.gdi_gamma_lut
+ } else {
+ &self.gamma_lut
+ }
}
- }
+ };
+ lut_correction.preblend(&mut bgra_pixels, font.color);
Some(RasterizedGlyph {
left: bounds.left as f32,
top: -bounds.top as f32,
width,
height,
scale: 1.0,
- format: font.get_glyph_format(),
+ format: font.get_glyph_format(false),
bytes: bgra_pixels,
})
}
}
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -594,25 +594,23 @@ impl TextRunPrimitiveCpu {
pub fn get_font(
&self,
device_pixel_ratio: f32,
transform: &LayerToWorldTransform,
rasterization_kind: RasterizationSpace,
) -> FontInstance {
let mut font = self.font.clone();
font.size = font.size.scale_by(device_pixel_ratio);
- match (font.render_mode, rasterization_kind) {
- (FontRenderMode::Subpixel, RasterizationSpace::Screen) => {
- if transform.has_perspective_component() || !transform.has_2d_inverse() {
- font.render_mode = FontRenderMode::Alpha;
- } else {
- font.transform = FontTransform::from(transform).quantize();
- }
+ if font.render_mode != FontRenderMode::Bitmap &&
+ rasterization_kind == RasterizationSpace::Screen {
+ if transform.has_perspective_component() || !transform.has_2d_inverse() {
+ font.render_mode = font.render_mode.limit_by(FontRenderMode::Alpha);
+ } else {
+ font.transform = FontTransform::from(transform).quantize();
}
- _ => {}
}
font
}
fn prepare_for_render(
&mut self,
resource_cache: &mut ResourceCache,
device_pixel_ratio: f32,
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -277,17 +277,17 @@ impl Into<ShaderMode> for TextShaderMode
fn into(self) -> i32 {
self as i32
}
}
impl From<GlyphFormat> for TextShaderMode {
fn from(format: GlyphFormat) -> TextShaderMode {
match format {
- GlyphFormat::Alpha => TextShaderMode::Alpha,
+ GlyphFormat::Alpha | GlyphFormat::TransformedAlpha => TextShaderMode::Alpha,
GlyphFormat::Subpixel | GlyphFormat::TransformedSubpixel => {
panic!("Subpixel glyph formats must be handled separately.");
}
GlyphFormat::ColorBitmap => TextShaderMode::ColorBitmap,
}
}
}
@@ -595,22 +595,21 @@ impl SourceTextureResolver {
device.delete_texture(texture);
}
}
fn end_pass(
&mut self,
a8_texture: Option<Texture>,
rgba8_texture: Option<Texture>,
- a8_pool: &mut Vec<Texture>,
- rgba8_pool: &mut Vec<Texture>,
+ pool: &mut Vec<Texture>,
) {
// If we have cache textures from previous pass, return them to the pool.
- rgba8_pool.extend(self.cache_rgba8_texture.take());
- a8_pool.extend(self.cache_a8_texture.take());
+ pool.extend(self.cache_rgba8_texture.take());
+ pool.extend(self.cache_a8_texture.take());
// We have another pass to process, make these textures available
// as inputs to the next pass.
self.cache_rgba8_texture = rgba8_texture;
self.cache_a8_texture = a8_texture;
}
// Bind a source texture to the device.
@@ -1187,16 +1186,17 @@ impl TextShader {
TransformedRectKind::AxisAligned => {
self.simple.bind(device, projection, mode, renderer_errors)
}
TransformedRectKind::Complex => {
self.transform.bind(device, projection, mode, renderer_errors)
}
}
}
+ GlyphFormat::TransformedAlpha |
GlyphFormat::TransformedSubpixel => {
self.glyph_transform.bind(device, projection, mode, renderer_errors)
}
}
}
fn deinit(self, device: &mut Device) {
self.simple.deinit(device);
@@ -1296,16 +1296,23 @@ pub enum ReadPixelsFormat {
Bgra8,
}
struct FrameOutput {
last_access: FrameId,
fbo_id: FBOId,
}
+#[derive(PartialEq)]
+struct TargetSelector {
+ size: DeviceUintSize,
+ num_layers: usize,
+ format: ImageFormat,
+}
+
/// The renderer is responsible for submitting to the GPU the work prepared by the
/// RenderBackend.
pub struct Renderer {
result_rx: Receiver<ResultMsg>,
debug_server: DebugServer,
device: Device,
pending_texture_updates: Vec<TextureUpdateList>,
pending_gpu_cache_updates: Vec<GpuCacheUpdateList>,
@@ -1365,18 +1372,17 @@ pub struct Renderer {
enable_clear_scissor: bool,
debug: DebugRenderer,
debug_flags: DebugFlags,
backend_profile_counters: BackendProfileCounters,
profile_counters: RendererProfileCounters,
profiler: Profiler,
last_time: u64,
- color_render_targets: Vec<Texture>,
- alpha_render_targets: Vec<Texture>,
+ render_target_pool: Vec<Texture>,
gpu_profile: GpuProfiler<GpuProfileTag>,
prim_vao: VAO,
blur_vao: VAO,
clip_vao: VAO,
node_data_texture: VertexDataTexture,
render_task_texture: VertexDataTexture,
@@ -2006,18 +2012,17 @@ impl Renderer {
backend_profile_counters: BackendProfileCounters::new(),
profile_counters: RendererProfileCounters::new(),
profiler: Profiler::new(),
max_texture_size: max_texture_size,
max_recorded_profiles: options.max_recorded_profiles,
clear_color: options.clear_color,
enable_clear_scissor: options.enable_clear_scissor,
last_time: 0,
- color_render_targets: Vec::new(),
- alpha_render_targets: Vec::new(),
+ render_target_pool: Vec::new(),
gpu_profile,
prim_vao,
blur_vao,
clip_vao,
node_data_texture,
render_task_texture,
pipeline_epoch_map: FastHashMap::default(),
dither_matrix_texture,
@@ -2383,16 +2388,22 @@ impl Renderer {
});
// don't clear the framebuffer if one of the rendered documents will overwrite it
if needs_clear {
let clear_color = self.clear_color.map(|color| color.to_array());
self.device.bind_draw_target(None, None);
self.device.clear_target(clear_color, None);
}
+ // Re-use whatever targets possible from the pool, before
+ // they get changed/re-allocated by the rendered frames.
+ for doc_with_id in &mut active_documents {
+ self.prepare_tile_frame(&mut doc_with_id.1.frame);
+ }
+
for &mut (_, RenderedDocument { ref mut frame, .. }) in &mut active_documents {
self.update_gpu_cache(frame);
self.draw_tile_frame(frame, framebuffer_size, cpu_frame_id);
if self.debug_flags.contains(DebugFlags::PROFILER_DBG) {
frame_profiles.push(frame.profile_counters.clone());
}
@@ -3524,54 +3535,91 @@ impl Renderer {
for (ext_data, _) in self.texture_resolver.external_images.drain() {
handler.unlock(ext_data.0, ext_data.1);
}
}
}
fn prepare_target_list<T: RenderTarget>(
+ &mut self,
list: &mut RenderTargetList<T>,
- device: &mut Device,
- target_pool: &mut Vec<Texture>,
- format: ImageFormat,
+ perfect_only: bool,
) {
debug_assert_ne!(list.max_size, DeviceUintSize::zero());
- debug_assert!(list.texture.is_none());
if list.targets.is_empty() {
return;
}
- let mut texture = match target_pool.pop() {
- Some(texture) => texture,
- None => device.create_texture(TextureTarget::Array),
+ let mut texture = if perfect_only {
+ debug_assert!(list.texture.is_none());
+
+ let selector = TargetSelector {
+ size: list.max_size,
+ num_layers: list.targets.len() as _,
+ format: list.format,
+ };
+ let index = self.render_target_pool
+ .iter()
+ .position(|texture| {
+ selector == TargetSelector {
+ size: texture.get_dimensions(),
+ num_layers: texture.get_render_target_layer_count(),
+ format: texture.get_format(),
+ }
+ });
+ match index {
+ Some(pos) => self.render_target_pool.swap_remove(pos),
+ None => return,
+ }
+ } else {
+ if list.texture.is_some() {
+ return
+ }
+ match self.render_target_pool.pop() {
+ Some(texture) => texture,
+ None => self.device.create_texture(TextureTarget::Array),
+ }
};
- device.init_texture(
+
+ self.device.init_texture(
&mut texture,
list.max_size.width,
list.max_size.height,
- format,
+ list.format,
TextureFilter::Linear,
Some(RenderTargetInfo {
has_depth: list.needs_depth(),
}),
list.targets.len() as _,
None,
);
list.texture = Some(texture);
}
- fn prepare_frame(&mut self, frame: &mut Frame) {
+ fn prepare_tile_frame(&mut self, frame: &mut Frame) {
+ // Init textures and render targets to match this scene.
+ // First pass grabs all the perfectly matching targets from the pool.
+ for pass in &mut frame.passes {
+ if let RenderPassKind::OffScreen { ref mut alpha, ref mut color } = pass.kind {
+ self.prepare_target_list(alpha, true);
+ self.prepare_target_list(color, true);
+ }
+ }
+ }
+
+ fn bind_frame_data(&mut self, frame: &mut Frame) {
let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_DATA);
self.device.device_pixel_ratio = frame.device_pixel_ratio;
- // Init textures and render targets to match this scene.
+ // Some of the textures are already assigned by `prepare_frame`.
+ // Now re-allocate the space for the rest of the target textures.
for pass in &mut frame.passes {
if let RenderPassKind::OffScreen { ref mut alpha, ref mut color } = pass.kind {
- Self::prepare_target_list(alpha, &mut self.device, &mut self.alpha_render_targets, ImageFormat::A8);
- Self::prepare_target_list(color, &mut self.device, &mut self.color_render_targets, ImageFormat::BGRA8);
+ self.prepare_target_list(alpha, false);
+ self.prepare_target_list(color, false);
}
}
self.node_data_texture
.update(&mut self.device, &mut frame.node_data);
self.device
.bind_texture(TextureSampler::ClipScrollNodes, &self.node_data_texture.texture);
@@ -3597,20 +3645,17 @@ impl Renderer {
if frame.passes.is_empty() {
return;
}
self.device.disable_depth_write();
self.device.disable_stencil();
self.device.set_blend(false);
- self.prepare_frame(frame);
-
- let base_color_target_count = self.color_render_targets.len();
- let base_alpha_target_count = self.alpha_render_targets.len();
+ self.bind_frame_data(frame);
for (pass_index, pass) in frame.passes.iter_mut().enumerate() {
self.texture_resolver.bind(
&SourceTexture::CacheA8,
TextureSampler::CacheA8,
&mut self.device,
);
self.texture_resolver.bind(
@@ -3691,34 +3736,31 @@ impl Renderer {
(alpha.texture.take(), color.texture.take())
}
};
self.texture_resolver.end_pass(
cur_alpha,
cur_color,
- &mut self.alpha_render_targets,
- &mut self.color_render_targets,
+ &mut self.render_target_pool,
);
// After completing the first pass, make the A8 target available as an
// input to any subsequent passes.
if pass_index == 0 {
if let Some(shared_alpha_texture) =
self.texture_resolver.resolve(&SourceTexture::CacheA8)
{
self.device
.bind_texture(TextureSampler::SharedCacheA8, shared_alpha_texture);
}
}
}
- self.color_render_targets[base_color_target_count..].reverse();
- self.alpha_render_targets[base_alpha_target_count..].reverse();
self.draw_render_target_debug(framebuffer_size);
self.draw_texture_cache_debug(framebuffer_size);
// Garbage collect any frame outputs that weren't used this frame.
let device = &mut self.device;
self.output_targets
.retain(|_, target| if target.last_access != frame_id {
device.delete_fbo(target.fbo_id);
@@ -3774,33 +3816,29 @@ impl Renderer {
fn draw_render_target_debug(&mut self, framebuffer_size: DeviceUintSize) {
if !self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) {
return;
}
let mut spacing = 16;
let mut size = 512;
let fb_width = framebuffer_size.width as i32;
- let num_layers: i32 = self.color_render_targets
+ let num_layers: i32 = self.render_target_pool
.iter()
- .chain(self.alpha_render_targets.iter())
.map(|texture| texture.get_render_target_layer_count() as i32)
.sum();
if num_layers * (size + spacing) > fb_width {
let factor = fb_width as f32 / (num_layers * (size + spacing)) as f32;
size = (size as f32 * factor) as i32;
spacing = (spacing as f32 * factor) as i32;
}
let mut target_index = 0;
- for texture in self.color_render_targets
- .iter()
- .chain(self.alpha_render_targets.iter())
- {
+ for texture in &self.render_target_pool {
let dimensions = texture.get_dimensions();
let src_rect = DeviceIntRect::new(DeviceIntPoint::zero(), dimensions.to_i32());
let layer_count = texture.get_render_target_layer_count();
for layer_index in 0 .. layer_count {
self.device
.bind_read_target(Some((texture, layer_index as i32)));
let x = fb_width - (spacing + size) * (target_index + 1);
@@ -3901,20 +3939,17 @@ impl Renderer {
//Note: this is a fake frame, only needed because texture deletion is require to happen inside a frame
self.device.begin_frame();
self.gpu_cache_texture.deinit(&mut self.device);
if let Some(dither_matrix_texture) = self.dither_matrix_texture {
self.device.delete_texture(dither_matrix_texture);
}
self.node_data_texture.deinit(&mut self.device);
self.render_task_texture.deinit(&mut self.device);
- for texture in self.alpha_render_targets {
- self.device.delete_texture(texture);
- }
- for texture in self.color_render_targets {
+ for texture in self.render_target_pool {
self.device.delete_texture(texture);
}
self.device.delete_pbo(self.texture_cache_upload_pbo);
self.texture_resolver.deinit(&mut self.device);
self.device.delete_vao(self.prim_vao);
self.device.delete_vao(self.clip_vao);
self.device.delete_vao(self.blur_vao);
self.debug.deinit(&mut self.device);
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -1,15 +1,16 @@
/* 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/. */
use api::{BorderRadiusKind, ClipId, ColorF, DeviceIntPoint, ImageKey};
use api::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
-use api::{DocumentLayer, ExternalImageType, FilterOp, FontRenderMode, ImageRendering};
+use api::{DocumentLayer, ExternalImageType, FilterOp, FontRenderMode};
+use api::{ImageFormat, ImageRendering};
use api::{LayerRect, MixBlendMode, PipelineId};
use api::{TileOffset, YuvColorSpace, YuvFormat};
use api::{LayerToWorldTransform, WorldPixel};
use border::{BorderCornerInstance, BorderCornerSide};
use clip::{ClipSource, ClipStore};
use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId};
use device::Texture;
use euclid::{TypedTransform3D, vec3};
@@ -1253,27 +1254,30 @@ pub trait RenderTarget {
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum RenderTargetKind {
Color, // RGBA32
Alpha, // R8
}
pub struct RenderTargetList<T> {
screen_size: DeviceIntSize,
+ pub format: ImageFormat,
pub max_size: DeviceUintSize,
pub targets: Vec<T>,
pub texture: Option<Texture>,
}
impl<T: RenderTarget> RenderTargetList<T> {
fn new(
screen_size: DeviceIntSize,
+ format: ImageFormat,
) -> Self {
RenderTargetList {
screen_size,
+ format,
max_size: DeviceUintSize::new(MIN_TARGET_SIZE, MIN_TARGET_SIZE),
targets: Vec::new(),
texture: None,
}
}
fn build(
&mut self,
@@ -1748,18 +1752,18 @@ impl RenderPass {
tasks: vec![],
dynamic_tasks: FastHashMap::default(),
}
}
pub fn new_off_screen(screen_size: DeviceIntSize) -> Self {
RenderPass {
kind: RenderPassKind::OffScreen {
- color: RenderTargetList::new(screen_size),
- alpha: RenderTargetList::new(screen_size),
+ color: RenderTargetList::new(screen_size, ImageFormat::BGRA8),
+ alpha: RenderTargetList::new(screen_size, ImageFormat::A8),
},
tasks: vec![],
dynamic_tasks: FastHashMap::default(),
}
}
pub fn add_render_task(
&mut self,
--- a/gfx/webrender/src/util.rs
+++ b/gfx/webrender/src/util.rs
@@ -205,17 +205,17 @@ pub fn get_normal(x: f32) -> Option<f32>
if x.is_normal() {
Some(x)
} else {
None
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-#[repr(u8)]
+#[repr(u32)]
pub enum TransformedRectKind {
AxisAligned = 0,
Complex = 1,
}
#[derive(Debug, Clone)]
pub struct TransformedRect {
pub local_rect: LayerRect,