mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 1423203 - Update webrender to commit 22f472f0adb02bd71c472e426e47182f2b218f6d. r=jrmuizel
MozReview-Commit-ID: JJK2le2vpeN --HG-- extra : rebase_source : 677e4433eddb14fea5e0d9a978f28b57912d21f8
This commit is contained in:
parent
e22361a5ac
commit
14a9b3751e
@ -175,4 +175,4 @@ Troubleshooting tips:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The version of WebRender currently in the tree is:
|
||||
b7714b1d4348c00682b5643ea0e3f0b15adaeda5
|
||||
22f472f0adb02bd71c472e426e47182f2b218f6d
|
||||
|
@ -49,6 +49,6 @@ freetype = { version = "0.3", default-features = false }
|
||||
dwrote = "0.4.1"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation = "0.4"
|
||||
core-foundation = "0.4.6"
|
||||
core-graphics = "0.12.3"
|
||||
core-text = { version = "8.0", default-features = false }
|
||||
|
@ -14,7 +14,7 @@ flat varying vec4 vUvBounds;
|
||||
flat varying vec4 vUvBounds_NoClamp;
|
||||
flat varying vec4 vParams;
|
||||
|
||||
#if defined WR_FEATURE_ALPHA_TARGET
|
||||
#if defined WR_FEATURE_ALPHA_TARGET || defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
|
||||
flat varying vec4 vColor;
|
||||
#endif
|
||||
|
||||
@ -41,6 +41,9 @@ void brush_vs(
|
||||
|
||||
#if defined WR_FEATURE_COLOR_TARGET
|
||||
vec2 texture_size = vec2(textureSize(sColor0, 0).xy);
|
||||
#elif defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
|
||||
vec2 texture_size = vec2(textureSize(sColor0, 0).xy);
|
||||
vColor = blur_task.color;
|
||||
#else
|
||||
vec2 texture_size = vec2(textureSize(sColor1, 0).xy);
|
||||
vColor = blur_task.color;
|
||||
@ -120,6 +123,8 @@ vec4 brush_fs() {
|
||||
|
||||
#if defined WR_FEATURE_COLOR_TARGET
|
||||
vec4 color = texture(sColor0, vec3(uv, vUv.z));
|
||||
#elif defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
|
||||
vec4 color = vColor * texture(sColor0, vec3(uv, vUv.z)).a;
|
||||
#else
|
||||
vec4 color = vColor * texture(sColor1, vec3(uv, vUv.z)).r;
|
||||
#endif
|
||||
|
@ -34,6 +34,6 @@ void main(void) {
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
void main(void) {
|
||||
vec2 uv = clamp(vUv.xy, vUvBounds.xy, vUvBounds.zw);
|
||||
oFragColor = texture(sCacheRGBA8, vec3(uv, vUv.z));
|
||||
oFragColor = texture(sColor0, vec3(uv, vUv.z));
|
||||
}
|
||||
#endif
|
||||
|
@ -19,15 +19,12 @@ flat varying vec4 vUvBorder;
|
||||
#define MODE_SUBPX_BG_PASS2 6
|
||||
#define MODE_COLOR_BITMAP 7
|
||||
|
||||
VertexInfo write_text_vertex(vec2 local_pos,
|
||||
VertexInfo write_text_vertex(vec2 clamped_local_pos,
|
||||
RectWithSize local_clip_rect,
|
||||
float z,
|
||||
Layer layer,
|
||||
PictureTask task,
|
||||
RectWithSize snap_rect) {
|
||||
// Clamp to the two local clip rects.
|
||||
vec2 clamped_local_pos = clamp_rect(clamp_rect(local_pos, local_clip_rect), layer.local_clip_rect);
|
||||
|
||||
// Transform the current vertex to world space.
|
||||
vec4 world_pos = layer.transform * vec4(clamped_local_pos, 0.0, 1.0);
|
||||
|
||||
@ -75,9 +72,22 @@ void main(void) {
|
||||
RectWithSize glyph_rect = RectWithSize(res.offset + transform * (text.offset + glyph.offset),
|
||||
res.uv_rect.zw - res.uv_rect.xy);
|
||||
|
||||
// Select the corner of the glyph rect that we are processing.
|
||||
// Transform it from glyph space into local space.
|
||||
vec2 local_pos = inverse(transform) * (glyph_rect.p0 + glyph_rect.size * aPosition.xy);
|
||||
// Transform the glyph rect back to local space.
|
||||
mat2 inv = inverse(transform);
|
||||
RectWithSize local_rect = transform_rect(glyph_rect, inv);
|
||||
|
||||
// Select the corner of the glyph's local space rect that we are processing.
|
||||
vec2 local_pos = local_rect.p0 + local_rect.size * aPosition.xy;
|
||||
|
||||
// Calculate a combined local clip rect.
|
||||
RectWithSize local_clip_rect = intersect_rects(prim.local_clip_rect, prim.layer.local_clip_rect);
|
||||
|
||||
// If the glyph's local rect would fit inside the local clip rect, then select a corner from
|
||||
// the device space glyph rect to reduce overdraw of clipped pixels in the fragment shader.
|
||||
// Otherwise, fall back to clamping the glyph's local rect to the local clip rect.
|
||||
local_pos = rect_inside_rect(local_rect, local_clip_rect) ?
|
||||
inv * (glyph_rect.p0 + glyph_rect.size * aPosition.xy) :
|
||||
clamp_rect(local_pos, local_clip_rect);
|
||||
#else
|
||||
// Scale from glyph space to local space.
|
||||
float scale = res.scale / uDevicePixelRatio;
|
||||
@ -88,6 +98,9 @@ void main(void) {
|
||||
|
||||
// Select the corner of the glyph rect that we are processing.
|
||||
vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy;
|
||||
|
||||
// Clamp to the two local clip rects.
|
||||
local_pos = clamp_rect(clamp_rect(local_pos, prim.local_clip_rect), prim.layer.local_clip_rect);
|
||||
#endif
|
||||
|
||||
VertexInfo vi = write_text_vertex(local_pos,
|
||||
@ -131,16 +144,16 @@ void main(void) {
|
||||
vec2 st1 = res.uv_rect.zw / texture_size;
|
||||
|
||||
vUv = vec3(mix(st0, st1, f), res.layer);
|
||||
vUvBorder = (res.uv_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
|
||||
vUvBorder = (res.uv_rect + vec4(0.499, 0.499, -0.499, -0.499)) / texture_size.xyxy;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
void main(void) {
|
||||
vec3 tc = vec3(clamp(vUv.xy, vUvBorder.xy, vUvBorder.zw), vUv.z);
|
||||
vec4 mask = texture(sColor0, tc);
|
||||
vec4 mask = texture(sColor0, vUv);
|
||||
|
||||
float alpha = do_clip();
|
||||
float alpha = float(all(lessThanEqual(vec4(vUvBorder.xy, vUv.xy), vec4(vUv.xy, vUvBorder.zw))));
|
||||
alpha *= do_clip();
|
||||
|
||||
#ifdef WR_FEATURE_SUBPX_BG_PASS1
|
||||
mask.rgb = vec3(mask.a) - mask.rgb;
|
||||
|
@ -27,3 +27,22 @@ RectWithSize to_rect_with_size(RectWithEndpoint rect) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RectWithSize transform_rect(RectWithSize rect, mat2 transform) {
|
||||
vec2 center = transform * (rect.p0 + rect.size * 0.5);
|
||||
vec2 radius = mat2(abs(transform[0]), abs(transform[1])) * (rect.size * 0.5);
|
||||
return RectWithSize(center - radius, radius * 2.0);
|
||||
}
|
||||
|
||||
RectWithSize intersect_rects(RectWithSize a, RectWithSize b) {
|
||||
RectWithSize result;
|
||||
result.p0 = max(a.p0, b.p0);
|
||||
result.size = min(a.p0 + a.size, b.p0 + b.size) - result.p0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool rect_inside_rect(RectWithSize little, RectWithSize big) {
|
||||
return all(lessThanEqual(vec4(big.p0, little.p0 + little.size),
|
||||
vec4(little.p0, big.p0 + big.size)));
|
||||
}
|
||||
|
@ -329,6 +329,7 @@ impl ClipScrollNode {
|
||||
pub fn update(
|
||||
&mut self,
|
||||
state: &mut TransformUpdateState,
|
||||
next_coordinate_system_id: &mut CoordinateSystemId,
|
||||
device_pixel_ratio: f32,
|
||||
clip_store: &mut ClipStore,
|
||||
resource_cache: &mut ResourceCache,
|
||||
@ -352,7 +353,7 @@ impl ClipScrollNode {
|
||||
}
|
||||
}
|
||||
|
||||
self.update_transform(state, scene_properties);
|
||||
self.update_transform(state, next_coordinate_system_id, scene_properties);
|
||||
self.update_clip_work_item(
|
||||
state,
|
||||
device_pixel_ratio,
|
||||
@ -441,10 +442,15 @@ impl ClipScrollNode {
|
||||
pub fn update_transform(
|
||||
&mut self,
|
||||
state: &mut TransformUpdateState,
|
||||
next_coordinate_system_id: &mut CoordinateSystemId,
|
||||
scene_properties: &SceneProperties,
|
||||
) {
|
||||
if self.node_type.is_reference_frame() {
|
||||
self.update_transform_for_reference_frame(state, scene_properties);
|
||||
self.update_transform_for_reference_frame(
|
||||
state,
|
||||
next_coordinate_system_id,
|
||||
scene_properties
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -484,6 +490,7 @@ impl ClipScrollNode {
|
||||
pub fn update_transform_for_reference_frame(
|
||||
&mut self,
|
||||
state: &mut TransformUpdateState,
|
||||
next_coordinate_system_id: &mut CoordinateSystemId,
|
||||
scene_properties: &SceneProperties,
|
||||
) {
|
||||
let info = match self.node_type {
|
||||
@ -502,10 +509,10 @@ impl ClipScrollNode {
|
||||
|
||||
if !info.resolved_transform.preserves_2d_axis_alignment() ||
|
||||
info.resolved_transform.has_perspective_component() {
|
||||
state.current_coordinate_system_id = state.next_coordinate_system_id;
|
||||
state.next_coordinate_system_id = state.next_coordinate_system_id.next();
|
||||
self.coordinate_system_id = state.current_coordinate_system_id;
|
||||
state.current_coordinate_system_id = *next_coordinate_system_id;
|
||||
next_coordinate_system_id.advance();
|
||||
}
|
||||
self.coordinate_system_id = state.current_coordinate_system_id;
|
||||
|
||||
// The transformation for this viewport in world coordinates is the transformation for
|
||||
// our parent reference frame, plus any accumulated scrolling offsets from nodes
|
||||
|
@ -34,6 +34,10 @@ impl CoordinateSystemId {
|
||||
let CoordinateSystemId(id) = *self;
|
||||
CoordinateSystemId(id + 1)
|
||||
}
|
||||
|
||||
pub fn advance(&mut self) {
|
||||
self.0 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ClipScrollTree {
|
||||
@ -78,7 +82,6 @@ pub struct TransformUpdateState {
|
||||
/// 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 {
|
||||
@ -362,12 +365,13 @@ impl ClipScrollTree {
|
||||
parent_clip_chain: None,
|
||||
combined_outer_clip_bounds: *screen_rect,
|
||||
combined_inner_clip_bounds: DeviceIntRect::max_rect(),
|
||||
current_coordinate_system_id: CoordinateSystemId(0),
|
||||
next_coordinate_system_id: CoordinateSystemId(0).next(),
|
||||
current_coordinate_system_id: CoordinateSystemId::root(),
|
||||
};
|
||||
let mut next_coordinate_system_id = state.current_coordinate_system_id.next();
|
||||
self.update_node(
|
||||
root_reference_frame_id,
|
||||
&mut state,
|
||||
&mut next_coordinate_system_id,
|
||||
device_pixel_ratio,
|
||||
clip_store,
|
||||
resource_cache,
|
||||
@ -381,6 +385,7 @@ impl ClipScrollTree {
|
||||
&mut self,
|
||||
layer_id: ClipId,
|
||||
state: &mut TransformUpdateState,
|
||||
next_coordinate_system_id: &mut CoordinateSystemId,
|
||||
device_pixel_ratio: f32,
|
||||
clip_store: &mut ClipStore,
|
||||
resource_cache: &mut ResourceCache,
|
||||
@ -402,6 +407,7 @@ impl ClipScrollTree {
|
||||
|
||||
node.update(
|
||||
&mut state,
|
||||
next_coordinate_system_id,
|
||||
device_pixel_ratio,
|
||||
clip_store,
|
||||
resource_cache,
|
||||
@ -411,10 +417,11 @@ impl ClipScrollTree {
|
||||
|
||||
node.push_gpu_node_data(&state, gpu_node_data);
|
||||
|
||||
if !node.children.is_empty() {
|
||||
node.prepare_state_for_children(&mut state, gpu_node_data);
|
||||
if node.children.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
node.prepare_state_for_children(&mut state, gpu_node_data);
|
||||
node.children.clone()
|
||||
};
|
||||
|
||||
@ -422,6 +429,7 @@ impl ClipScrollTree {
|
||||
self.update_node(
|
||||
child_layer_id,
|
||||
&mut state,
|
||||
next_coordinate_system_id,
|
||||
device_pixel_ratio,
|
||||
clip_store,
|
||||
resource_cache,
|
||||
|
@ -22,7 +22,7 @@ use frame::FrameId;
|
||||
use glyph_rasterizer::FontInstance;
|
||||
use gpu_cache::GpuCache;
|
||||
use gpu_types::ClipScrollNodeData;
|
||||
use internal_types::{FastHashMap, FastHashSet};
|
||||
use internal_types::{FastHashMap, FastHashSet, RenderPassIndex};
|
||||
use picture::{PictureCompositeMode, PictureKind, PicturePrimitive, RasterizationSpace};
|
||||
use prim_store::{BrushAntiAliasMode, BrushKind, BrushPrimitive, TexelRect, YuvImagePrimitiveCpu};
|
||||
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, LinePrimitive, PrimitiveKind};
|
||||
@ -35,7 +35,7 @@ use resource_cache::ResourceCache;
|
||||
use scene::{ScenePipeline, SceneProperties};
|
||||
use std::{mem, usize, f32};
|
||||
use tiling::{CompositeOps, Frame};
|
||||
use tiling::{RenderPass, RenderPassKind, RenderTargetKind};
|
||||
use tiling::{RenderPass, RenderTargetKind};
|
||||
use tiling::{RenderTargetContext, ScrollbarPrimitive};
|
||||
use util::{self, MaxRect, pack_as_float, RectHelpers, recycle_vec};
|
||||
|
||||
@ -1761,7 +1761,7 @@ impl FrameBuilder {
|
||||
|
||||
let mut deferred_resolves = vec![];
|
||||
|
||||
for pass in &mut passes {
|
||||
for (pass_index, pass) in passes.iter_mut().enumerate() {
|
||||
let ctx = RenderTargetContext {
|
||||
device_pixel_ratio,
|
||||
prim_store: &self.prim_store,
|
||||
@ -1776,23 +1776,8 @@ impl FrameBuilder {
|
||||
&mut render_tasks,
|
||||
&mut deferred_resolves,
|
||||
&self.clip_store,
|
||||
RenderPassIndex(pass_index),
|
||||
);
|
||||
|
||||
profile_counters.passes.inc();
|
||||
|
||||
match pass.kind {
|
||||
RenderPassKind::MainFramebuffer(_) => {
|
||||
profile_counters.color_targets.add(1);
|
||||
}
|
||||
RenderPassKind::OffScreen { ref color, ref alpha } => {
|
||||
profile_counters
|
||||
.color_targets
|
||||
.add(color.targets.len());
|
||||
profile_counters
|
||||
.alpha_targets
|
||||
.add(alpha.targets.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let gpu_cache_updates = gpu_cache.end_frame(gpu_cache_profile);
|
||||
|
@ -32,6 +32,9 @@ pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct CacheTextureId(pub usize);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct RenderPassIndex(pub usize);
|
||||
|
||||
// Represents the source for a texture.
|
||||
// These are passed from throughout the
|
||||
// pipeline until they reach the rendering
|
||||
@ -45,6 +48,10 @@ pub enum SourceTexture {
|
||||
External(ExternalImageData),
|
||||
CacheA8,
|
||||
CacheRGBA8,
|
||||
// XXX Remove this once RenderTaskCacheA8 is used.
|
||||
#[allow(dead_code)]
|
||||
RenderTaskCacheA8(RenderPassIndex),
|
||||
RenderTaskCacheRGBA8(RenderPassIndex),
|
||||
}
|
||||
|
||||
pub const ORTHO_NEAR_PLANE: f32 = -1000000.0;
|
||||
|
@ -67,7 +67,10 @@ pub enum PictureKind {
|
||||
// If a mix-blend-mode, contains the render task for
|
||||
// the readback of the framebuffer that we use to sample
|
||||
// from in the mix-blend-mode shader.
|
||||
readback_render_task_id: Option<RenderTaskId>,
|
||||
// For drop-shadow filter, this will store the original
|
||||
// picture task which would be rendered on screen after
|
||||
// blur pass.
|
||||
secondary_render_task_id: Option<RenderTaskId>,
|
||||
/// How this picture should be composited.
|
||||
/// If None, don't composite - just draw directly on parent surface.
|
||||
composite_mode: Option<PictureCompositeMode>,
|
||||
@ -186,7 +189,7 @@ impl PicturePrimitive {
|
||||
runs: Vec::new(),
|
||||
render_task_id: None,
|
||||
kind: PictureKind::Image {
|
||||
readback_render_task_id: None,
|
||||
secondary_render_task_id: None,
|
||||
composite_mode,
|
||||
is_in_3d_context,
|
||||
frame_output_pipeline_id,
|
||||
@ -236,6 +239,11 @@ impl PicturePrimitive {
|
||||
let inflate_size = blur_radius * BLUR_SAMPLE_SCALE;
|
||||
local_content_rect.inflate(inflate_size, inflate_size)
|
||||
}
|
||||
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, _))) => {
|
||||
let inflate_size = blur_radius * BLUR_SAMPLE_SCALE;
|
||||
local_content_rect.inflate(inflate_size, inflate_size)
|
||||
.translate(&offset)
|
||||
}
|
||||
_ => {
|
||||
local_content_rect
|
||||
}
|
||||
@ -304,7 +312,7 @@ impl PicturePrimitive {
|
||||
) {
|
||||
match self.kind {
|
||||
PictureKind::Image {
|
||||
ref mut readback_render_task_id,
|
||||
ref mut secondary_render_task_id,
|
||||
composite_mode,
|
||||
..
|
||||
} => {
|
||||
@ -341,6 +349,37 @@ impl PicturePrimitive {
|
||||
let blur_render_task_id = render_tasks.add(blur_render_task);
|
||||
self.render_task_id = Some(blur_render_task_id);
|
||||
}
|
||||
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
|
||||
let picture_task = RenderTask::new_picture(
|
||||
Some(prim_screen_rect.size),
|
||||
prim_index,
|
||||
RenderTargetKind::Color,
|
||||
prim_screen_rect.origin.x as f32 - offset.x,
|
||||
prim_screen_rect.origin.y as f32 - offset.y,
|
||||
PremultipliedColorF::TRANSPARENT,
|
||||
ClearMode::Transparent,
|
||||
self.rasterization_kind,
|
||||
child_tasks,
|
||||
None,
|
||||
);
|
||||
|
||||
let blur_std_deviation = blur_radius * prim_context.device_pixel_ratio;
|
||||
let picture_task_id = render_tasks.add(picture_task);
|
||||
|
||||
let blur_render_task = RenderTask::new_blur(
|
||||
blur_std_deviation,
|
||||
picture_task_id,
|
||||
render_tasks,
|
||||
RenderTargetKind::Color,
|
||||
&[],
|
||||
ClearMode::Transparent,
|
||||
color.premultiplied(),
|
||||
None,
|
||||
);
|
||||
|
||||
*secondary_render_task_id = Some(picture_task_id);
|
||||
self.render_task_id = Some(render_tasks.add(blur_render_task));
|
||||
}
|
||||
Some(PictureCompositeMode::MixBlend(..)) => {
|
||||
let picture_task = RenderTask::new_picture(
|
||||
Some(prim_screen_rect.size),
|
||||
@ -357,7 +396,7 @@ impl PicturePrimitive {
|
||||
|
||||
let readback_task_id = render_tasks.add(RenderTask::new_readback(*prim_screen_rect));
|
||||
|
||||
*readback_render_task_id = Some(readback_task_id);
|
||||
*secondary_render_task_id = Some(readback_task_id);
|
||||
parent_tasks.push(readback_task_id);
|
||||
|
||||
self.render_task_id = Some(render_tasks.add(picture_task));
|
||||
|
@ -247,7 +247,7 @@ fn new_ct_font_with_variations(cg_font: &CGFont, size: f64, variations: &[FontVa
|
||||
|
||||
val = val.max(min_val).min(max_val);
|
||||
if val != def_val {
|
||||
vals.push((name, CFNumber::from_f64(val)));
|
||||
vals.push((name, CFNumber::from(val)));
|
||||
}
|
||||
}
|
||||
if vals.is_empty() {
|
||||
|
@ -19,8 +19,8 @@ use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuData
|
||||
use gpu_types::ClipScrollNodeData;
|
||||
use picture::{PictureKind, PicturePrimitive, RasterizationSpace};
|
||||
use profiler::FrameProfileCounters;
|
||||
use render_task::{ClipChainNode, ClipChainNodeIter, ClipWorkItem, RenderTask, RenderTaskId};
|
||||
use render_task::RenderTaskTree;
|
||||
use render_task::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipWorkItem, RenderTask};
|
||||
use render_task::{RenderTaskId, RenderTaskTree};
|
||||
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
|
||||
use resource_cache::{ImageProperties, ResourceCache};
|
||||
use scene::{ScenePipeline, SceneProperties};
|
||||
@ -209,6 +209,15 @@ pub enum BrushKind {
|
||||
Clear,
|
||||
}
|
||||
|
||||
impl BrushKind {
|
||||
fn is_solid(&self) -> bool {
|
||||
match *self {
|
||||
BrushKind::Solid { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(u32)]
|
||||
pub enum BrushAntiAliasMode {
|
||||
@ -1367,6 +1376,154 @@ impl PrimitiveStore {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_brush_nine_patch_segment_description(
|
||||
&mut self,
|
||||
prim_index: PrimitiveIndex,
|
||||
prim_context: &PrimitiveContext,
|
||||
clip_store: &mut ClipStore,
|
||||
node_data: &[ClipScrollNodeData],
|
||||
clips: &Vec<ClipWorkItem>,
|
||||
) {
|
||||
debug_assert!(self.cpu_metadata[prim_index.0].prim_kind == PrimitiveKind::Brush);
|
||||
|
||||
if clips.len() != 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let clip_item = clips.first().unwrap();
|
||||
if clip_item.coordinate_system_id != prim_context.scroll_node.coordinate_system_id {
|
||||
return;
|
||||
}
|
||||
|
||||
let metadata = &self.cpu_metadata[prim_index.0];
|
||||
let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
|
||||
if brush.segment_desc.is_some() {
|
||||
return;
|
||||
}
|
||||
if !brush.kind.is_solid() {
|
||||
return;
|
||||
}
|
||||
if metadata.local_rect.size.area() <= MIN_BRUSH_SPLIT_AREA {
|
||||
return;
|
||||
}
|
||||
|
||||
let local_clips = clip_store.get_opt(&clip_item.clip_sources).expect("bug");
|
||||
let mut selected_clip = None;
|
||||
for &(ref clip, _) in &local_clips.clips {
|
||||
match *clip {
|
||||
ClipSource::RoundedRectangle(rect, radii, ClipMode::Clip) => {
|
||||
if selected_clip.is_some() {
|
||||
selected_clip = None;
|
||||
break;
|
||||
}
|
||||
selected_clip = Some((rect, radii, clip_item.scroll_node_data_index));
|
||||
}
|
||||
ClipSource::Rectangle(..) => {}
|
||||
ClipSource::RoundedRectangle(_, _, ClipMode::ClipOut) |
|
||||
ClipSource::BorderCorner(..) |
|
||||
ClipSource::Image(..) => {
|
||||
selected_clip = None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((rect, radii, clip_scroll_node_data_index)) = selected_clip {
|
||||
// If the scroll node transforms are different between the clip
|
||||
// node and the primitive, we need to get the clip rect in the
|
||||
// local space of the primitive, in order to generate correct
|
||||
// local segments.
|
||||
let local_clip_rect = if clip_scroll_node_data_index == prim_context.scroll_node.node_data_index {
|
||||
rect
|
||||
} else {
|
||||
let clip_transform_data = &node_data[clip_scroll_node_data_index.0 as usize];
|
||||
let prim_transform = &prim_context.scroll_node.world_content_transform;
|
||||
|
||||
let relative_transform = prim_transform
|
||||
.inverse()
|
||||
.unwrap_or(WorldToLayerTransform::identity())
|
||||
.pre_mul(&clip_transform_data.transform);
|
||||
|
||||
relative_transform.transform_rect(&rect)
|
||||
};
|
||||
brush.segment_desc = create_nine_patch(
|
||||
&metadata.local_rect,
|
||||
&local_clip_rect,
|
||||
&radii
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_nine_patch_clip_task_for_brush(
|
||||
&mut self,
|
||||
prim_context: &PrimitiveContext,
|
||||
prim_index: PrimitiveIndex,
|
||||
render_tasks: &mut RenderTaskTree,
|
||||
clip_store: &mut ClipStore,
|
||||
tasks: &mut Vec<RenderTaskId>,
|
||||
node_data: &[ClipScrollNodeData],
|
||||
clips: &Vec<ClipWorkItem>,
|
||||
combined_outer_rect: &DeviceIntRect,
|
||||
) -> bool {
|
||||
if self.cpu_metadata[prim_index.0].prim_kind != PrimitiveKind::Brush {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.write_brush_nine_patch_segment_description(
|
||||
prim_index,
|
||||
prim_context,
|
||||
clip_store,
|
||||
node_data,
|
||||
clips
|
||||
);
|
||||
|
||||
let metadata = &self.cpu_metadata[prim_index.0];
|
||||
let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
|
||||
let segment_desc = match brush.segment_desc {
|
||||
Some(ref mut description) => description,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let enabled_segments = segment_desc.enabled_segments;
|
||||
let can_optimize_clip_mask = segment_desc.can_optimize_clip_mask;
|
||||
|
||||
for (i, segment) in segment_desc.segments.iter_mut().enumerate() {
|
||||
// We only build clips for the corners. The ordering of the
|
||||
// BrushSegmentKind enum is such that corners come first, then
|
||||
// edges, then inner.
|
||||
let segment_enabled = ((1 << i) & enabled_segments) != 0;
|
||||
let create_clip_task =
|
||||
segment_enabled &&
|
||||
(!can_optimize_clip_mask || i <= BrushSegmentKind::BottomLeft as usize);
|
||||
|
||||
segment.clip_task_id = if create_clip_task {
|
||||
let segment_screen_rect = calculate_screen_bounding_rect(
|
||||
&prim_context.scroll_node.world_content_transform,
|
||||
&segment.local_rect,
|
||||
prim_context.device_pixel_ratio
|
||||
);
|
||||
|
||||
combined_outer_rect.intersection(&segment_screen_rect).map(|bounds| {
|
||||
let clip_task = RenderTask::new_mask(
|
||||
None,
|
||||
bounds,
|
||||
clips.clone(),
|
||||
prim_context.scroll_node.coordinate_system_id,
|
||||
);
|
||||
|
||||
let clip_task_id = render_tasks.add(clip_task);
|
||||
tasks.push(clip_task_id);
|
||||
|
||||
clip_task_id
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn update_clip_task(
|
||||
&mut self,
|
||||
prim_index: PrimitiveIndex,
|
||||
@ -1380,13 +1537,12 @@ impl PrimitiveStore {
|
||||
tasks: &mut Vec<RenderTaskId>,
|
||||
node_data: &[ClipScrollNodeData],
|
||||
) -> bool {
|
||||
let metadata = &mut self.cpu_metadata[prim_index.0];
|
||||
metadata.clip_task_id = None;
|
||||
self.cpu_metadata[prim_index.0].clip_task_id = None;
|
||||
|
||||
let prim_screen_rect = match prim_screen_rect.intersection(screen_rect) {
|
||||
Some(rect) => rect,
|
||||
None => {
|
||||
metadata.screen_rect = None;
|
||||
self.cpu_metadata[prim_index.0].screen_rect = None;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@ -1400,6 +1556,7 @@ impl PrimitiveStore {
|
||||
let prim_coordinate_system_id = prim_context.scroll_node.coordinate_system_id;
|
||||
let transform = &prim_context.scroll_node.world_content_transform;
|
||||
let extra_clip = {
|
||||
let metadata = &self.cpu_metadata[prim_index.0];
|
||||
let prim_clips = clip_store.get_mut(&metadata.clip_sources);
|
||||
if prim_clips.has_clips() {
|
||||
prim_clips.update(gpu_cache, resource_cache);
|
||||
@ -1431,34 +1588,18 @@ impl PrimitiveStore {
|
||||
let combined_outer_rect = match combined_outer_rect {
|
||||
Some(rect) if !rect.is_empty() => rect,
|
||||
_ => {
|
||||
metadata.screen_rect = None;
|
||||
self.cpu_metadata[prim_index.0].screen_rect = None;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Filter out all the clip instances that don't contribute to the result.
|
||||
let mut combined_inner_rect = *screen_rect;
|
||||
let clips: Vec<_> = ClipChainNodeIter { current: extra_clip }
|
||||
.chain(ClipChainNodeIter { current: clip_chain })
|
||||
.take_while(|node| {
|
||||
!node.combined_inner_screen_rect.contains_rect(&combined_outer_rect)
|
||||
})
|
||||
.filter_map(|node| {
|
||||
combined_inner_rect = if !node.screen_inner_rect.is_empty() {
|
||||
// If this clip's inner area contains the area of the primitive clipped
|
||||
// by previous clips, then it's not going to affect rendering in any way.
|
||||
if node.screen_inner_rect.contains_rect(&combined_outer_rect) {
|
||||
return None;
|
||||
}
|
||||
combined_inner_rect.intersection(&node.screen_inner_rect)
|
||||
.unwrap_or_else(DeviceIntRect::zero)
|
||||
} else {
|
||||
DeviceIntRect::zero()
|
||||
};
|
||||
|
||||
Some(node.work_item.clone())
|
||||
})
|
||||
.collect();
|
||||
let clips = convert_clip_chain_to_clip_vector(
|
||||
clip_chain,
|
||||
extra_clip,
|
||||
&combined_outer_rect,
|
||||
&mut combined_inner_rect
|
||||
);
|
||||
|
||||
if clips.is_empty() {
|
||||
// If this item is in the root coordinate system, then
|
||||
@ -1483,116 +1624,30 @@ impl PrimitiveStore {
|
||||
return true;
|
||||
}
|
||||
|
||||
let mut needs_prim_clip_task = true;
|
||||
|
||||
if metadata.prim_kind == PrimitiveKind::Brush {
|
||||
let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
|
||||
if brush.segment_desc.is_none() && metadata.local_rect.size.area() > MIN_BRUSH_SPLIT_AREA {
|
||||
if let BrushKind::Solid { .. } = brush.kind {
|
||||
if clips.len() == 1 {
|
||||
let clip_item = clips.first().unwrap();
|
||||
if clip_item.coordinate_system_id == prim_coordinate_system_id {
|
||||
let local_clips = clip_store.get_opt(&clip_item.clip_sources).expect("bug");
|
||||
let mut selected_clip = None;
|
||||
for &(ref clip, _) in &local_clips.clips {
|
||||
match *clip {
|
||||
ClipSource::RoundedRectangle(rect, radii, ClipMode::Clip) => {
|
||||
if selected_clip.is_some() {
|
||||
selected_clip = None;
|
||||
break;
|
||||
}
|
||||
selected_clip = Some((rect, radii, clip_item.scroll_node_data_index));
|
||||
}
|
||||
ClipSource::Rectangle(..) => {}
|
||||
ClipSource::RoundedRectangle(_, _, ClipMode::ClipOut) |
|
||||
ClipSource::BorderCorner(..) |
|
||||
ClipSource::Image(..) => {
|
||||
selected_clip = None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some((rect, radii, clip_scroll_node_data_index)) = selected_clip {
|
||||
// If the scroll node transforms are different between the clip
|
||||
// node and the primitive, we need to get the clip rect in the
|
||||
// local space of the primitive, in order to generate correct
|
||||
// local segments.
|
||||
let local_clip_rect = if clip_scroll_node_data_index == prim_context.scroll_node.node_data_index {
|
||||
rect
|
||||
} else {
|
||||
let clip_transform_data = &node_data[clip_scroll_node_data_index.0 as usize];
|
||||
let prim_transform = &prim_context.scroll_node.world_content_transform;
|
||||
|
||||
let relative_transform = prim_transform
|
||||
.inverse()
|
||||
.unwrap_or(WorldToLayerTransform::identity())
|
||||
.pre_mul(&clip_transform_data.transform);
|
||||
|
||||
relative_transform.transform_rect(&rect)
|
||||
};
|
||||
brush.segment_desc = create_nine_patch(
|
||||
&metadata.local_rect,
|
||||
&local_clip_rect,
|
||||
&radii
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut segment_desc) = brush.segment_desc {
|
||||
let enabled_segments = segment_desc.enabled_segments;
|
||||
let can_optimize_clip_mask = segment_desc.can_optimize_clip_mask;
|
||||
|
||||
for (i, segment) in segment_desc.segments.iter_mut().enumerate() {
|
||||
// We only build clips for the corners. The ordering of the
|
||||
// BrushSegmentKind enum is such that corners come first, then
|
||||
// edges, then inner.
|
||||
let segment_enabled = ((1 << i) & enabled_segments) != 0;
|
||||
let create_clip_task = segment_enabled &&
|
||||
(!can_optimize_clip_mask || i <= BrushSegmentKind::BottomLeft as usize);
|
||||
segment.clip_task_id = if create_clip_task {
|
||||
let segment_screen_rect = calculate_screen_bounding_rect(
|
||||
&prim_context.scroll_node.world_content_transform,
|
||||
&segment.local_rect,
|
||||
prim_context.device_pixel_ratio
|
||||
);
|
||||
|
||||
combined_outer_rect.intersection(&segment_screen_rect).map(|bounds| {
|
||||
let clip_task = RenderTask::new_mask(
|
||||
None,
|
||||
bounds,
|
||||
clips.clone(),
|
||||
prim_coordinate_system_id,
|
||||
);
|
||||
|
||||
let clip_task_id = render_tasks.add(clip_task);
|
||||
tasks.push(clip_task_id);
|
||||
|
||||
clip_task_id
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
|
||||
needs_prim_clip_task = false;
|
||||
}
|
||||
// First try to render this primitive's mask using optimized nine-patch brush rendering.
|
||||
if self.update_nine_patch_clip_task_for_brush(
|
||||
prim_context,
|
||||
prim_index,
|
||||
render_tasks,
|
||||
clip_store,
|
||||
tasks,
|
||||
node_data,
|
||||
&clips,
|
||||
&combined_outer_rect,
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if needs_prim_clip_task {
|
||||
let clip_task = RenderTask::new_mask(
|
||||
None,
|
||||
combined_outer_rect,
|
||||
clips,
|
||||
prim_coordinate_system_id,
|
||||
);
|
||||
let clip_task = RenderTask::new_mask(
|
||||
None,
|
||||
combined_outer_rect,
|
||||
clips,
|
||||
prim_coordinate_system_id,
|
||||
);
|
||||
|
||||
let clip_task_id = render_tasks.add(clip_task);
|
||||
metadata.clip_task_id = Some(clip_task_id);
|
||||
tasks.push(clip_task_id);
|
||||
}
|
||||
let clip_task_id = render_tasks.add(clip_task);
|
||||
self.cpu_metadata[prim_index.0].clip_task_id = Some(clip_task_id);
|
||||
tasks.push(clip_task_id);
|
||||
|
||||
true
|
||||
}
|
||||
@ -1913,3 +1968,33 @@ fn create_nine_patch(
|
||||
Box::new(desc)
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_clip_chain_to_clip_vector(
|
||||
clip_chain: ClipChain,
|
||||
extra_clip: ClipChain,
|
||||
combined_outer_rect: &DeviceIntRect,
|
||||
combined_inner_rect: &mut DeviceIntRect,
|
||||
) -> Vec<ClipWorkItem> {
|
||||
// Filter out all the clip instances that don't contribute to the result.
|
||||
ClipChainNodeIter { current: extra_clip }
|
||||
.chain(ClipChainNodeIter { current: clip_chain })
|
||||
.take_while(|node| {
|
||||
!node.combined_inner_screen_rect.contains_rect(&combined_outer_rect)
|
||||
})
|
||||
.filter_map(|node| {
|
||||
*combined_inner_rect = if !node.screen_inner_rect.is_empty() {
|
||||
// If this clip's inner area contains the area of the primitive clipped
|
||||
// by previous clips, then it's not going to affect rendering in any way.
|
||||
if node.screen_inner_rect.contains_rect(&combined_outer_rect) {
|
||||
return None;
|
||||
}
|
||||
combined_inner_rect.intersection(&node.screen_inner_rect)
|
||||
.unwrap_or_else(DeviceIntRect::zero)
|
||||
} else {
|
||||
DeviceIntRect::zero()
|
||||
};
|
||||
|
||||
Some(node.work_item.clone())
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -37,15 +37,6 @@ trait ProfileCounter {
|
||||
fn value(&self) -> String;
|
||||
}
|
||||
|
||||
impl<'a, T: ProfileCounter> ProfileCounter for &'a T {
|
||||
fn description(&self) -> &'static str {
|
||||
(*self).description()
|
||||
}
|
||||
fn value(&self) -> String {
|
||||
(*self).value()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IntProfileCounter {
|
||||
description: &'static str,
|
||||
@ -309,9 +300,6 @@ impl ProfileCounter for AverageTimeProfileCounter {
|
||||
pub struct FrameProfileCounters {
|
||||
pub total_primitives: IntProfileCounter,
|
||||
pub visible_primitives: IntProfileCounter,
|
||||
pub passes: IntProfileCounter,
|
||||
pub color_targets: IntProfileCounter,
|
||||
pub alpha_targets: IntProfileCounter,
|
||||
}
|
||||
|
||||
impl FrameProfileCounters {
|
||||
@ -319,9 +307,6 @@ impl FrameProfileCounters {
|
||||
FrameProfileCounters {
|
||||
total_primitives: IntProfileCounter::new("Total Primitives"),
|
||||
visible_primitives: IntProfileCounter::new("Visible Primitives"),
|
||||
passes: IntProfileCounter::new("Passes"),
|
||||
color_targets: IntProfileCounter::new("Color Targets"),
|
||||
alpha_targets: IntProfileCounter::new("Alpha Targets"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -449,6 +434,8 @@ pub struct RendererProfileCounters {
|
||||
pub draw_calls: IntProfileCounter,
|
||||
pub vertices: IntProfileCounter,
|
||||
pub vao_count_and_size: ResourceProfileCounter,
|
||||
pub color_targets: IntProfileCounter,
|
||||
pub alpha_targets: IntProfileCounter,
|
||||
}
|
||||
|
||||
pub struct RendererProfileTimers {
|
||||
@ -465,12 +452,16 @@ impl RendererProfileCounters {
|
||||
draw_calls: IntProfileCounter::new("Draw Calls"),
|
||||
vertices: IntProfileCounter::new("Vertices"),
|
||||
vao_count_and_size: ResourceProfileCounter::new("VAO"),
|
||||
color_targets: IntProfileCounter::new("Color Targets"),
|
||||
alpha_targets: IntProfileCounter::new("Alpha Targets"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.draw_calls.reset();
|
||||
self.vertices.reset();
|
||||
self.color_targets.reset();
|
||||
self.alpha_targets.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@ -493,13 +484,18 @@ struct GraphStats {
|
||||
struct ProfileGraph {
|
||||
max_samples: usize,
|
||||
values: VecDeque<f32>,
|
||||
short_description: &'static str,
|
||||
}
|
||||
|
||||
impl ProfileGraph {
|
||||
fn new(max_samples: usize) -> Self {
|
||||
fn new(
|
||||
max_samples: usize,
|
||||
short_description: &'static str,
|
||||
) -> Self {
|
||||
ProfileGraph {
|
||||
max_samples,
|
||||
values: VecDeque::new(),
|
||||
short_description,
|
||||
}
|
||||
}
|
||||
|
||||
@ -620,6 +616,16 @@ impl ProfileGraph {
|
||||
}
|
||||
}
|
||||
|
||||
impl ProfileCounter for ProfileGraph {
|
||||
fn description(&self) -> &'static str {
|
||||
self.short_description
|
||||
}
|
||||
|
||||
fn value(&self) -> String {
|
||||
format!("{:.2}ms", self.stats().mean_value)
|
||||
}
|
||||
}
|
||||
|
||||
struct GpuFrame {
|
||||
total_time: u64,
|
||||
samples: Vec<GpuTimer<GpuProfileTag>>,
|
||||
@ -737,11 +743,15 @@ impl GpuFrameCollection {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Profiler {
|
||||
struct DrawState {
|
||||
x_left: f32,
|
||||
y_left: f32,
|
||||
x_right: f32,
|
||||
y_right: f32,
|
||||
}
|
||||
|
||||
pub struct Profiler {
|
||||
draw_state: DrawState,
|
||||
backend_time: ProfileGraph,
|
||||
compositor_time: ProfileGraph,
|
||||
gpu_time: ProfileGraph,
|
||||
@ -752,30 +762,32 @@ pub struct Profiler {
|
||||
impl Profiler {
|
||||
pub fn new() -> Self {
|
||||
Profiler {
|
||||
x_left: 0.0,
|
||||
y_left: 0.0,
|
||||
x_right: 0.0,
|
||||
y_right: 0.0,
|
||||
backend_time: ProfileGraph::new(600),
|
||||
compositor_time: ProfileGraph::new(600),
|
||||
gpu_time: ProfileGraph::new(600),
|
||||
draw_state: DrawState {
|
||||
x_left: 0.0,
|
||||
y_left: 0.0,
|
||||
x_right: 0.0,
|
||||
y_right: 0.0,
|
||||
},
|
||||
backend_time: ProfileGraph::new(600, "Backend:"),
|
||||
compositor_time: ProfileGraph::new(600, "Compositor:"),
|
||||
gpu_time: ProfileGraph::new(600, "GPU:"),
|
||||
gpu_frames: GpuFrameCollection::new(),
|
||||
ipc_time: ProfileGraph::new(600),
|
||||
ipc_time: ProfileGraph::new(600, "IPC:"),
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_counters<T: ProfileCounter>(
|
||||
&mut self,
|
||||
counters: &[T],
|
||||
fn draw_counters<T: ProfileCounter + ?Sized>(
|
||||
counters: &[&T],
|
||||
debug_renderer: &mut DebugRenderer,
|
||||
left: bool,
|
||||
draw_state: &mut DrawState,
|
||||
) {
|
||||
let mut label_rect = Rect::zero();
|
||||
let mut value_rect = Rect::zero();
|
||||
let (mut current_x, mut current_y) = if left {
|
||||
(self.x_left, self.y_left)
|
||||
(draw_state.x_left, draw_state.y_left)
|
||||
} else {
|
||||
(self.x_right, self.y_right)
|
||||
(draw_state.x_right, draw_state.y_right)
|
||||
};
|
||||
let mut color_index = 0;
|
||||
let line_height = debug_renderer.line_height();
|
||||
@ -800,7 +812,7 @@ impl Profiler {
|
||||
|
||||
color_index = 0;
|
||||
current_x = label_rect.origin.x + label_rect.size.width + 60.0;
|
||||
current_y = if left { self.y_left } else { self.y_right };
|
||||
current_y = if left { draw_state.y_left } else { draw_state.y_right };
|
||||
|
||||
for counter in counters {
|
||||
let rect = debug_renderer.add_text(
|
||||
@ -826,9 +838,9 @@ impl Profiler {
|
||||
);
|
||||
let new_y = total_rect.origin.y + total_rect.size.height + 30.0;
|
||||
if left {
|
||||
self.y_left = new_y;
|
||||
draw_state.y_left = new_y;
|
||||
} else {
|
||||
self.y_right = new_y;
|
||||
draw_state.y_right = new_y;
|
||||
}
|
||||
}
|
||||
|
||||
@ -840,15 +852,15 @@ impl Profiler {
|
||||
debug_renderer: &mut DebugRenderer,
|
||||
) -> Rect<f32> {
|
||||
let mut rect = debug_renderer.add_text(
|
||||
self.x_left,
|
||||
self.y_left,
|
||||
self.draw_state.x_left,
|
||||
self.draw_state.y_left,
|
||||
label,
|
||||
label_color,
|
||||
);
|
||||
|
||||
let x_base = rect.origin.x + rect.size.width + 10.0;
|
||||
let height = debug_renderer.line_height();
|
||||
let width = (self.x_right - 30.0 - x_base).max(0.0);
|
||||
let width = (self.draw_state.x_right - 30.0 - x_base).max(0.0);
|
||||
let total_value = counters.last().unwrap().1.value;
|
||||
let scale = width / total_value as f32;
|
||||
let mut x_current = x_base;
|
||||
@ -866,7 +878,7 @@ impl Profiler {
|
||||
x_current = x_stop;
|
||||
}
|
||||
|
||||
self.y_left += height;
|
||||
self.draw_state.y_left += height;
|
||||
|
||||
rect.size.width += width + 10.0;
|
||||
rect
|
||||
@ -922,10 +934,31 @@ impl Profiler {
|
||||
ColorF::new(0.2, 0.2, 0.2, 0.8).into(),
|
||||
);
|
||||
|
||||
self.y_left = total_rect.origin.y + total_rect.size.height + 30.0;
|
||||
self.draw_state.y_left = total_rect.origin.y + total_rect.size.height + 30.0;
|
||||
}
|
||||
|
||||
pub fn draw_profile(
|
||||
fn draw_compact_profile(
|
||||
&mut self,
|
||||
renderer_profile: &RendererProfileCounters,
|
||||
debug_renderer: &mut DebugRenderer,
|
||||
) {
|
||||
Profiler::draw_counters(
|
||||
&[
|
||||
&renderer_profile.frame_time as &ProfileCounter,
|
||||
&renderer_profile.color_targets,
|
||||
&renderer_profile.alpha_targets,
|
||||
&renderer_profile.draw_calls,
|
||||
&self.backend_time,
|
||||
&self.compositor_time,
|
||||
&self.gpu_time,
|
||||
],
|
||||
debug_renderer,
|
||||
true,
|
||||
&mut self.draw_state,
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_full_profile(
|
||||
&mut self,
|
||||
frame_profiles: &[FrameProfileCounters],
|
||||
backend_profile: &BackendProfileCounters,
|
||||
@ -935,36 +968,34 @@ impl Profiler {
|
||||
screen_fraction: f32,
|
||||
debug_renderer: &mut DebugRenderer,
|
||||
) {
|
||||
self.x_left = 20.0;
|
||||
self.y_left = 40.0;
|
||||
self.x_right = 450.0;
|
||||
self.y_right = 40.0;
|
||||
|
||||
let mut gpu_time = 0;
|
||||
let gpu_timers = mem::replace(&mut renderer_timers.gpu_samples, Vec::new());
|
||||
for sample in &gpu_timers {
|
||||
gpu_time += sample.time_ns;
|
||||
}
|
||||
renderer_timers.gpu_time.set(gpu_time);
|
||||
|
||||
self.draw_counters(&[&renderer_profile.frame_time], debug_renderer, true);
|
||||
self.draw_counters(&[&renderer_profile.frame_counter], debug_renderer, true);
|
||||
Profiler::draw_counters(
|
||||
&[
|
||||
&renderer_profile.frame_time as &ProfileCounter,
|
||||
&renderer_profile.frame_counter,
|
||||
&renderer_profile.color_targets,
|
||||
&renderer_profile.alpha_targets,
|
||||
],
|
||||
debug_renderer,
|
||||
true,
|
||||
&mut self.draw_state
|
||||
);
|
||||
|
||||
self.draw_gpu_cache_bars(
|
||||
&backend_profile.resources.gpu_cache,
|
||||
debug_renderer,
|
||||
);
|
||||
|
||||
self.draw_counters(
|
||||
Profiler::draw_counters(
|
||||
&[
|
||||
&backend_profile.resources.font_templates,
|
||||
&backend_profile.resources.image_templates,
|
||||
],
|
||||
debug_renderer,
|
||||
true,
|
||||
&mut self.draw_state
|
||||
);
|
||||
|
||||
self.draw_counters(
|
||||
Profiler::draw_counters(
|
||||
&[
|
||||
&backend_profile.resources.texture_cache.pages_a8_linear,
|
||||
&backend_profile.resources.texture_cache.pages_rgb8_linear,
|
||||
@ -975,9 +1006,10 @@ impl Profiler {
|
||||
],
|
||||
debug_renderer,
|
||||
true,
|
||||
&mut self.draw_state
|
||||
);
|
||||
|
||||
self.draw_counters(
|
||||
Profiler::draw_counters(
|
||||
&[
|
||||
&backend_profile.ipc.build_time,
|
||||
&backend_profile.ipc.send_time,
|
||||
@ -986,29 +1018,29 @@ impl Profiler {
|
||||
],
|
||||
debug_renderer,
|
||||
true,
|
||||
&mut self.draw_state
|
||||
);
|
||||
|
||||
for frame_profile in frame_profiles {
|
||||
self.draw_counters(
|
||||
Profiler::draw_counters(
|
||||
&[
|
||||
&frame_profile.total_primitives,
|
||||
&frame_profile.visible_primitives,
|
||||
&frame_profile.passes,
|
||||
&frame_profile.color_targets,
|
||||
&frame_profile.alpha_targets,
|
||||
],
|
||||
debug_renderer,
|
||||
true,
|
||||
&mut self.draw_state
|
||||
);
|
||||
}
|
||||
|
||||
self.draw_counters(
|
||||
Profiler::draw_counters(
|
||||
&[&renderer_profile.draw_calls, &renderer_profile.vertices],
|
||||
debug_renderer,
|
||||
true,
|
||||
&mut self.draw_state
|
||||
);
|
||||
|
||||
self.draw_counters(
|
||||
Profiler::draw_counters(
|
||||
&[
|
||||
&backend_profile.total_time,
|
||||
&renderer_timers.cpu_time,
|
||||
@ -1016,6 +1048,7 @@ impl Profiler {
|
||||
],
|
||||
debug_renderer,
|
||||
false,
|
||||
&mut self.draw_state
|
||||
);
|
||||
|
||||
if !gpu_samplers.is_empty() {
|
||||
@ -1034,9 +1067,63 @@ impl Profiler {
|
||||
}),
|
||||
}
|
||||
}
|
||||
self.draw_counters(&samplers, debug_renderer, false);
|
||||
let samplers: Vec<&ProfileCounter> = samplers.iter().map(|sampler| {
|
||||
sampler as &ProfileCounter
|
||||
}).collect();
|
||||
Profiler::draw_counters(
|
||||
&samplers,
|
||||
debug_renderer,
|
||||
false,
|
||||
&mut self.draw_state,
|
||||
);
|
||||
}
|
||||
|
||||
let rect =
|
||||
self.backend_time
|
||||
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "CPU (backend)", debug_renderer);
|
||||
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
|
||||
let rect = self.compositor_time.draw_graph(
|
||||
self.draw_state.x_right,
|
||||
self.draw_state.y_right,
|
||||
"CPU (compositor)",
|
||||
debug_renderer,
|
||||
);
|
||||
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
|
||||
let rect =
|
||||
self.ipc_time
|
||||
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "DisplayList IPC", debug_renderer);
|
||||
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
|
||||
let rect = self.gpu_time
|
||||
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "GPU", debug_renderer);
|
||||
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
|
||||
let rect = self.gpu_frames
|
||||
.draw(self.draw_state.x_left, f32::max(self.draw_state.y_left, self.draw_state.y_right), debug_renderer);
|
||||
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
|
||||
}
|
||||
|
||||
pub fn draw_profile(
|
||||
&mut self,
|
||||
frame_profiles: &[FrameProfileCounters],
|
||||
backend_profile: &BackendProfileCounters,
|
||||
renderer_profile: &RendererProfileCounters,
|
||||
renderer_timers: &mut RendererProfileTimers,
|
||||
gpu_samplers: &[GpuSampler<GpuProfileTag>],
|
||||
screen_fraction: f32,
|
||||
debug_renderer: &mut DebugRenderer,
|
||||
compact: bool,
|
||||
) {
|
||||
self.draw_state.x_left = 20.0;
|
||||
self.draw_state.y_left = 40.0;
|
||||
self.draw_state.x_right = 450.0;
|
||||
self.draw_state.y_right = 40.0;
|
||||
|
||||
let mut gpu_time = 0;
|
||||
let gpu_timers = mem::replace(&mut renderer_timers.gpu_samples, Vec::new());
|
||||
for sample in &gpu_timers {
|
||||
gpu_time += sample.time_ns;
|
||||
}
|
||||
renderer_timers.gpu_time.set(gpu_time);
|
||||
|
||||
self.backend_time
|
||||
.push(backend_profile.total_time.nanoseconds);
|
||||
self.compositor_time
|
||||
@ -1046,27 +1133,21 @@ impl Profiler {
|
||||
self.gpu_time.push(gpu_time);
|
||||
self.gpu_frames.push(gpu_time, gpu_timers);
|
||||
|
||||
|
||||
let rect =
|
||||
self.backend_time
|
||||
.draw_graph(self.x_right, self.y_right, "CPU (backend)", debug_renderer);
|
||||
self.y_right += rect.size.height + PROFILE_PADDING;
|
||||
let rect = self.compositor_time.draw_graph(
|
||||
self.x_right,
|
||||
self.y_right,
|
||||
"CPU (compositor)",
|
||||
debug_renderer,
|
||||
);
|
||||
self.y_right += rect.size.height + PROFILE_PADDING;
|
||||
let rect =
|
||||
self.ipc_time
|
||||
.draw_graph(self.x_right, self.y_right, "DisplayList IPC", debug_renderer);
|
||||
self.y_right += rect.size.height + PROFILE_PADDING;
|
||||
let rect = self.gpu_time
|
||||
.draw_graph(self.x_right, self.y_right, "GPU", debug_renderer);
|
||||
self.y_right += rect.size.height + PROFILE_PADDING;
|
||||
let rect = self.gpu_frames
|
||||
.draw(self.x_left, f32::max(self.y_left, self.y_right), debug_renderer);
|
||||
self.y_right += rect.size.height + PROFILE_PADDING;
|
||||
if compact {
|
||||
self.draw_compact_profile(
|
||||
renderer_profile,
|
||||
debug_renderer,
|
||||
);
|
||||
} else {
|
||||
self.draw_full_profile(
|
||||
frame_profiles,
|
||||
backend_profile,
|
||||
renderer_profile,
|
||||
renderer_timers,
|
||||
gpu_samplers,
|
||||
screen_fraction,
|
||||
debug_renderer,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use clip::{ClipSourcesWeakHandle};
|
||||
use clip_scroll_tree::CoordinateSystemId;
|
||||
use euclid::TypedSize2D;
|
||||
use gpu_types::{ClipScrollNodeIndex};
|
||||
use internal_types::RenderPassIndex;
|
||||
use picture::RasterizationSpace;
|
||||
use prim_store::{PrimitiveIndex};
|
||||
#[cfg(feature = "debugger")]
|
||||
@ -241,6 +242,7 @@ pub struct RenderTask {
|
||||
pub children: Vec<RenderTaskId>,
|
||||
pub kind: RenderTaskKind,
|
||||
pub clear_mode: ClearMode,
|
||||
pub pass_index: Option<RenderPassIndex>,
|
||||
}
|
||||
|
||||
impl RenderTask {
|
||||
@ -276,6 +278,7 @@ impl RenderTask {
|
||||
rasterization_kind,
|
||||
}),
|
||||
clear_mode,
|
||||
pass_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,6 +289,7 @@ impl RenderTask {
|
||||
location: RenderTaskLocation::Dynamic(None, screen_rect.size),
|
||||
kind: RenderTaskKind::Readback(screen_rect),
|
||||
clear_mode: ClearMode::Transparent,
|
||||
pass_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,6 +309,7 @@ impl RenderTask {
|
||||
coordinate_system_id: prim_coordinate_system_id,
|
||||
}),
|
||||
clear_mode: ClearMode::One,
|
||||
pass_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,6 +380,7 @@ impl RenderTask {
|
||||
scale_factor,
|
||||
}),
|
||||
clear_mode,
|
||||
pass_index: None,
|
||||
};
|
||||
|
||||
let blur_task_v_id = render_tasks.add(blur_task_v);
|
||||
@ -394,6 +400,7 @@ impl RenderTask {
|
||||
scale_factor,
|
||||
}),
|
||||
clear_mode,
|
||||
pass_index: None,
|
||||
};
|
||||
|
||||
blur_task_h
|
||||
@ -417,6 +424,7 @@ impl RenderTask {
|
||||
RenderTargetKind::Color => ClearMode::Transparent,
|
||||
RenderTargetKind::Alpha => ClearMode::One,
|
||||
},
|
||||
pass_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
|
||||
use gpu_types::PrimitiveInstance;
|
||||
use internal_types::{BatchTextures, SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE};
|
||||
use internal_types::{CacheTextureId, FastHashMap, RenderedDocument, ResultMsg, TextureUpdateOp};
|
||||
use internal_types::{DebugOutput, RenderTargetInfo, TextureUpdateList, TextureUpdateSource};
|
||||
use internal_types::{DebugOutput, RenderPassIndex, RenderTargetInfo, TextureUpdateList, TextureUpdateSource};
|
||||
use profiler::{BackendProfileCounters, Profiler};
|
||||
use profiler::{GpuProfileTag, RendererProfileCounters, RendererProfileTimers};
|
||||
use query::{GpuProfiler, GpuTimer};
|
||||
@ -65,8 +65,8 @@ use std::thread;
|
||||
use texture_cache::TextureCache;
|
||||
use thread_profiler::{register_thread_with_profiler, write_profile};
|
||||
use tiling::{AlphaRenderTarget, ColorRenderTarget};
|
||||
use tiling::{RenderPass, RenderPassKind, RenderTargetKind, RenderTargetList};
|
||||
use tiling::{BatchKey, BatchKind, BrushBatchKind, Frame, RenderTarget, ScalingInfo, TransformBatchKind};
|
||||
use tiling::{RenderPass, RenderPassKind, RenderTargetList};
|
||||
use tiling::{BatchKey, BatchKind, BrushBatchKind, BrushImageSourceKind, Frame, RenderTarget, ScalingInfo, TransformBatchKind};
|
||||
use time::precise_time_ns;
|
||||
use util::TransformedRectKind;
|
||||
|
||||
@ -256,6 +256,7 @@ bitflags! {
|
||||
const GPU_SAMPLE_QUERIES= 1 << 5;
|
||||
const DISABLE_BATCHING = 1 << 6;
|
||||
const EPOCHS = 1 << 7;
|
||||
const COMPACT_PROFILER = 1 << 8;
|
||||
}
|
||||
}
|
||||
|
||||
@ -551,6 +552,8 @@ impl CpuProfile {
|
||||
}
|
||||
}
|
||||
|
||||
struct RenderTargetPoolId(usize);
|
||||
|
||||
struct SourceTextureResolver {
|
||||
/// A vector for fast resolves of texture cache IDs to
|
||||
/// native texture IDs. This maps to a free-list managed
|
||||
@ -573,6 +576,11 @@ struct SourceTextureResolver {
|
||||
/// The current cache textures.
|
||||
cache_rgba8_texture: Option<Texture>,
|
||||
cache_a8_texture: Option<Texture>,
|
||||
|
||||
pass_rgba8_textures: FastHashMap<RenderPassIndex, RenderTargetPoolId>,
|
||||
pass_a8_textures: FastHashMap<RenderPassIndex, RenderTargetPoolId>,
|
||||
|
||||
render_target_pool: Vec<Texture>,
|
||||
}
|
||||
|
||||
impl SourceTextureResolver {
|
||||
@ -595,6 +603,9 @@ impl SourceTextureResolver {
|
||||
dummy_cache_texture,
|
||||
cache_a8_texture: None,
|
||||
cache_rgba8_texture: None,
|
||||
pass_rgba8_textures: FastHashMap::default(),
|
||||
pass_a8_textures: FastHashMap::default(),
|
||||
render_target_pool: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -604,27 +615,44 @@ impl SourceTextureResolver {
|
||||
for texture in self.cache_texture_map {
|
||||
device.delete_texture(texture);
|
||||
}
|
||||
|
||||
for texture in self.render_target_pool {
|
||||
device.delete_texture(texture);
|
||||
}
|
||||
}
|
||||
|
||||
fn begin_frame(&self) {
|
||||
fn begin_frame(&mut self) {
|
||||
assert!(self.cache_rgba8_texture.is_none());
|
||||
assert!(self.cache_a8_texture.is_none());
|
||||
|
||||
self.pass_rgba8_textures.clear();
|
||||
self.pass_a8_textures.clear();
|
||||
}
|
||||
|
||||
fn end_frame(&mut self, pool: &mut Vec<Texture>) {
|
||||
fn end_frame(&mut self, pass_index: RenderPassIndex) {
|
||||
// return the cached targets to the pool
|
||||
self.end_pass(None, None, pool)
|
||||
self.end_pass(None, None, pass_index)
|
||||
}
|
||||
|
||||
fn end_pass(
|
||||
&mut self,
|
||||
a8_texture: Option<Texture>,
|
||||
rgba8_texture: Option<Texture>,
|
||||
pool: &mut Vec<Texture>,
|
||||
pass_index: RenderPassIndex,
|
||||
) {
|
||||
// If we have cache textures from previous pass, return them to the pool.
|
||||
pool.extend(self.cache_rgba8_texture.take());
|
||||
pool.extend(self.cache_a8_texture.take());
|
||||
// Also assign the pool index of those cache textures to last pass's index because this is
|
||||
// the result of last pass.
|
||||
if let Some(texture) = self.cache_rgba8_texture.take() {
|
||||
self.pass_rgba8_textures.insert(
|
||||
RenderPassIndex(pass_index.0 - 1), RenderTargetPoolId(self.render_target_pool.len()));
|
||||
self.render_target_pool.push(texture);
|
||||
}
|
||||
if let Some(texture) = self.cache_a8_texture.take() {
|
||||
self.pass_a8_textures.insert(
|
||||
RenderPassIndex(pass_index.0 - 1), RenderTargetPoolId(self.render_target_pool.len()));
|
||||
self.render_target_pool.push(texture);
|
||||
}
|
||||
|
||||
// We have another pass to process, make these textures available
|
||||
// as inputs to the next pass.
|
||||
@ -658,6 +686,18 @@ impl SourceTextureResolver {
|
||||
let texture = &self.cache_texture_map[index.0];
|
||||
device.bind_texture(sampler, texture);
|
||||
}
|
||||
SourceTexture::RenderTaskCacheRGBA8(pass_index) => {
|
||||
let pool_index = self.pass_rgba8_textures
|
||||
.get(&pass_index)
|
||||
.expect("BUG: pass_index doesn't map to pool_index");
|
||||
device.bind_texture(sampler, &self.render_target_pool[pool_index.0])
|
||||
}
|
||||
SourceTexture::RenderTaskCacheA8(pass_index) => {
|
||||
let pool_index = self.pass_a8_textures
|
||||
.get(&pass_index)
|
||||
.expect("BUG: pass_index doesn't map to pool_index");
|
||||
device.bind_texture(sampler, &self.render_target_pool[pool_index.0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -681,6 +721,18 @@ impl SourceTextureResolver {
|
||||
panic!("BUG: External textures cannot be resolved, they can only be bound.");
|
||||
}
|
||||
SourceTexture::TextureCache(index) => Some(&self.cache_texture_map[index.0]),
|
||||
SourceTexture::RenderTaskCacheRGBA8(pass_index) => {
|
||||
let pool_index = self.pass_rgba8_textures
|
||||
.get(&pass_index)
|
||||
.expect("BUG: pass_index doesn't map to pool_index");
|
||||
Some(&self.render_target_pool[pool_index.0])
|
||||
},
|
||||
SourceTexture::RenderTaskCacheA8(pass_index) => {
|
||||
let pool_index = self.pass_a8_textures
|
||||
.get(&pass_index)
|
||||
.expect("BUG: pass_index doesn't map to pool_index");
|
||||
Some(&self.render_target_pool[pool_index.0])
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1349,6 +1401,7 @@ pub struct Renderer {
|
||||
brush_mask_corner: LazilyCompiledShader,
|
||||
brush_mask_rounded_rect: LazilyCompiledShader,
|
||||
brush_image_rgba8: BrushShader,
|
||||
brush_image_rgba8_alpha_mask: BrushShader,
|
||||
brush_image_a8: BrushShader,
|
||||
brush_solid: BrushShader,
|
||||
|
||||
@ -1394,8 +1447,6 @@ pub struct Renderer {
|
||||
profiler: Profiler,
|
||||
last_time: u64,
|
||||
|
||||
render_target_pool: Vec<Texture>,
|
||||
|
||||
gpu_profile: GpuProfiler<GpuProfileTag>,
|
||||
prim_vao: VAO,
|
||||
blur_vao: VAO,
|
||||
@ -1574,6 +1625,13 @@ impl Renderer {
|
||||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let brush_image_rgba8_alpha_mask = try!{
|
||||
BrushShader::new("brush_image",
|
||||
&mut device,
|
||||
&["COLOR_TARGET_ALPHA_MASK"],
|
||||
options.precache_shaders)
|
||||
};
|
||||
|
||||
let cs_blur_a8 = try!{
|
||||
LazilyCompiledShader::new(ShaderKind::Cache(VertexArrayKind::Blur),
|
||||
"cs_blur",
|
||||
@ -1998,6 +2056,7 @@ impl Renderer {
|
||||
brush_mask_corner,
|
||||
brush_mask_rounded_rect,
|
||||
brush_image_rgba8,
|
||||
brush_image_rgba8_alpha_mask,
|
||||
brush_image_a8,
|
||||
brush_solid,
|
||||
cs_clip_rectangle,
|
||||
@ -2027,7 +2086,6 @@ impl Renderer {
|
||||
clear_color: options.clear_color,
|
||||
enable_clear_scissor: options.enable_clear_scissor,
|
||||
last_time: 0,
|
||||
render_target_pool: Vec::new(),
|
||||
gpu_profile,
|
||||
prim_vao,
|
||||
blur_vao,
|
||||
@ -2549,6 +2607,7 @@ impl Renderer {
|
||||
&profile_samplers,
|
||||
screen_fraction,
|
||||
&mut self.debug,
|
||||
self.debug_flags.contains(DebugFlags::COMPACT_PROFILER),
|
||||
);
|
||||
}
|
||||
|
||||
@ -2778,8 +2837,9 @@ impl Renderer {
|
||||
}
|
||||
BrushBatchKind::Image(target_kind) => {
|
||||
let shader = match target_kind {
|
||||
RenderTargetKind::Alpha => &mut self.brush_image_a8,
|
||||
RenderTargetKind::Color => &mut self.brush_image_rgba8,
|
||||
BrushImageSourceKind::Alpha => &mut self.brush_image_a8,
|
||||
BrushImageSourceKind::Color => &mut self.brush_image_rgba8,
|
||||
BrushImageSourceKind::ColorAlphaMask => &mut self.brush_image_rgba8_alpha_mask,
|
||||
};
|
||||
shader.bind(
|
||||
&mut self.device,
|
||||
@ -2987,6 +3047,7 @@ impl Renderer {
|
||||
frame_id: FrameId,
|
||||
stats: &mut RendererStats,
|
||||
) {
|
||||
self.profile_counters.color_targets.inc();
|
||||
let _gm = self.gpu_profile.start_marker("color target");
|
||||
|
||||
// sanity check for the depth buffer
|
||||
@ -3408,6 +3469,7 @@ impl Renderer {
|
||||
render_tasks: &RenderTaskTree,
|
||||
stats: &mut RendererStats,
|
||||
) {
|
||||
self.profile_counters.alpha_targets.inc();
|
||||
let _gm = self.gpu_profile.start_marker("alpha target");
|
||||
let alpha_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_ALPHA);
|
||||
|
||||
@ -3684,7 +3746,7 @@ impl Renderer {
|
||||
num_layers: list.targets.len() as _,
|
||||
format: list.format,
|
||||
};
|
||||
let index = self.render_target_pool
|
||||
let index = self.texture_resolver.render_target_pool
|
||||
.iter()
|
||||
.position(|texture| {
|
||||
selector == TargetSelector {
|
||||
@ -3694,14 +3756,14 @@ impl Renderer {
|
||||
}
|
||||
});
|
||||
match index {
|
||||
Some(pos) => self.render_target_pool.swap_remove(pos),
|
||||
Some(pos) => self.texture_resolver.render_target_pool.swap_remove(pos),
|
||||
None => return,
|
||||
}
|
||||
} else {
|
||||
if list.texture.is_some() {
|
||||
return
|
||||
}
|
||||
match self.render_target_pool.pop() {
|
||||
match self.texture_resolver.render_target_pool.pop() {
|
||||
Some(texture) => texture,
|
||||
None => self.device.create_texture(TextureTarget::Array),
|
||||
}
|
||||
@ -3885,7 +3947,7 @@ impl Renderer {
|
||||
self.texture_resolver.end_pass(
|
||||
cur_alpha,
|
||||
cur_color,
|
||||
&mut self.render_target_pool,
|
||||
RenderPassIndex(pass_index),
|
||||
);
|
||||
|
||||
// After completing the first pass, make the A8 target available as an
|
||||
@ -3900,7 +3962,7 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
self.texture_resolver.end_frame(&mut self.render_target_pool);
|
||||
self.texture_resolver.end_frame(RenderPassIndex(frame.passes.len()));
|
||||
self.draw_render_target_debug(framebuffer_size);
|
||||
self.draw_texture_cache_debug(framebuffer_size);
|
||||
self.draw_epoch_debug();
|
||||
@ -3967,7 +4029,7 @@ impl Renderer {
|
||||
let mut spacing = 16;
|
||||
let mut size = 512;
|
||||
let fb_width = framebuffer_size.width as i32;
|
||||
let num_layers: i32 = self.render_target_pool
|
||||
let num_layers: i32 = self.texture_resolver.render_target_pool
|
||||
.iter()
|
||||
.map(|texture| texture.get_render_target_layer_count() as i32)
|
||||
.sum();
|
||||
@ -3979,7 +4041,7 @@ impl Renderer {
|
||||
}
|
||||
|
||||
let mut target_index = 0;
|
||||
for texture in &self.render_target_pool {
|
||||
for texture in &self.texture_resolver.render_target_pool {
|
||||
let dimensions = texture.get_dimensions();
|
||||
let src_rect = DeviceIntRect::new(DeviceIntPoint::zero(), dimensions.to_i32());
|
||||
|
||||
@ -4121,9 +4183,6 @@ impl Renderer {
|
||||
}
|
||||
self.node_data_texture.deinit(&mut self.device);
|
||||
self.render_task_texture.deinit(&mut self.device);
|
||||
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);
|
||||
@ -4137,6 +4196,7 @@ impl Renderer {
|
||||
self.brush_mask_rounded_rect.deinit(&mut self.device);
|
||||
self.brush_mask_corner.deinit(&mut self.device);
|
||||
self.brush_image_rgba8.deinit(&mut self.device);
|
||||
self.brush_image_rgba8_alpha_mask.deinit(&mut self.device);
|
||||
self.brush_image_a8.deinit(&mut self.device);
|
||||
self.brush_solid.deinit(&mut self.device);
|
||||
self.cs_clip_rectangle.deinit(&mut self.device);
|
||||
|
@ -162,7 +162,8 @@ impl FilterOpHelpers for FilterOp {
|
||||
FilterOp::HueRotate(..) |
|
||||
FilterOp::Invert(..) |
|
||||
FilterOp::Saturate(..) |
|
||||
FilterOp::Sepia(..) => true,
|
||||
FilterOp::Sepia(..) |
|
||||
FilterOp::DropShadow(..) => true,
|
||||
FilterOp::Opacity(_, amount) => {
|
||||
amount > OPACITY_EPSILON
|
||||
}
|
||||
@ -180,6 +181,9 @@ impl FilterOpHelpers for FilterOp {
|
||||
FilterOp::Opacity(_, amount) => amount >= 1.0,
|
||||
FilterOp::Saturate(amount) => amount == 1.0,
|
||||
FilterOp::Sepia(amount) => amount == 0.0,
|
||||
FilterOp::DropShadow(offset, blur, _) => {
|
||||
offset.x == 0.0 && offset.y == 0.0 && blur == 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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::{DeviceIntRect, DeviceIntSize, device_length, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
|
||||
use api::{DocumentLayer, ExternalImageType, FilterOp, FontRenderMode};
|
||||
use api::{ImageFormat, ImageRendering};
|
||||
use api::{LayerRect, MixBlendMode, PipelineId};
|
||||
@ -20,7 +20,7 @@ use gpu_types::{BlurDirection, BlurInstance, BrushInstance, BrushImageKind, Clip
|
||||
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
|
||||
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
|
||||
use internal_types::{FastHashMap, SourceTexture};
|
||||
use internal_types::{BatchTextures};
|
||||
use internal_types::{BatchTextures, RenderPassIndex};
|
||||
use picture::{PictureCompositeMode, PictureKind, PicturePrimitive, RasterizationSpace};
|
||||
use plane_split::{BspSplitter, Polygon, Splitter};
|
||||
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
|
||||
@ -148,9 +148,6 @@ pub struct ScrollbarPrimitive {
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct RenderTargetIndex(pub usize);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct RenderPassIndex(isize);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DynamicTaskInfo {
|
||||
task_id: RenderTaskId,
|
||||
@ -627,7 +624,8 @@ fn add_to_batch(
|
||||
match picture.kind {
|
||||
PictureKind::TextShadow { .. } => {
|
||||
let kind = BatchKind::Brush(
|
||||
BrushBatchKind::Image(picture.target_kind()),
|
||||
BrushBatchKind::Image(
|
||||
BrushImageSourceKind::from_render_target_kind(picture.target_kind())),
|
||||
);
|
||||
let key = BatchKey::new(kind, blend_mode, textures);
|
||||
let batch = batch_list.get_suitable_batch(key, item_bounding_rect);
|
||||
@ -647,7 +645,8 @@ fn add_to_batch(
|
||||
}
|
||||
PictureKind::BoxShadow { radii_kind, .. } => {
|
||||
let kind = BatchKind::Brush(
|
||||
BrushBatchKind::Image(picture.target_kind()),
|
||||
BrushBatchKind::Image(
|
||||
BrushImageSourceKind::from_render_target_kind(picture.target_kind())),
|
||||
);
|
||||
let key = BatchKey::new(kind, blend_mode, textures);
|
||||
let batch = batch_list.get_suitable_batch(key, item_bounding_rect);
|
||||
@ -676,7 +675,7 @@ fn add_to_batch(
|
||||
}
|
||||
PictureKind::Image {
|
||||
composite_mode,
|
||||
readback_render_task_id,
|
||||
secondary_render_task_id,
|
||||
is_in_3d_context,
|
||||
reference_frame_id,
|
||||
real_local_rect,
|
||||
@ -717,7 +716,7 @@ fn add_to_batch(
|
||||
let key = BatchKey::new(
|
||||
BatchKind::HardwareComposite,
|
||||
BlendMode::PremultipliedAlpha,
|
||||
BatchTextures::no_texture(),
|
||||
BatchTextures::render_target_cache(),
|
||||
);
|
||||
let batch = batch_list.get_suitable_batch(key, &item_bounding_rect);
|
||||
let instance = CompositePrimitiveInstance::new(
|
||||
@ -733,6 +732,61 @@ fn add_to_batch(
|
||||
|
||||
batch.push(PrimitiveInstance::from(instance));
|
||||
}
|
||||
FilterOp::DropShadow(offset, _, _) => {
|
||||
let kind = BatchKind::Brush(
|
||||
BrushBatchKind::Image(BrushImageSourceKind::ColorAlphaMask),
|
||||
);
|
||||
let key = BatchKey::new(kind, blend_mode, textures);
|
||||
|
||||
let instance = BrushInstance {
|
||||
picture_address: task_address,
|
||||
prim_address: prim_cache_address,
|
||||
clip_id,
|
||||
scroll_id,
|
||||
clip_task_address,
|
||||
z,
|
||||
segment_kind: 0,
|
||||
user_data0: cache_task_address.0 as i32,
|
||||
user_data1: BrushImageKind::Simple as i32,
|
||||
};
|
||||
|
||||
{
|
||||
let batch = batch_list.get_suitable_batch(key, item_bounding_rect);
|
||||
batch.push(PrimitiveInstance::from(instance));
|
||||
}
|
||||
|
||||
let secondary_id = secondary_render_task_id.expect("no secondary!?");
|
||||
let render_task = &render_tasks[secondary_id];
|
||||
let secondary_task_address = render_tasks.get_task_address(secondary_id);
|
||||
let render_pass_index = render_task.pass_index.expect("no render_pass_index!?");
|
||||
let secondary_textures = BatchTextures {
|
||||
colors: [
|
||||
SourceTexture::RenderTaskCacheRGBA8(render_pass_index),
|
||||
SourceTexture::Invalid,
|
||||
SourceTexture::Invalid,
|
||||
],
|
||||
};
|
||||
let key = BatchKey::new(
|
||||
BatchKind::HardwareComposite,
|
||||
BlendMode::PremultipliedAlpha,
|
||||
secondary_textures,
|
||||
);
|
||||
let batch = batch_list.get_suitable_batch(key, &item_bounding_rect);
|
||||
let device_offset_x = device_length(offset.x, ctx.device_pixel_ratio);
|
||||
let device_offset_y = device_length(offset.y, ctx.device_pixel_ratio);
|
||||
let instance = CompositePrimitiveInstance::new(
|
||||
task_address,
|
||||
secondary_task_address,
|
||||
RenderTaskAddress(0),
|
||||
item_bounding_rect.origin.x - device_offset_x.0,
|
||||
item_bounding_rect.origin.y - device_offset_y.0,
|
||||
z,
|
||||
item_bounding_rect.size.width,
|
||||
item_bounding_rect.size.height,
|
||||
);
|
||||
|
||||
batch.push(PrimitiveInstance::from(instance));
|
||||
}
|
||||
_ => {
|
||||
let key = BatchKey::new(
|
||||
BatchKind::Blend,
|
||||
@ -751,6 +805,7 @@ fn add_to_batch(
|
||||
FilterOp::Sepia(amount) => (6, amount),
|
||||
FilterOp::Brightness(amount) => (7, amount),
|
||||
FilterOp::Opacity(_, amount) => (8, amount),
|
||||
FilterOp::DropShadow(..) => unreachable!(),
|
||||
};
|
||||
|
||||
let amount = (amount * 65535.0).round() as i32;
|
||||
@ -772,7 +827,7 @@ fn add_to_batch(
|
||||
}
|
||||
}
|
||||
PictureCompositeMode::MixBlend(mode) => {
|
||||
let backdrop_id = readback_render_task_id.expect("no backdrop!?");
|
||||
let backdrop_id = secondary_render_task_id.expect("no backdrop!?");
|
||||
|
||||
let key = BatchKey::new(
|
||||
BatchKind::Composite {
|
||||
@ -805,7 +860,7 @@ fn add_to_batch(
|
||||
let key = BatchKey::new(
|
||||
BatchKind::HardwareComposite,
|
||||
BlendMode::PremultipliedAlpha,
|
||||
BatchTextures::no_texture(),
|
||||
BatchTextures::render_target_cache(),
|
||||
);
|
||||
let batch = batch_list.get_suitable_batch(key, &item_bounding_rect);
|
||||
let instance = CompositePrimitiveInstance::new(
|
||||
@ -1796,6 +1851,7 @@ impl RenderPass {
|
||||
render_tasks: &mut RenderTaskTree,
|
||||
deferred_resolves: &mut Vec<DeferredResolve>,
|
||||
clip_store: &ClipStore,
|
||||
pass_index: RenderPassIndex,
|
||||
) {
|
||||
profile_scope!("RenderPass::build");
|
||||
|
||||
@ -1803,6 +1859,7 @@ impl RenderPass {
|
||||
RenderPassKind::MainFramebuffer(ref mut target) => {
|
||||
for &task_id in &self.tasks {
|
||||
assert_eq!(render_tasks[task_id].target_kind(), RenderTargetKind::Color);
|
||||
render_tasks[task_id].pass_index = Some(pass_index);
|
||||
target.add_task(task_id, ctx, gpu_cache, render_tasks, clip_store);
|
||||
}
|
||||
target.build(ctx, gpu_cache, render_tasks, deferred_resolves);
|
||||
@ -1812,6 +1869,7 @@ impl RenderPass {
|
||||
for &task_id in &self.tasks {
|
||||
let target_kind = {
|
||||
let task = &mut render_tasks[task_id];
|
||||
task.pass_index = Some(pass_index);
|
||||
let target_kind = task.target_kind();
|
||||
|
||||
// Find a target to assign this task to, or create a new
|
||||
@ -1880,9 +1938,25 @@ pub enum TransformBatchKind {
|
||||
Line,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum BrushImageSourceKind {
|
||||
Alpha,
|
||||
Color,
|
||||
ColorAlphaMask,
|
||||
}
|
||||
|
||||
impl BrushImageSourceKind {
|
||||
pub fn from_render_target_kind(render_target_kind: RenderTargetKind) -> BrushImageSourceKind {
|
||||
match render_target_kind {
|
||||
RenderTargetKind::Color => BrushImageSourceKind::Color,
|
||||
RenderTargetKind::Alpha => BrushImageSourceKind::Alpha,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum BrushBatchKind {
|
||||
Image(RenderTargetKind),
|
||||
Image(BrushImageSourceKind),
|
||||
Solid,
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ serde = { version = "1.0", features = ["rc", "derive"] }
|
||||
time = "0.1"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation = "0.4"
|
||||
core-foundation = "0.4.6"
|
||||
core-graphics = "0.12.3"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
|
@ -458,6 +458,7 @@ pub enum FilterOp {
|
||||
Opacity(PropertyBinding<f32>, f32),
|
||||
Saturate(f32),
|
||||
Sepia(f32),
|
||||
DropShadow(LayoutVector2D, f32, ColorF),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
|
@ -21,7 +21,7 @@ default-features = false
|
||||
dwrote = "0.4.1"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation = "0.4"
|
||||
core-foundation = "0.4.6"
|
||||
core-graphics = "0.12.3"
|
||||
foreign-types = "0.3.0"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user