Bug 1429806 - Update webrender to commit eb9e1702df4b6dc036b649b3dd32ccc4bfbe43bf. r=jrmuizel

MozReview-Commit-ID: 7m0P5kgiWZF

--HG--
extra : rebase_source : 4543ca28be94c735c24120892b5eb254afabd677
This commit is contained in:
Kartikaya Gupta 2018-01-16 12:28:30 -05:00
Родитель f8a2d60a78
Коммит acf6b152ff
42 изменённых файлов: 1362 добавлений и 696 удалений

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

@ -175,4 +175,4 @@ Troubleshooting tips:
-------------------------------------------------------------------------------
The version of WebRender currently in the tree is:
722e8b104bf99d29d61ecb1fe456eebe89ad81fd
eb9e1702df4b6dc036b649b3dd32ccc4bfbe43bf

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

@ -35,7 +35,7 @@ serde_json = { optional = true, version = "1.0" }
serde = { optional = true, version = "1.0", features = ["serde_derive"] }
image = { optional = true, version = "0.17" }
base64 = { optional = true, version = "0.3.0" }
ron = { optional = true, version = "0.1.3" }
ron = { optional = true, version = "0.1.5" }
[dev-dependencies]
angle = {git = "https://github.com/servo/angle", branch = "servo"}

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

@ -0,0 +1,86 @@
/* 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/. */
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
#[path = "common/boilerplate.rs"]
mod boilerplate;
use boilerplate::{Example, HandyDandyRectBuilder};
use std::cmp;
use webrender::api::*;
struct App {
rect_count: usize,
}
impl Example for App {
fn render(
&mut self,
_api: &RenderApi,
builder: &mut DisplayListBuilder,
_resources: &mut ResourceUpdates,
_framebuffer_size: DeviceUintSize,
_pipeline_id: PipelineId,
_document_id: DocumentId,
) {
let bounds = (0, 0).to(1920, 1080);
let info = LayoutPrimitiveInfo {
local_clip: LocalClip::Rect(bounds),
.. LayoutPrimitiveInfo::new(bounds)
};
builder.push_stacking_context(
&info,
ScrollPolicy::Scrollable,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
);
for _ in 0 .. self.rect_count {
builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 0.05));
}
builder.pop_stacking_context();
}
fn on_event(
&mut self,
event: glutin::Event,
_api: &RenderApi,
_document_id: DocumentId
) -> bool {
match event {
glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(key)) => {
match key {
glutin::VirtualKeyCode::Right => {
self.rect_count += 1;
println!("rects = {}", self.rect_count);
}
glutin::VirtualKeyCode::Left => {
self.rect_count = cmp::max(self.rect_count, 1) - 1;
println!("rects = {}", self.rect_count);
}
_ => {}
};
}
_ => (),
}
true
}
}
fn main() {
let mut app = App {
rect_count: 1,
};
boilerplate::main_wrapper(&mut app, None);
}

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

@ -212,7 +212,7 @@ impl Example for App {
let image_mask_key = api.generate_image_key();
resources.add_image(
image_mask_key,
ImageDescriptor::new(2, 2, ImageFormat::A8, true),
ImageDescriptor::new(2, 2, ImageFormat::R8, true),
ImageData::new(vec![0, 80, 180, 255]),
None,
);

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

@ -85,7 +85,7 @@ fn render_blob(
texels.push(color.r * checker + tc);
texels.push(color.a * checker + tc);
}
api::ImageFormat::A8 => {
api::ImageFormat::R8 => {
texels.push(color.a * checker + tc);
}
_ => {
@ -265,6 +265,7 @@ impl Example for App {
api::LayoutSize::new(500.0, 500.0),
api::LayoutSize::new(0.0, 0.0),
api::ImageRendering::Auto,
api::AlphaType::PremultipliedAlpha,
blob_img1,
);
@ -274,6 +275,7 @@ impl Example for App {
api::LayoutSize::new(200.0, 200.0),
api::LayoutSize::new(0.0, 0.0),
api::ImageRendering::Auto,
api::AlphaType::PremultipliedAlpha,
blob_img2,
);

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

@ -64,6 +64,9 @@ impl HandyDandyRectBuilder for (i32, i32) {
pub trait Example {
const TITLE: &'static str = "WebRender Sample App";
const PRECACHE_SHADERS: bool = false;
const WIDTH: u32 = 1920;
const HEIGHT: u32 = 1080;
fn render(
&mut self,
api: &RenderApi,
@ -103,6 +106,7 @@ pub fn main_wrapper<E: Example>(
let window = glutin::WindowBuilder::new()
.with_title(E::TITLE)
.with_multitouch()
.with_dimensions(E::WIDTH, E::HEIGHT)
.with_gl(glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
opengles_version: (3, 0),
@ -224,6 +228,13 @@ pub fn main_wrapper<E: Example>(
) => {
renderer.toggle_debug_flags(webrender::DebugFlags::ALPHA_PRIM_DBG);
}
glutin::Event::KeyboardInput(
glutin::ElementState::Pressed,
_,
Some(glutin::VirtualKeyCode::S),
) => {
renderer.toggle_debug_flags(webrender::DebugFlags::COMPACT_PROFILER);
}
glutin::Event::KeyboardInput(
glutin::ElementState::Pressed,
_,

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

@ -164,6 +164,7 @@ impl Example for App {
info.rect.size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
self.external_image_key.unwrap()
);

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

@ -59,6 +59,7 @@ impl Example for App {
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
self.image_key,
);
@ -71,6 +72,7 @@ impl Example for App {
image_size,
LayoutSize::zero(),
ImageRendering::Pixelated,
AlphaType::PremultipliedAlpha,
self.image_key,
);

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

@ -147,6 +147,7 @@ impl Example for App {
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
*key,
);
}
@ -162,6 +163,7 @@ impl Example for App {
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
image_key,
);
}
@ -177,6 +179,7 @@ impl Example for App {
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
swap_key,
);
self.swap_index = 1 - self.swap_index;

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

@ -192,7 +192,7 @@ impl Example for App {
let yuv_chanel3 = api.generate_image_key();
resources.add_image(
yuv_chanel1,
ImageDescriptor::new(100, 100, ImageFormat::A8, true),
ImageDescriptor::new(100, 100, ImageFormat::R8, true),
ImageData::new(vec![127; 100 * 100]),
None,
);
@ -204,13 +204,13 @@ impl Example for App {
);
resources.add_image(
yuv_chanel2_1,
ImageDescriptor::new(100, 100, ImageFormat::A8, true),
ImageDescriptor::new(100, 100, ImageFormat::R8, true),
ImageData::new(vec![127; 100 * 100]),
None,
);
resources.add_image(
yuv_chanel3,
ImageDescriptor::new(100, 100, ImageFormat::A8, true),
ImageDescriptor::new(100, 100, ImageFormat::R8, true),
ImageData::new(vec![127; 100 * 100]),
None,
);

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

@ -23,6 +23,7 @@ struct BrushInstance {
int clip_address;
int z;
int segment_index;
int edge_mask;
ivec2 user_data;
};
@ -35,7 +36,8 @@ BrushInstance load_brush() {
bi.scroll_node_id = aData0.z % 65536;
bi.clip_address = aData0.w;
bi.z = aData1.x;
bi.segment_index = aData1.y;
bi.segment_index = aData1.y & 0xffff;
bi.edge_mask = aData1.y >> 16;
bi.user_data = aData1.zw;
return bi;
@ -125,7 +127,7 @@ void main(void) {
vLocalBounds = vec4(vec2(-1000000.0), vec2(1000000.0));
#endif
} else {
bvec4 edge_mask = notEqual(int(segment_data[1].x) & ivec4(1, 2, 4, 8), ivec4(0));
bvec4 edge_mask = notEqual(brush.edge_mask & ivec4(1, 2, 4, 8), ivec4(0));
vi = write_transform_vertex(
local_segment_rect,
brush_prim.local_rect,

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

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define VECS_PER_SPECIFIC_BRUSH 0
#define VECS_PER_SPECIFIC_BRUSH 1
#include shared,prim_shared,brush
@ -25,6 +25,16 @@ flat varying vec4 vColor;
#define BRUSH_IMAGE_MIRROR 2
#ifdef WR_VERTEX_SHADER
struct Picture {
vec4 color;
};
Picture fetch_picture(int address) {
vec4 data = fetch_from_resource_cache_1(address);
return Picture(data);
}
void brush_vs(
int prim_address,
vec2 local_pos,
@ -32,29 +42,35 @@ void brush_vs(
ivec2 user_data,
PictureTask pic_task
) {
// TODO(gw): For now, this brush_image shader is only
// being used to draw items from the intermediate
// surface cache (render tasks). In the future
// we can expand this to support items from
// the normal texture cache and unify this
// with the normal image shader.
BlurTask blur_task = fetch_blur_task(user_data.x);
vUv.z = blur_task.common_data.texture_layer_index;
vImageKind = user_data.y;
#if defined WR_FEATURE_COLOR_TARGET
// TODO(gw): There's quite a bit of code duplication here,
// depending on which variation of brush image
// this is being used for. This is because only
// box-shadow pictures are currently supported
// as texture cacheable items. Once we port the
// drop-shadows and text-shadows to be cacheable,
// most of this code can be merged together.
#if defined WR_FEATURE_COLOR_TARGET || defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
BlurTask blur_task = fetch_blur_task(user_data.x);
vUv.z = blur_task.common_data.texture_layer_index;
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);
#if defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
vColor = blur_task.color;
#endif
vec2 uv0 = blur_task.common_data.task_rect.p0;
vec2 src_size = blur_task.common_data.task_rect.size * blur_task.scale_factor;
vec2 uv1 = uv0 + blur_task.common_data.task_rect.size;
#else
Picture pic = fetch_picture(prim_address);
ImageResource uv_rect = fetch_image_resource(user_data.x);
vec2 texture_size = vec2(textureSize(sColor1, 0).xy);
vColor = pic.color;
vec2 uv0 = uv_rect.uv_rect.xy;
vec2 uv1 = uv_rect.uv_rect.zw;
vec2 src_size = (uv1 - uv0) * uv_rect.user_data.x;
vUv.z = uv_rect.layer;
#endif
// TODO(gw): In the future we'll probably draw these as segments
// with the brush shader. When that occurs, we can

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

@ -20,7 +20,6 @@ flat varying int vBlurRadius;
in int aBlurRenderTaskAddress;
in int aBlurSourceTaskAddress;
in int aBlurDirection;
in vec4 aBlurRegion;
void main(void) {
BlurTask blur_task = fetch_blur_task(aBlurRenderTaskAddress);
@ -51,13 +50,6 @@ void main(void) {
src_rect.p0 + src_rect.size - vec2(0.5));
vUvRect /= texture_size.xyxy;
if (aBlurRegion.z > 0.0) {
vec4 blur_region = aBlurRegion * uDevicePixelRatio;
src_rect = RectWithSize(src_rect.p0 + blur_region.xy, blur_region.zw);
target_rect.p0 = target_rect.p0 + blur_region.xy;
target_rect.size = blur_region.zw;
}
vec2 pos = target_rect.p0 + target_rect.size * aPosition.xy;
vec2 uv0 = src_rect.p0 / texture_size;

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

@ -694,17 +694,18 @@ GlyphResource fetch_glyph_resource(int address) {
struct ImageResource {
vec4 uv_rect;
float layer;
vec3 user_data;
};
ImageResource fetch_image_resource(int address) {
//Note: number of blocks has to match `renderer::BLOCKS_PER_UV_RECT`
vec4 data[2] = fetch_from_resource_cache_2(address);
return ImageResource(data[0], data[1].x);
return ImageResource(data[0], data[1].x, data[1].yzw);
}
ImageResource fetch_image_resource_direct(ivec2 address) {
vec4 data[2] = fetch_from_resource_cache_2_direct(address);
return ImageResource(data[0], data[1].x);
return ImageResource(data[0], data[1].x, data[1].yzw);
}
struct TextRun {

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

@ -47,7 +47,7 @@ vec4 get_effective_border_widths(Border border, int style) {
// for now - we can adjust this if we find other browsers pick
// different values in some cases.
// SEE: https://drafts.csswg.org/css-backgrounds-3/#double
return floor(0.5 + border.widths / 3.0);
return max(floor(0.5 + border.widths / 3.0), 1.0);
case BORDER_STYLE_GROOVE:
case BORDER_STYLE_RIDGE:
return floor(0.5 + border.widths * 0.5);

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

@ -2,11 +2,11 @@
* 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::{DeviceIntRect, DeviceIntSize, ImageKey, LayerToWorldScale};
use api::{AlphaType, DeviceIntRect, DeviceIntSize, ImageKey, LayerToWorldScale};
use api::{ExternalImageType, FilterOp, ImageRendering, LayerRect};
use api::{SubpixelDirection, TileOffset, YuvColorSpace, YuvFormat};
use api::{LayerToWorldTransform, WorldPixel};
use border::{BorderCornerInstance, BorderCornerSide};
use border::{BorderCornerInstance, BorderCornerSide, BorderEdgeKind};
use clip::{ClipSource, ClipStore};
use clip_scroll_tree::{CoordinateSystemId};
use euclid::{TypedTransform3D, vec3};
@ -16,10 +16,10 @@ use gpu_types::{BrushImageKind, BrushInstance, ClipChainRectIndex};
use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, PictureType};
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
use internal_types::{FastHashMap, SourceTexture};
use picture::{PictureCompositeMode, PictureKind, PicturePrimitive};
use picture::{PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, PrimitiveRun};
use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PrimitiveRun};
use render_task::{ClipWorkItem};
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind};
use render_task::{RenderTaskTree};
@ -109,7 +109,7 @@ impl BatchTextures {
pub fn color(texture: SourceTexture) -> Self {
BatchTextures {
colors: [texture, SourceTexture::Invalid, SourceTexture::Invalid],
colors: [texture, texture, SourceTexture::Invalid],
}
}
}
@ -344,6 +344,7 @@ impl BatchList {
self.opaque_batch_list
.get_suitable_batch(key, item_bounding_rect)
}
BlendMode::Alpha |
BlendMode::PremultipliedAlpha |
BlendMode::PremultipliedDestOut |
BlendMode::SubpixelConstantTextColor(..) |
@ -365,7 +366,6 @@ impl BatchList {
pub struct AlphaBatcher {
pub batch_list: BatchList,
pub text_run_cache_prims: FastHashMap<SourceTexture, Vec<PrimitiveInstance>>,
pub line_cache_prims: Vec<PrimitiveInstance>,
glyph_fetch_buffer: Vec<GlyphFetchResult>,
}
@ -375,7 +375,6 @@ impl AlphaBatcher {
batch_list: BatchList::new(screen_size),
glyph_fetch_buffer: Vec::new(),
text_run_cache_prims: FastHashMap::default(),
line_cache_prims: Vec::new(),
}
}
@ -468,7 +467,12 @@ impl AlphaBatcher {
let pic_metadata = &ctx.prim_store.cpu_metadata[prim_index.0];
let pic = &ctx.prim_store.cpu_pictures[pic_metadata.cpu_prim_index.0];
let batch = self.batch_list.get_suitable_batch(key, pic_metadata.screen_rect.as_ref().expect("bug"));
let source_task_address = render_tasks.get_task_address(pic.render_task_id.expect("bug"));
let render_task_id = match pic.surface {
Some(PictureSurface::RenderTask(render_task_id)) => render_task_id,
Some(PictureSurface::TextureCache(..)) | None => panic!("BUG: unexpected surface in splitting"),
};
let source_task_address = render_tasks.get_task_address(render_task_id);
let gpu_address = gpu_handle.as_int(gpu_cache);
let instance = CompositePrimitiveInstance::new(
@ -646,37 +650,13 @@ impl AlphaBatcher {
}
let batch = self.batch_list.get_suitable_batch(edge_key, item_bounding_rect);
for border_segment in 0 .. 4 {
batch.push(base_instance.build(border_segment, 0, 0));
for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() {
match *instance_kind {
BorderEdgeKind::None => {},
_ => {
batch.push(base_instance.build(border_segment as i32, 0, 0));
}
}
PrimitiveKind::Line => {
let base_instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
user_data0: 0,
user_data1: 0,
};
let instance = PrimitiveInstance::from(base_instance);
match pic_type {
PictureType::TextShadow => {
self.line_cache_prims.push(instance);
}
PictureType::Image => {
let kind =
BatchKind::Brush(BrushBatchKind::Line);
let key = BatchKey::new(kind, blend_mode, no_textures);
let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect);
batch.push(instance);
}
PictureType::BoxShadow => unreachable!(),
}
}
PrimitiveKind::Image => {
@ -806,7 +786,7 @@ impl AlphaBatcher {
} else if ctx.use_dual_source_blending {
BlendMode::SubpixelDualSource
} else {
BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into())
BlendMode::SubpixelConstantTextColor(text_cpu.get_color())
}
}
GlyphFormat::Alpha |
@ -833,8 +813,39 @@ impl AlphaBatcher {
let picture =
&ctx.prim_store.cpu_pictures[prim_metadata.cpu_prim_index.0];
match picture.render_task_id {
Some(cache_task_id) => {
match picture.surface {
Some(PictureSurface::TextureCache(ref cache_item)) => {
match picture.kind {
PictureKind::TextShadow { .. } |
PictureKind::Image { .. } => {
panic!("BUG: only supported as render tasks for now");
}
PictureKind::BoxShadow { image_kind, .. } => {
let textures = BatchTextures::color(cache_item.texture_id);
let kind = BatchKind::Brush(
BrushBatchKind::Image(
BrushImageSourceKind::from_render_target_kind(picture.target_kind())),
);
let key = BatchKey::new(kind, blend_mode, textures);
let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
user_data0: cache_item.uv_rect_handle.as_int(gpu_cache),
user_data1: image_kind as i32,
};
batch.push(PrimitiveInstance::from(instance));
}
}
}
Some(PictureSurface::RenderTask(cache_task_id)) => {
let cache_task_address = render_tasks.get_task_address(cache_task_id);
let textures = BatchTextures::render_target_cache();
@ -855,31 +866,14 @@ impl AlphaBatcher {
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
user_data0: cache_task_address.0 as i32,
user_data1: BrushImageKind::Simple as i32,
};
batch.push(PrimitiveInstance::from(instance));
}
PictureKind::BoxShadow { image_kind, .. } => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(
BrushImageSourceKind::from_render_target_kind(picture.target_kind())),
);
let key = BatchKey::new(kind, blend_mode, textures);
let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
user_data0: cache_task_address.0 as i32,
user_data1: image_kind as i32,
};
batch.push(PrimitiveInstance::from(instance));
PictureKind::BoxShadow { .. } => {
panic!("BUG: should be handled as a texture cache surface");
}
PictureKind::Image {
composite_mode,
@ -914,7 +908,7 @@ impl AlphaBatcher {
// This will allow us to unify some of the shaders, apply clip masks
// when compositing pictures, and also correctly apply pixel snapping
// to picture compositing operations.
let source_id = picture.render_task_id.expect("no source!?");
let source_id = cache_task_id;
match composite_mode.expect("bug: only composites here") {
PictureCompositeMode::Filter(filter) => {
@ -954,6 +948,7 @@ impl AlphaBatcher {
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
user_data0: cache_task_address.0 as i32,
user_data1: BrushImageKind::Simple as i32,
};
@ -1244,6 +1239,7 @@ impl AlphaBatcher {
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
user_data0: 0,
user_data1: 0,
};
@ -1275,6 +1271,7 @@ impl AlphaBatcher {
let instance = PrimitiveInstance::from(BrushInstance {
segment_index: i as i32,
edge_flags: segment.edge_flags,
clip_task_address,
..base_instance
});
@ -1297,6 +1294,13 @@ impl AlphaBatcher {
impl BrushPrimitive {
fn get_batch_key(&self, blend_mode: BlendMode) -> BatchKey {
match self.kind {
BrushKind::Line { .. } => {
BatchKey::new(
BatchKind::Brush(BrushBatchKind::Line),
blend_mode,
BatchTextures::no_texture(),
)
}
BrushKind::Solid { .. } => {
BatchKey::new(
BatchKind::Brush(BrushBatchKind::Solid),
@ -1339,18 +1343,25 @@ impl AlphaBatchHelpers for PrimitiveStore {
// Can only resolve the TextRun's blend mode once glyphs are fetched.
PrimitiveKind::TextRun => BlendMode::PremultipliedAlpha,
PrimitiveKind::Border |
PrimitiveKind::Image |
PrimitiveKind::YuvImage |
PrimitiveKind::AlignedGradient |
PrimitiveKind::AngleGradient |
PrimitiveKind::RadialGradient |
PrimitiveKind::Line |
PrimitiveKind::Brush |
PrimitiveKind::Picture => if needs_blending {
BlendMode::PremultipliedAlpha
} else {
BlendMode::None
},
PrimitiveKind::Image => if needs_blending {
let image_cpu = &self.cpu_images[metadata.cpu_prim_index.0];
match image_cpu.alpha_type {
AlphaType::PremultipliedAlpha => BlendMode::PremultipliedAlpha,
AlphaType::Alpha => BlendMode::Alpha,
}
} else {
BlendMode::None
},
}
}
}

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

@ -149,6 +149,14 @@ impl NormalBorderHelpers for NormalBorder {
BorderCornerKind::None
}
// If one of the edges is none or hidden, we just draw one style.
(BorderStyle::None, _) |
(_, BorderStyle::None) |
(BorderStyle::Hidden, _) |
(_, BorderStyle::Hidden) => {
BorderCornerKind::Clip(BorderCornerInstance::Single)
}
// If both borders are solid, we can draw them with a simple rectangle if
// both the colors match and there is no radius.
(BorderStyle::Solid, BorderStyle::Solid) => {
@ -237,12 +245,12 @@ pub fn ensure_no_corner_overlap(
let bottom_right_radius = &mut radius.bottom_right;
let bottom_left_radius = &mut radius.bottom_left;
let sum = top_left_radius.width + bottom_left_radius.width;
let sum = top_left_radius.width + top_right_radius.width;
if rect.size.width < sum {
ratio = f32::min(ratio, rect.size.width / sum);
}
let sum = top_right_radius.width + bottom_right_radius.width;
let sum = bottom_left_radius.width + bottom_right_radius.width;
if rect.size.width < sum {
ratio = f32::min(ratio, rect.size.width / sum);
}
@ -280,6 +288,7 @@ impl FrameBuilder {
widths: &BorderWidths,
clip_and_scroll: ClipAndScrollInfo,
corner_instances: [BorderCornerInstance; 4],
edges: [BorderEdgeKind; 4],
clip_sources: Vec<ClipSource>,
) {
let radius = &border.radius;
@ -296,6 +305,7 @@ impl FrameBuilder {
let prim_cpu = BorderPrimitiveCpu {
corner_instances,
edges,
// TODO(gw): In the future, we will build these on demand
// from the deserialized display list, rather
@ -536,6 +546,7 @@ impl FrameBuilder {
widths,
clip_and_scroll,
corner_instances,
edges,
extra_clips,
);
}

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

@ -83,6 +83,9 @@ impl FrameBuilder {
.inflate(spread_amount, spread_amount);
if blur_radius == 0.0 {
if box_offset.x == 0.0 && box_offset.y == 0.0 && spread_amount == 0.0 {
return;
}
let mut clips = Vec::new();
let fast_info = match clip_mode {
@ -242,7 +245,6 @@ impl FrameBuilder {
let mut pic_prim = PicturePrimitive::new_box_shadow(
blur_radius,
*color,
Vec::new(),
clip_mode,
image_kind,
cache_key,
@ -301,7 +303,7 @@ impl FrameBuilder {
inflate_size *= 2.0;
}
let brush_rect = brush_rect.inflate(inflate_size, inflate_size);
let brush_rect = brush_rect.inflate(inflate_size + box_offset.x.abs(), inflate_size + box_offset.y.abs());
let brush_prim = BrushPrimitive::new(
BrushKind::Mask {
clip_mode: brush_clip_mode,
@ -321,7 +323,6 @@ impl FrameBuilder {
let mut pic_prim = PicturePrimitive::new_box_shadow(
blur_radius,
*color,
Vec::new(),
BoxShadowClipMode::Inset,
// TODO(gw): Make use of optimization for inset.
BrushImageKind::NinePatch,
@ -337,7 +338,7 @@ impl FrameBuilder {
// rect to account for the inflate above. This
// extra edge will be clipped by the local clip
// rect set below.
let pic_rect = prim_info.rect.inflate(inflate_size, inflate_size);
let pic_rect = prim_info.rect.inflate(inflate_size + box_offset.x.abs(), inflate_size + box_offset.y.abs());
let pic_info = LayerPrimitiveInfo::with_clip_rect(
pic_rect,
prim_info.rect

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

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ClipId, DeviceIntRect, DevicePixelScale, LayerPixel, LayerPoint, LayerRect, LayerSize};
use api::{ClipId, DevicePixelScale, LayerPixel, LayerPoint, LayerRect, LayerSize};
use api::{LayerToWorldTransform, LayerTransform, LayerVector2D, LayoutTransform, LayoutVector2D};
use api::{PipelineId, PropertyBinding, ScrollClamping, ScrollEventPhase, ScrollLocation};
use api::{ScrollSensitivity, StickyOffsetBounds, WorldPoint};
@ -12,11 +12,10 @@ use euclid::SideOffsets2D;
use geometry::ray_intersects_rect;
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use render_task::{ClipChain, ClipChainNode, ClipWorkItem};
use render_task::{ClipChain, ClipWorkItem};
use resource_cache::ResourceCache;
use scene::SceneProperties;
use spring::{DAMPING, STIFFNESS, Spring};
use std::rc::Rc;
use util::{MatrixHelpers, TransformOrOffset, TransformedRectKind};
#[cfg(target_os = "macos")]
@ -107,10 +106,8 @@ pub struct ClipScrollNode {
/// The type of this node and any data associated with that node type.
pub node_type: NodeType,
/// The node in the chain of clips that are necessary to clip display items
/// that have this ClipScrollNode as their clip parent. This will be used to
/// generate clip tasks.
pub clip_chain_node: ClipChain,
/// The ClipChain that will be used if this node is used as the 'clipping node.'
pub clip_chain: Option<ClipChain>,
/// True if this node is transformed by an invertible transform. If not, display items
/// transformed by this node will not be displayed and display items not transformed by this
@ -145,7 +142,7 @@ impl ClipScrollNode {
children: Vec::new(),
pipeline_id,
node_type: node_type,
clip_chain_node: None,
clip_chain: None,
invertible: true,
coordinate_system_id: CoordinateSystemId(0),
coordinate_system_relative_transform: TransformOrOffset::zero(),
@ -272,7 +269,7 @@ impl ClipScrollNode {
self.invertible = false;
self.world_content_transform = LayerToWorldTransform::identity();
self.world_viewport_transform = LayerToWorldTransform::identity();
self.clip_chain_node = None;
self.clip_chain = None;
}
pub fn push_gpu_node_data(&mut self, node_data: &mut Vec<ClipScrollNodeData>) {
@ -300,7 +297,6 @@ impl ClipScrollNode {
&mut self,
state: &mut TransformUpdateState,
next_coordinate_system_id: &mut CoordinateSystemId,
screen_rect: &DeviceIntRect,
device_pixel_scale: DevicePixelScale,
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
@ -329,7 +325,6 @@ impl ClipScrollNode {
self.update_clip_work_item(
state,
screen_rect,
device_pixel_scale,
clip_store,
resource_cache,
@ -340,21 +335,15 @@ impl ClipScrollNode {
pub fn update_clip_work_item(
&mut self,
state: &mut TransformUpdateState,
screen_rect: &DeviceIntRect,
device_pixel_scale: DevicePixelScale,
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
) {
let current_clip_chain = state.parent_clip_chain.clone();
let combined_outer_screen_rect = current_clip_chain.as_ref().map_or(
*screen_rect, |clip| clip.combined_outer_screen_rect,
);
let clip_sources_handle = match self.node_type {
NodeType::Clip(ref handle) => handle,
_ => {
self.clip_chain_node = current_clip_chain.clone();
self.clip_chain = Some(state.parent_clip_chain.clone());
self.invertible = true;
return;
}
@ -376,8 +365,8 @@ impl ClipScrollNode {
// If this clip's inner rectangle completely surrounds the existing clip
// chain's outer rectangle, we can discard this clip entirely since it isn't
// going to affect anything.
if screen_inner_rect.contains_rect(&combined_outer_screen_rect) {
self.clip_chain_node = current_clip_chain;
if screen_inner_rect.contains_rect(&state.parent_clip_chain.combined_outer_screen_rect) {
self.clip_chain = Some(state.parent_clip_chain.clone());
return;
}
@ -387,16 +376,15 @@ impl ClipScrollNode {
coordinate_system_id: state.current_coordinate_system_id,
};
let clip_chain_node = ClipChainNode::new(
let clip_chain = state.parent_clip_chain.new_with_added_node(
work_item,
self.coordinate_system_relative_transform.apply(&local_outer_rect),
screen_outer_rect,
screen_inner_rect,
current_clip_chain
);
self.clip_chain_node = Some(Rc::new(clip_chain_node));
state.parent_clip_chain = self.clip_chain_node.clone();
self.clip_chain = Some(clip_chain.clone());
state.parent_clip_chain = clip_chain;
}
pub fn update_transform(
@ -613,7 +601,6 @@ impl ClipScrollNode {
pub fn prepare_state_for_children(&self, state: &mut TransformUpdateState) {
if !self.invertible {
state.invertible = false;
state.parent_clip_chain = None;
return;
}
@ -778,16 +765,6 @@ impl ClipScrollNode {
_ => false,
}
}
pub fn is_visible(&self) -> bool {
if !self.invertible {
return false;
}
match self.clip_chain_node {
Some(ref node) if node.combined_outer_screen_rect.is_empty() => false,
_ => true,
}
}
}
#[derive(Copy, Clone, Debug)]

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

@ -2,9 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ClipId, DeviceIntRect, DevicePixelScale, LayerPoint, LayerRect};
use api::{LayerToWorldTransform, LayerVector2D, PipelineId, ScrollClamping, ScrollEventPhase};
use api::{PropertyBinding, LayoutTransform, ScrollLayerState, ScrollLocation, WorldPoint};
use api::{ClipId, ClipChainId, DeviceIntRect, DevicePixelScale, LayerPoint, LayerRect};
use api::{LayerToWorldTransform, LayerVector2D, LayoutTransform, PipelineId, PropertyBinding};
use api::{ScrollClamping, ScrollEventPhase, ScrollLayerState, ScrollLocation, WorldPoint};
use clip::ClipStore;
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollingState, StickyFrameInfo};
use gpu_cache::GpuCache;
@ -40,8 +40,23 @@ impl CoordinateSystemId {
}
}
struct ClipChainDescriptor {
id: ClipChainId,
parent: Option<ClipChainId>,
clips: Vec<ClipId>,
}
pub struct ClipScrollTree {
pub nodes: FastHashMap<ClipId, ClipScrollNode>,
/// A Vec of all descriptors that describe ClipChains in the order in which they are
/// encountered during display list flattening. ClipChains are expected to never be
/// the children of ClipChains later in the list.
clip_chains_descriptors: Vec<ClipChainDescriptor>,
/// A HashMap of built ClipChains that are described by `clip_chains_descriptors`.
pub clip_chains: FastHashMap<ClipChainId, ClipChain>,
pub pending_scroll_offsets: FastHashMap<ClipId, (LayerPoint, ScrollClamping)>,
/// The ClipId of the currently scrolling node. Used to allow the same
@ -94,6 +109,8 @@ impl ClipScrollTree {
let dummy_pipeline = PipelineId::dummy();
ClipScrollTree {
nodes: FastHashMap::default(),
clip_chains_descriptors: Vec::new(),
clip_chains: FastHashMap::default(),
pending_scroll_offsets: FastHashMap::default(),
currently_scrolling_node_id: None,
root_reference_frame_id: ClipId::root_reference_frame(dummy_pipeline),
@ -243,6 +260,8 @@ impl ClipScrollTree {
}
self.pipelines_to_discard.clear();
self.clip_chains.clear();
self.clip_chains_descriptors.clear();
scroll_states
}
@ -359,7 +378,7 @@ impl ClipScrollTree {
parent_accumulated_scroll_offset: LayerVector2D::zero(),
nearest_scrolling_ancestor_offset: LayerVector2D::zero(),
nearest_scrolling_ancestor_viewport: LayerRect::zero(),
parent_clip_chain: None,
parent_clip_chain: ClipChain::empty(screen_rect),
current_coordinate_system_id: CoordinateSystemId::root(),
coordinate_system_relative_transform: TransformOrOffset::zero(),
invertible: true,
@ -369,7 +388,6 @@ impl ClipScrollTree {
root_reference_frame_id,
&mut state,
&mut next_coordinate_system_id,
screen_rect,
device_pixel_scale,
clip_store,
resource_cache,
@ -377,6 +395,8 @@ impl ClipScrollTree {
node_data,
scene_properties,
);
self.build_clip_chains(screen_rect);
}
fn update_node(
@ -384,7 +404,6 @@ impl ClipScrollTree {
layer_id: ClipId,
state: &mut TransformUpdateState,
next_coordinate_system_id: &mut CoordinateSystemId,
screen_rect: &DeviceIntRect,
device_pixel_scale: DevicePixelScale,
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
@ -407,7 +426,6 @@ impl ClipScrollTree {
node.update(
&mut state,
next_coordinate_system_id,
screen_rect,
device_pixel_scale,
clip_store,
resource_cache,
@ -421,7 +439,6 @@ impl ClipScrollTree {
return;
}
node.prepare_state_for_children(&mut state);
node.children.clone()
};
@ -431,7 +448,6 @@ impl ClipScrollTree {
child_node_id,
&mut state,
next_coordinate_system_id,
screen_rect,
device_pixel_scale,
clip_store,
resource_cache,
@ -442,6 +458,25 @@ impl ClipScrollTree {
}
}
pub fn build_clip_chains(&mut self, screen_rect: &DeviceIntRect) {
for descriptor in &self.clip_chains_descriptors {
let mut chain = match descriptor.parent {
Some(id) => self.clip_chains[&id].clone(),
None => ClipChain::empty(screen_rect),
};
for clip_id in &descriptor.clips {
if let Some(ref node_chain) = self.nodes[&clip_id].clip_chain {
if let Some(ref nodes) = node_chain.nodes {
chain.add_node((**nodes).clone());
}
}
}
self.clip_chains.insert(descriptor.id, chain);
}
}
pub fn tick_scrolling_bounce_animations(&mut self) {
for (_, node) in &mut self.nodes {
node.tick_scrolling_bounce_animation()
@ -512,6 +547,15 @@ impl ClipScrollTree {
self.add_node(node, id);
}
pub fn add_clip_chain_descriptor(
&mut self,
id: ClipChainId,
parent: Option<ClipChainId>,
clips: Vec<ClipId>
) {
self.clip_chains_descriptors.push(ClipChainDescriptor { id, parent, clips });
}
pub fn add_node(&mut self, node: ClipScrollNode, id: ClipId) {
// When the parent node is None this means we are adding the root.
match node.parent {
@ -612,4 +656,12 @@ impl ClipScrollTree {
.unwrap_or_else(|| WorldPoint::new(point.x, point.y))
}
pub fn get_clip_chain(&self, id: &ClipId) -> Option<&ClipChain> {
match id {
&ClipId::ClipChain(clip_chain_id) => Some(&self.clip_chains[&clip_chain_id]),
_ => self.nodes[id].clip_chain.as_ref(),
}
}
}

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

@ -121,7 +121,7 @@ impl DebugRenderer {
&mut font_texture,
debug_font_data::BMP_WIDTH,
debug_font_data::BMP_HEIGHT,
ImageFormat::A8,
ImageFormat::R8,
TextureFilter::Linear,
None,
1,

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

@ -12,7 +12,6 @@ use smallvec::SmallVec;
use std::cell::RefCell;
use std::fs::File;
use std::io::Read;
use std::iter::repeat;
use std::marker::PhantomData;
use std::mem;
use std::ops::Add;
@ -21,6 +20,11 @@ use std::ptr;
use std::rc::Rc;
use std::thread;
// Apparently, in some cases calling `glTexImage3D` with
// similar parameters that the texture already has confuses
// Angle when running with optimizations.
const WORK_AROUND_TEX_IMAGE: bool = cfg!(windows);
#[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)]
pub struct FrameId(usize);
@ -38,12 +42,6 @@ impl Add<usize> for FrameId {
}
}
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
const GL_FORMAT_A: gl::GLuint = gl::RED;
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
const GL_FORMAT_A: gl::GLuint = gl::ALPHA;
const GL_FORMAT_BGRA_GL: gl::GLuint = gl::BGRA;
const GL_FORMAT_BGRA_GLES: gl::GLuint = gl::BGRA_EXT;
@ -457,7 +455,7 @@ impl Texture {
pub fn get_bpp(&self) -> u32 {
match self.format {
ImageFormat::A8 => 1,
ImageFormat::R8 => 1,
ImageFormat::BGRA8 => 4,
ImageFormat::RG8 => 2,
ImageFormat::RGBAF32 => 16,
@ -468,6 +466,10 @@ impl Texture {
pub fn has_depth(&self) -> bool {
self.depth_rb.is_some()
}
pub fn get_rt_info(&self) -> Option<&RenderTargetInfo> {
self.render_target.as_ref()
}
}
impl Drop for Texture {
@ -962,7 +964,7 @@ impl Device {
self.bind_texture(DEFAULT_TEXTURE, texture);
self.set_texture_parameters(texture.target, texture.filter);
self.update_texture_storage(texture, &rt_info, true);
self.update_texture_storage(texture, &rt_info, true, false);
let rect = DeviceIntRect::new(DeviceIntPoint::zero(), old_size.to_i32());
for (read_fbo, &draw_fbo) in old_fbos.into_iter().zip(&texture.fbo_ids) {
@ -984,13 +986,13 @@ impl Device {
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 ||
texture.format != format;
let is_resized = texture.width != width || texture.height != height;
let is_format_changed = texture.format != format;
texture.format = format;
texture.width = width;
@ -1005,26 +1007,12 @@ impl Device {
match render_target {
Some(info) => {
assert!(pixels.is_none());
self.update_texture_storage(texture, &info, resized);
self.update_texture_storage(texture, &info, is_resized, is_format_changed);
}
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))
.collect();
Some(expanded_data.as_slice())
} else {
pixels
};
match texture.target {
gl::TEXTURE_2D_ARRAY => {
self.gl.tex_image_3d(
@ -1037,7 +1025,7 @@ impl Device {
0,
gl_format,
type_,
actual_pixels,
pixels,
);
}
gl::TEXTURE_2D | gl::TEXTURE_RECTANGLE | gl::TEXTURE_EXTERNAL_OES => {
@ -1050,7 +1038,7 @@ impl Device {
0,
gl_format,
type_,
actual_pixels,
pixels,
);
}
_ => panic!("BUG: Unexpected texture target!"),
@ -1065,11 +1053,12 @@ impl Device {
texture: &mut Texture,
rt_info: &RenderTargetInfo,
is_resized: bool,
is_format_changed: bool,
) {
assert!(texture.layer_count > 0);
let needed_layer_count = texture.layer_count - texture.fbo_ids.len() as i32;
let allocate_color = needed_layer_count != 0 || is_resized;
let allocate_color = needed_layer_count != 0 || is_resized || is_format_changed;
if allocate_color {
let (internal_format, gl_format) =
@ -1078,6 +1067,19 @@ impl Device {
match texture.target {
gl::TEXTURE_2D_ARRAY => {
if WORK_AROUND_TEX_IMAGE {
// reset the contents before resizing
self.gl.tex_image_3d(
texture.target,
0,
gl::RGBA32F as _,
2, 2, 1,
0,
gl::RGBA,
gl::FLOAT,
None,
)
}
self.gl.tex_image_3d(
texture.target,
0,
@ -1138,8 +1140,8 @@ impl Device {
self.gl.renderbuffer_storage(
gl::RENDERBUFFER,
gl::DEPTH_COMPONENT24,
texture.width as gl::GLsizei,
texture.height as gl::GLsizei,
texture.width as _,
texture.height as _,
);
} else {
self.gl.delete_renderbuffers(&[depth_rb]);
@ -1149,6 +1151,7 @@ impl Device {
}
if allocate_color || allocate_depth {
let original_bound_fbo = self.bound_draw_fbo;
for (fbo_index, &fbo_id) in texture.fbo_ids.iter().enumerate() {
self.bind_external_draw_target(fbo_id);
match texture.target {
@ -1158,7 +1161,7 @@ impl Device {
gl::COLOR_ATTACHMENT0,
texture.id,
0,
fbo_index as gl::GLint,
fbo_index as _,
)
}
_ => {
@ -1180,9 +1183,7 @@ impl Device {
depth_rb,
);
}
// restore the previous FBO
let bound_fbo = self.bound_draw_fbo;
self.bind_external_draw_target(bound_fbo);
self.bind_external_draw_target(original_bound_fbo);
}
}
@ -1859,6 +1860,12 @@ impl Device {
}
}
pub fn set_blend_mode_alpha(&self) {
self.gl.blend_func_separate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA,
gl::ONE, gl::ONE);
self.gl.blend_equation(gl::FUNC_ADD);
}
pub fn set_blend_mode_premultiplied_alpha(&self) {
self.gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
self.gl.blend_equation(gl::FUNC_ADD);
@ -1924,11 +1931,7 @@ fn gl_texture_formats_for_image_format(
format: ImageFormat,
) -> (gl::GLint, gl::GLuint) {
match format {
ImageFormat::A8 => if cfg!(any(target_arch = "arm", target_arch = "aarch64")) {
(get_gl_format_bgra(gl) as gl::GLint, get_gl_format_bgra(gl))
} else {
(GL_FORMAT_A as gl::GLint, GL_FORMAT_A)
},
ImageFormat::R8 => (gl::RED as gl::GLint, gl::RED),
ImageFormat::BGRA8 => match gl.get_type() {
gl::GlType::Gl => (gl::RGBA as gl::GLint, get_gl_format_bgra(gl)),
gl::GlType::Gles => (get_gl_format_bgra(gl) as gl::GLint, get_gl_format_bgra(gl)),
@ -2053,7 +2056,7 @@ impl<'a, T> TextureUploader<'a, T> {
impl<'a> UploadTarget<'a> {
fn update_impl(&mut self, chunk: UploadChunk) {
let (gl_format, bpp, data_type) = match self.texture.format {
ImageFormat::A8 => (GL_FORMAT_A, 1, gl::UNSIGNED_BYTE),
ImageFormat::R8 => (gl::RED, 1, gl::UNSIGNED_BYTE),
ImageFormat::BGRA8 => (get_gl_format_bgra(self.gl), 4, gl::UNSIGNED_BYTE),
ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE),
ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT),

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

@ -74,6 +74,24 @@ impl<'a> FlattenContext<'a> {
.collect()
}
fn get_clip_chain_items(
&self,
pipeline_id: PipelineId,
items: ItemRange<ClipId>,
) -> Vec<ClipId> {
if items.is_empty() {
return vec![];
}
self.scene
.pipelines
.get(&pipeline_id)
.expect("No display list?")
.display_list
.get(items)
.collect()
}
fn flatten_root(
&mut self,
traversal: &mut BuiltDisplayListIter<'a>,
@ -405,6 +423,7 @@ impl<'a> FlattenContext<'a> {
None,
info.image_key,
info.image_rendering,
info.alpha_type,
None,
);
}
@ -558,6 +577,10 @@ impl<'a> FlattenContext<'a> {
clip_region,
);
}
SpecificDisplayItem::ClipChain(ref info) => {
let items = self.get_clip_chain_items(pipeline_id, item.clip_chain_items());
self.clip_scroll_tree.add_clip_chain_descriptor(info.id, info.parent, items);
},
SpecificDisplayItem::ScrollFrame(ref info) => {
let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0);
let clip_region = ClipRegion::create_for_clip_node(
@ -915,6 +938,7 @@ impl<'a> FlattenContext<'a> {
None,
info.image_key,
info.image_rendering,
info.alpha_type,
Some(tile_offset),
);
}

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

@ -2,8 +2,8 @@
* 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::{BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipAndScrollInfo, ClipId, ColorF};
use api::{ColorU, DeviceIntPoint, DevicePixelScale, DeviceUintPoint, DeviceUintRect};
use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipAndScrollInfo, ClipId};
use api::{ColorF, ColorU, DeviceIntPoint, DevicePixelScale, DeviceUintPoint, DeviceUintRect};
use api::{DeviceUintSize, DocumentLayer, ExtendMode, FontRenderMode, GlyphInstance, GlyphOptions};
use api::{GradientStop, HitTestFlags, HitTestItem, HitTestResult, ImageKey, ImageRendering};
use api::{ItemRange, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize};
@ -22,19 +22,18 @@ use glyph_rasterizer::FontInstance;
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeData, PictureType};
use internal_types::{FastHashMap, FastHashSet, RenderPassIndex};
use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive};
use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface};
use prim_store::{BrushKind, BrushPrimitive, TexelRect, YuvImagePrimitiveCpu};
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, LinePrimitive, PrimitiveKind};
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, PrimitiveKind};
use prim_store::{PrimitiveContainer, PrimitiveIndex, SpecificPrimitiveIndex};
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu};
use prim_store::{BrushSegmentDescriptor, TextRunPrimitiveCpu};
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use render_task::{ClearMode, RenderTask, RenderTaskId, RenderTaskTree};
use render_task::{ClearMode, ClipChain, RenderTask, RenderTaskId, RenderTaskTree};
use resource_cache::ResourceCache;
use scene::{ScenePipeline, SceneProperties};
use std::{mem, usize, f32};
use tiling::{CompositeOps, Frame};
use tiling::{RenderPass, RenderTargetKind};
use tiling::{CompositeOps, Frame, RenderPass, RenderTargetKind};
use tiling::{RenderTargetContext, ScrollbarPrimitive};
use util::{self, MaxRect, pack_as_float, RectHelpers, recycle_vec};
@ -129,7 +128,7 @@ pub struct FrameBuilder {
pub struct PrimitiveContext<'a> {
pub device_pixel_scale: DevicePixelScale,
pub display_list: &'a BuiltDisplayList,
pub clip_node: &'a ClipScrollNode,
pub clip_chain: Option<&'a ClipChain>,
pub scroll_node: &'a ClipScrollNode,
}
@ -137,13 +136,13 @@ impl<'a> PrimitiveContext<'a> {
pub fn new(
device_pixel_scale: DevicePixelScale,
display_list: &'a BuiltDisplayList,
clip_node: &'a ClipScrollNode,
clip_chain: Option<&'a ClipChain>,
scroll_node: &'a ClipScrollNode,
) -> Self {
PrimitiveContext {
device_pixel_scale,
display_list,
clip_node,
clip_chain,
scroll_node,
}
}
@ -819,12 +818,15 @@ impl FrameBuilder {
line_color: &ColorF,
style: LineStyle,
) {
let line = LinePrimitive {
let line = BrushPrimitive::new(
BrushKind::Line {
wavy_line_thickness,
color: line_color.premultiplied(),
style,
orientation,
};
},
None,
);
let mut fast_shadow_prims = Vec::new();
for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() {
@ -839,14 +841,21 @@ impl FrameBuilder {
}
for (idx, shadow_offset, shadow_color) in fast_shadow_prims {
let mut line = line.clone();
line.color = shadow_color.premultiplied();
let line = BrushPrimitive::new(
BrushKind::Line {
wavy_line_thickness,
color: shadow_color.premultiplied(),
style,
orientation,
},
None,
);
let mut info = info.clone();
info.rect = info.rect.translate(&shadow_offset);
let prim_index = self.create_primitive(
&info,
Vec::new(),
PrimitiveContainer::Line(line),
PrimitiveContainer::Brush(line),
);
self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll));
}
@ -854,7 +863,7 @@ impl FrameBuilder {
let prim_index = self.create_primitive(
&info,
Vec::new(),
PrimitiveContainer::Line(line),
PrimitiveContainer::Brush(line),
);
if line_color.a > 0.0 {
@ -1088,6 +1097,7 @@ impl FrameBuilder {
Some(segment.sub_rect),
border.image_key,
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
None,
);
}
@ -1283,8 +1293,10 @@ impl FrameBuilder {
let mut render_mode = self.config
.default_font_render_mode
.limit_by(font.render_mode);
let mut flags = font.flags;
if let Some(options) = glyph_options {
render_mode = render_mode.limit_by(options.render_mode);
flags |= options.flags;
}
// There are some conditions under which we can't use
@ -1309,7 +1321,7 @@ impl FrameBuilder {
font.bg_color,
render_mode,
font.subpx_dir,
font.flags,
flags,
font.platform_options,
font.variations.clone(),
);
@ -1411,6 +1423,7 @@ impl FrameBuilder {
sub_rect: Option<TexelRect>,
image_key: ImageKey,
image_rendering: ImageRendering,
alpha_type: AlphaType,
tile: Option<TileOffset>,
) {
let sub_rect_block = sub_rect.unwrap_or(TexelRect::invalid()).into();
@ -1430,6 +1443,7 @@ impl FrameBuilder {
image_rendering,
tile_offset: tile,
tile_spacing,
alpha_type,
gpu_blocks: [
[
stretch_size.width,
@ -1582,7 +1596,7 @@ impl FrameBuilder {
let root_prim_context = PrimitiveContext::new(
device_pixel_scale,
display_list,
root_clip_scroll_node,
root_clip_scroll_node.clip_chain.as_ref(),
root_clip_scroll_node,
);
@ -1620,12 +1634,12 @@ impl FrameBuilder {
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
child_tasks,
None,
PictureType::Image,
);
pic.render_task_id = Some(render_tasks.add(root_render_task));
pic.render_task_id
let render_task_id = render_tasks.add(root_render_task);
pic.surface = Some(PictureSurface::RenderTask(render_task_id));
Some(render_task_id)
}
fn update_scroll_bars(&mut self, clip_scroll_tree: &ClipScrollTree, gpu_cache: &mut GpuCache) {

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

@ -114,6 +114,18 @@ impl FontTransform {
self.scale_y - self.skew_y * skew_factor,
)
}
pub fn swap_xy(&self) -> Self {
FontTransform::new(self.skew_x, self.scale_x, self.scale_y, self.skew_y)
}
pub fn flip_x(&self) -> Self {
FontTransform::new(-self.scale_x, self.skew_x, -self.skew_y, self.scale_y)
}
pub fn flip_y(&self) -> Self {
FontTransform::new(self.scale_x, -self.skew_y, self.skew_y, -self.scale_y)
}
}
impl<'a> From<&'a LayerToWorldTransform> for FontTransform {
@ -220,8 +232,6 @@ pub enum GlyphFormat {
impl GlyphFormat {
pub fn ignore_color(self) -> Self {
match self {
GlyphFormat::Subpixel => GlyphFormat::Alpha,
GlyphFormat::TransformedSubpixel => GlyphFormat::TransformedAlpha,
GlyphFormat::ColorBitmap => GlyphFormat::Bitmap,
_ => self,
}
@ -400,7 +410,7 @@ impl GlyphRasterizer {
offset: 0,
},
TextureFilter::Linear,
ImageData::Raw(glyph_info.glyph_bytes.clone()),
Some(ImageData::Raw(glyph_info.glyph_bytes.clone())),
[glyph_info.offset.x, glyph_info.offset.y, glyph_info.scale],
None,
gpu_cache,
@ -523,7 +533,7 @@ impl GlyphRasterizer {
offset: 0,
},
TextureFilter::Linear,
ImageData::Raw(glyph_bytes.clone()),
Some(ImageData::Raw(glyph_bytes.clone())),
[glyph.left, -glyph.top, glyph.scale],
None,
gpu_cache,

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

@ -2,8 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{LayerRect, LayerToWorldTransform};
use api::{LayerToWorldTransform};
use gpu_cache::GpuCacheAddress;
use prim_store::EdgeAaSegmentMask;
use render_task::RenderTaskAddress;
// Contains type that must exactly match the same structures declared in GLSL.
@ -21,7 +22,6 @@ pub struct BlurInstance {
pub task_address: RenderTaskAddress,
pub src_task_address: RenderTaskAddress,
pub blur_direction: BlurDirection,
pub region: LayerRect,
}
/// A clipping primitive drawn into the clipping mask.
@ -155,6 +155,7 @@ pub struct BrushInstance {
pub clip_task_address: RenderTaskAddress,
pub z: i32,
pub segment_index: i32,
pub edge_flags: EdgeAaSegmentMask,
pub user_data0: i32,
pub user_data1: i32,
}
@ -168,7 +169,7 @@ impl From<BrushInstance> for PrimitiveInstance {
((instance.clip_chain_rect_index.0 as i32) << 16) | instance.scroll_id.0 as i32,
instance.clip_task_address.0 as i32,
instance.z,
instance.segment_index,
instance.segment_index | ((instance.edge_flags.bits() as i32) << 16),
instance.user_data0,
instance.user_data1,
]

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

@ -8,10 +8,12 @@ use api::{BoxShadowClipMode, LayerPoint, LayerRect, LayerVector2D, Shadow};
use api::{ClipId, PremultipliedColorF};
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowCacheKey};
use frame_builder::PrimitiveContext;
use gpu_cache::GpuDataRequest;
use gpu_cache::{GpuCache, GpuDataRequest};
use gpu_types::{BrushImageKind, PictureType};
use prim_store::{PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
use render_task::{ClearMode, RenderTask, RenderTaskId, RenderTaskTree};
use render_task::{ClearMode, RenderTask, RenderTaskCacheKey};
use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskTree};
use resource_cache::{CacheItem, ResourceCache};
use scene::{FilterOpHelpers, SceneProperties};
use tiling::RenderTargetKind;
@ -57,7 +59,6 @@ pub enum PictureKind {
BoxShadow {
blur_radius: f32,
color: ColorF,
blur_regions: Vec<LayerRect>,
clip_mode: BoxShadowClipMode,
image_kind: BrushImageKind,
content_rect: LayerRect,
@ -88,11 +89,21 @@ pub enum PictureKind {
},
}
// The type of surface that a picture can be drawn to.
// RenderTask surfaces are not retained across frames.
// TextureCache surfaces are stored across frames, and
// also shared between display lists.
#[derive(Debug)]
pub enum PictureSurface {
RenderTask(RenderTaskId),
TextureCache(CacheItem),
}
#[derive(Debug)]
pub struct PicturePrimitive {
// If this picture is drawn to an intermediate surface,
// the associated render task.
pub render_task_id: Option<RenderTaskId>,
// the associated target information.
pub surface: Option<PictureSurface>,
// Details specific to this type of picture.
pub kind: PictureKind,
@ -113,7 +124,7 @@ impl PicturePrimitive {
pub fn new_text_shadow(shadow: Shadow, pipeline_id: PipelineId) -> Self {
PicturePrimitive {
runs: Vec::new(),
render_task_id: None,
surface: None,
kind: PictureKind::TextShadow {
offset: shadow.offset,
color: shadow.color,
@ -149,7 +160,6 @@ impl PicturePrimitive {
pub fn new_box_shadow(
blur_radius: f32,
color: ColorF,
blur_regions: Vec<LayerRect>,
clip_mode: BoxShadowClipMode,
image_kind: BrushImageKind,
cache_key: BoxShadowCacheKey,
@ -157,11 +167,10 @@ impl PicturePrimitive {
) -> Self {
PicturePrimitive {
runs: Vec::new(),
render_task_id: None,
surface: None,
kind: PictureKind::BoxShadow {
blur_radius,
color,
blur_regions,
clip_mode,
image_kind,
content_rect: LayerRect::zero(),
@ -181,7 +190,7 @@ impl PicturePrimitive {
) -> Self {
PicturePrimitive {
runs: Vec::new(),
render_task_id: None,
surface: None,
kind: PictureKind::Image {
secondary_render_task_id: None,
composite_mode,
@ -303,6 +312,8 @@ impl PicturePrimitive {
prim_local_rect: &LayerRect,
child_tasks: Vec<RenderTaskId>,
parent_tasks: &mut Vec<RenderTaskId>,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
) {
let content_scale = LayerToWorldScale::new(1.0) * prim_context.device_pixel_scale;
@ -323,26 +334,24 @@ impl PicturePrimitive {
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
child_tasks,
None,
PictureType::Image,
);
let blur_std_deviation = blur_radius * prim_context.device_pixel_scale.0;
let picture_task_id = render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
let (blur_render_task, _) = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
render_tasks,
RenderTargetKind::Color,
&[],
ClearMode::Transparent,
PremultipliedColorF::TRANSPARENT,
None,
);
let blur_render_task_id = render_tasks.add(blur_render_task);
self.render_task_id = Some(blur_render_task_id);
let render_task_id = render_tasks.add(blur_render_task);
parent_tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
let rect = (prim_local_rect.translate(&-offset) * content_scale).round().to_i32();
@ -354,26 +363,26 @@ impl PicturePrimitive {
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
child_tasks,
None,
PictureType::Image,
);
let blur_std_deviation = blur_radius * prim_context.device_pixel_scale.0;
let picture_task_id = render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
let (blur_render_task, _) = RenderTask::new_blur(
blur_std_deviation.round(),
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));
let render_task_id = render_tasks.add(blur_render_task);
parent_tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::MixBlend(..)) => {
let picture_task = RenderTask::new_picture(
@ -384,7 +393,6 @@ impl PicturePrimitive {
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
child_tasks,
None,
PictureType::Image,
);
@ -393,7 +401,9 @@ impl PicturePrimitive {
*secondary_render_task_id = Some(readback_task_id);
parent_tasks.push(readback_task_id);
self.render_task_id = Some(render_tasks.add(picture_task));
let render_task_id = render_tasks.add(picture_task);
parent_tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::Filter(filter)) => {
// If this filter is not currently going to affect
@ -403,7 +413,7 @@ impl PicturePrimitive {
// filters and be a significant performance win.
if filter.is_noop() {
parent_tasks.extend(child_tasks);
self.render_task_id = None;
self.surface = None;
} else {
let picture_task = RenderTask::new_picture(
Some(prim_screen_rect.size),
@ -413,11 +423,12 @@ impl PicturePrimitive {
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
child_tasks,
None,
PictureType::Image,
);
self.render_task_id = Some(render_tasks.add(picture_task));
let render_task_id = render_tasks.add(picture_task);
parent_tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
}
Some(PictureCompositeMode::Blit) => {
@ -429,15 +440,16 @@ impl PicturePrimitive {
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
child_tasks,
None,
PictureType::Image,
);
self.render_task_id = Some(render_tasks.add(picture_task));
let render_task_id = render_tasks.add(picture_task);
parent_tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
None => {
parent_tasks.extend(child_tasks);
self.render_task_id = None;
self.surface = None;
}
}
}
@ -468,26 +480,25 @@ impl PicturePrimitive {
color.premultiplied(),
ClearMode::Transparent,
Vec::new(),
None,
PictureType::TextShadow,
);
let picture_task_id = render_tasks.add(picture_task);
let render_task = RenderTask::new_blur(
let (blur_render_task, _) = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
render_tasks,
RenderTargetKind::Color,
&[],
ClearMode::Transparent,
color.premultiplied(),
None,
);
self.render_task_id = Some(render_tasks.add(render_task));
let render_task_id = render_tasks.add(blur_render_task);
parent_tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
PictureKind::BoxShadow { blur_radius, clip_mode, ref blur_regions, color, content_rect, cache_key, .. } => {
PictureKind::BoxShadow { blur_radius, clip_mode, color, content_rect, cache_key, .. } => {
// TODO(gw): Rounding the content rect here to device pixels is not
// technically correct. Ideally we should ceil() here, and ensure that
// the extra part pixel in the case of fractional sizes is correctly
@ -495,6 +506,17 @@ impl PicturePrimitive {
// Gecko tests.
let cache_size = (content_rect.size * content_scale).round().to_i32();
// Request the texture cache item for this box-shadow key. If it
// doesn't exist in the cache, the closure is invoked to build
// a render task chain to draw the cacheable result.
let cache_item = resource_cache.request_render_task(
RenderTaskCacheKey {
size: cache_size,
kind: RenderTaskCacheKeyKind::BoxShadow(cache_key),
},
gpu_cache,
render_tasks,
|render_tasks| {
// Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur
// "the image that would be generated by applying to the shadow a
// Gaussian blur with a standard deviation equal to half the blur radius."
@ -518,36 +540,48 @@ impl PicturePrimitive {
color.premultiplied(),
ClearMode::Zero,
Vec::new(),
Some(cache_key),
PictureType::BoxShadow,
);
let picture_task_id = render_tasks.add(picture_task);
let render_task = RenderTask::new_blur(
let (blur_render_task, scale_factor) = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
render_tasks,
RenderTargetKind::Alpha,
blur_regions,
blur_clear_mode,
color.premultiplied(),
Some(cache_key),
);
self.render_task_id = Some(render_tasks.add(render_task));
let root_task_id = render_tasks.add(blur_render_task);
parent_tasks.push(root_task_id);
// TODO(gw): Remove the nastiness with having to pass
// the scale factor through the texture cache
// item user data. This will disappear once
// the brush_image shader is updated to draw
// segments, since the scale factor will not
// be used at all then during drawing.
(root_task_id, [scale_factor, 0.0, 0.0])
}
);
self.surface = Some(PictureSurface::TextureCache(cache_item));
}
}
}
if let Some(render_task_id) = self.render_task_id {
parent_tasks.push(render_task_id);
pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
match self.kind {
PictureKind::TextShadow { .. } |
PictureKind::Image { .. } => {
request.push([0.0; 4]);
}
PictureKind::BoxShadow { color, .. } => {
request.push(color.premultiplied());
}
}
pub fn write_gpu_blocks(&self, _request: &mut GpuDataRequest) {
// TODO(gw): We'll need to write the GPU blocks
// here specific to a brush primitive
// once we start drawing pictures as brushes!
}
pub fn target_kind(&self) -> RenderTargetKind {

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

@ -117,7 +117,6 @@ fn get_glyph_metrics(
if let Some(transform) = transform {
bounds = bounds.apply_transform(transform);
advance = advance.apply_transform(transform);
}
// First round out to pixel boundaries
@ -361,8 +360,23 @@ impl FontContext {
let glyph = key.index as CGGlyph;
let bitmap = is_bitmap_font(ct_font);
let (x_offset, y_offset) = if bitmap { (0.0, 0.0) } else { font.get_subpx_offset(key) };
let transform = if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
let shape = FontTransform::identity().synthesize_italics(OBLIQUE_SKEW_FACTOR);
let transform = if font.flags.intersects(FontInstanceFlags::SYNTHETIC_ITALICS |
FontInstanceFlags::TRANSPOSE |
FontInstanceFlags::FLIP_X |
FontInstanceFlags::FLIP_Y) {
let mut shape = FontTransform::identity();
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
}
Some(CGAffineTransform {
a: shape.scale_x as f64,
b: -shape.skew_y as f64,
@ -483,6 +497,15 @@ impl FontContext {
} else {
(font.transform.invert_scale(y_scale, y_scale), font.get_subpx_offset(key))
};
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
}

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

@ -105,6 +105,38 @@ fn skew_bitmap(bitmap: &[u8], width: usize, height: usize, left: i32, top: i32)
(skew_buffer, skew_width, left + skew_min as i32)
}
fn transpose_bitmap(bitmap: &[u8], width: usize, height: usize) -> Vec<u8> {
let mut transposed = vec![0u8; width * height * 4];
for (y, row) in bitmap.chunks(width * 4).enumerate() {
let mut offset = y * 4;
for src in row.chunks(4) {
transposed[offset .. offset + 4].copy_from_slice(src);
offset += height * 4;
}
}
transposed
}
fn flip_bitmap_x(bitmap: &mut [u8], width: usize, height: usize) {
assert!(bitmap.len() == width * height * 4);
let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
for row in pixels.chunks_mut(width) {
row.reverse();
}
}
fn flip_bitmap_y(bitmap: &mut [u8], width: usize, height: usize) {
assert!(bitmap.len() == width * height * 4);
let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
for y in 0 .. height / 2 {
let low_row = y * width;
let high_row = (height - 1 - y) * width;
for x in 0 .. width {
pixels.swap(low_row + x, high_row + x);
}
}
}
impl FontContext {
pub fn new() -> FontContext {
let mut lib: FT_Library = ptr::null_mut();
@ -250,6 +282,15 @@ impl FontContext {
self.choose_bitmap_size(face.face, req_size * y_scale)
} else {
let mut shape = font.transform.invert_scale(x_scale, y_scale);
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
};
@ -391,6 +432,18 @@ impl FontContext {
left += skew_min as i32;
width += (skew_max - skew_min) as u32;
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
mem::swap(&mut width, &mut height);
mem::swap(&mut left, &mut top);
left -= width as i32;
top += height as i32;
}
if font.flags.contains(FontInstanceFlags::FLIP_X) {
left = -(left + width as i32);
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
top = -(top - height as i32);
}
}
Some(GlyphDimensions {
left,
@ -570,7 +623,7 @@ impl FontContext {
let bitmap = unsafe { &(*slot).bitmap };
let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
let (mut actual_width, actual_height) = match pixel_mode {
let (mut actual_width, mut actual_height) = match pixel_mode {
FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
assert!(bitmap.width % 3 == 0);
((bitmap.width / 3) as usize, bitmap.rows as usize)
@ -677,6 +730,21 @@ impl FontContext {
actual_width = skew_width;
left = skew_left;
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
final_buffer = transpose_bitmap(&final_buffer, actual_width, actual_height);
mem::swap(&mut actual_width, &mut actual_height);
mem::swap(&mut left, &mut top);
left -= actual_width as i32;
top += actual_height as i32;
}
if font.flags.contains(FontInstanceFlags::FLIP_X) {
flip_bitmap_x(&mut final_buffer, actual_width, actual_height);
left = -(left + actual_width as i32);
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
flip_bitmap_y(&mut final_buffer, actual_width, actual_height);
top = -(top - actual_height as i32);
}
}
FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
unsafe {

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

@ -236,8 +236,23 @@ impl FontContext {
) -> Option<GlyphDimensions> {
let size = font.size.to_f32_px();
let bitmaps = is_bitmap_font(font);
let transform = if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
let shape = FontTransform::identity().synthesize_italics(OBLIQUE_SKEW_FACTOR);
let transform = if font.flags.intersects(FontInstanceFlags::SYNTHETIC_ITALICS |
FontInstanceFlags::TRANSPOSE |
FontInstanceFlags::FLIP_X |
FontInstanceFlags::FLIP_Y) {
let mut shape = FontTransform::identity();
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
}
Some(dwrote::DWRITE_MATRIX {
m11: shape.scale_x,
m12: shape.skew_y,
@ -359,6 +374,15 @@ impl FontContext {
} else {
(font.transform.invert_scale(y_scale, y_scale), font.get_subpx_offset(key))
};
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
}

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

@ -2,14 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{BorderRadius, BuiltDisplayList, ClipAndScrollInfo, ClipId, ClipMode, ColorF, ColorU};
use api::{DeviceIntRect, DevicePixelScale, DevicePoint};
use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipAndScrollInfo, ClipId, ClipMode};
use api::{ColorF, ColorU, DeviceIntRect, DevicePixelScale, DevicePoint};
use api::{ComplexClipRegion, ExtendMode, FontRenderMode};
use api::{GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag};
use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D, LineOrientation};
use api::{LineStyle, PipelineId, PremultipliedColorF, TileOffset, WorldToLayerTransform};
use api::{YuvColorSpace, YuvFormat};
use border::BorderCornerInstance;
use border::{BorderCornerInstance, BorderEdgeKind};
use clip_scroll_tree::{CoordinateSystemId, ClipScrollTree};
use clip_scroll_node::ClipScrollNode;
use clip::{ClipSource, ClipSourcesHandle, ClipStore};
@ -21,8 +21,8 @@ use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuData
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData};
use picture::{PictureKind, PicturePrimitive};
use profiler::FrameProfileCounters;
use render_task::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipWorkItem, RenderTask};
use render_task::{RenderTaskId, RenderTaskTree};
use render_task::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipWorkItem};
use render_task::{RenderTask, RenderTaskId, RenderTaskTree};
use renderer::{BLOCKS_PER_UV_RECT, MAX_VERTEX_TEXTURE_WIDTH};
use resource_cache::{ImageProperties, ResourceCache};
use scene::{ScenePipeline, SceneProperties};
@ -151,7 +151,6 @@ pub enum PrimitiveKind {
AlignedGradient,
AngleGradient,
RadialGradient,
Line,
Picture,
Brush,
}
@ -212,6 +211,12 @@ pub enum BrushKind {
color: ColorF,
},
Clear,
Line {
color: PremultipliedColorF,
wavy_line_thickness: f32,
style: LineStyle,
orientation: LineOrientation,
}
}
impl BrushKind {
@ -331,30 +336,18 @@ impl BrushPrimitive {
radii.bottom_left.height,
]);
}
}
}
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct LinePrimitive {
pub color: PremultipliedColorF,
pub wavy_line_thickness: f32,
pub style: LineStyle,
pub orientation: LineOrientation,
}
impl LinePrimitive {
fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
request.push(self.color);
BrushKind::Line { color, wavy_line_thickness, style, orientation } => {
request.push(color);
request.push([
self.wavy_line_thickness,
pack_as_float(self.style as u32),
pack_as_float(self.orientation as u32),
wavy_line_thickness,
pack_as_float(style as u32),
pack_as_float(orientation as u32),
0.0,
]);
}
}
}
}
#[derive(Debug)]
pub struct ImagePrimitiveCpu {
@ -362,6 +355,7 @@ pub struct ImagePrimitiveCpu {
pub image_rendering: ImageRendering,
pub tile_offset: Option<TileOffset>,
pub tile_spacing: LayerSize,
pub alpha_type: AlphaType,
// TODO(gw): Build on demand
pub gpu_blocks: [GpuBlockData; BLOCKS_PER_UV_RECT],
}
@ -393,6 +387,7 @@ impl ToGpuBlocks for YuvImagePrimitiveCpu {
#[derive(Debug)]
pub struct BorderPrimitiveCpu {
pub corner_instances: [BorderCornerInstance; 4],
pub edges: [BorderEdgeKind; 4],
pub gpu_blocks: [GpuBlockData; 8],
}
@ -679,6 +674,14 @@ impl TextRunPrimitiveCpu {
self.shadow_color.a != 0
}
pub fn get_color(&self) -> ColorF {
ColorF::from(if self.is_shadow() {
self.shadow_color
} else {
self.font.color
})
}
fn prepare_for_render(
&mut self,
resource_cache: &mut ResourceCache,
@ -728,14 +731,9 @@ impl TextRunPrimitiveCpu {
}
fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
let bg_color = ColorF::from(self.font.bg_color);
let color = ColorF::from(if self.is_shadow() {
self.shadow_color
} else {
self.font.color
});
request.push(color.premultiplied());
request.push(self.get_color().premultiplied());
// this is the only case where we need to provide plain color to GPU
let bg_color = ColorF::from(self.font.bg_color);
request.extend_from_slice(&[
GpuBlockData { data: [bg_color.r, bg_color.g, bg_color.b, 1.0] }
]);
@ -944,7 +942,6 @@ pub enum PrimitiveContainer {
AngleGradient(GradientPrimitiveCpu),
RadialGradient(RadialGradientPrimitiveCpu),
Picture(PicturePrimitive),
Line(LinePrimitive),
Brush(BrushPrimitive),
}
@ -959,7 +956,6 @@ pub struct PrimitiveStore {
pub cpu_radial_gradients: Vec<RadialGradientPrimitiveCpu>,
pub cpu_metadata: Vec<PrimitiveMetadata>,
pub cpu_borders: Vec<BorderPrimitiveCpu>,
pub cpu_lines: Vec<LinePrimitive>,
}
impl PrimitiveStore {
@ -974,7 +970,6 @@ impl PrimitiveStore {
cpu_gradients: Vec::new(),
cpu_radial_gradients: Vec::new(),
cpu_borders: Vec::new(),
cpu_lines: Vec::new(),
}
}
@ -989,7 +984,6 @@ impl PrimitiveStore {
cpu_gradients: recycle_vec(self.cpu_gradients),
cpu_radial_gradients: recycle_vec(self.cpu_radial_gradients),
cpu_borders: recycle_vec(self.cpu_borders),
cpu_lines: recycle_vec(self.cpu_lines),
}
}
@ -1025,6 +1019,7 @@ impl PrimitiveStore {
BrushKind::Clear => PrimitiveOpacity::translucent(),
BrushKind::Solid { ref color } => PrimitiveOpacity::from_alpha(color.a),
BrushKind::Mask { .. } => PrimitiveOpacity::translucent(),
BrushKind::Line { .. } => PrimitiveOpacity::translucent(),
};
let metadata = PrimitiveMetadata {
@ -1038,17 +1033,6 @@ impl PrimitiveStore {
metadata
}
PrimitiveContainer::Line(line) => {
let metadata = PrimitiveMetadata {
opacity: PrimitiveOpacity::translucent(),
prim_kind: PrimitiveKind::Line,
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_lines.len()),
..base_metadata
};
self.cpu_lines.push(line);
metadata
}
PrimitiveContainer::TextRun(text_cpu) => {
let metadata = PrimitiveMetadata {
opacity: PrimitiveOpacity::translucent(),
@ -1167,7 +1151,7 @@ impl PrimitiveStore {
) {
let metadata = &mut self.cpu_metadata[prim_index.0];
match metadata.prim_kind {
PrimitiveKind::Border | PrimitiveKind::Line => {}
PrimitiveKind::Border => {}
PrimitiveKind::Picture => {
self.cpu_pictures[metadata.cpu_prim_index.0]
.prepare_for_render(
@ -1178,6 +1162,8 @@ impl PrimitiveStore {
&metadata.local_rect,
child_tasks,
parent_tasks,
resource_cache,
gpu_cache,
);
}
PrimitiveKind::TextRun => {
@ -1248,25 +1234,6 @@ impl PrimitiveStore {
request.push(metadata.local_clip_rect);
match metadata.prim_kind {
PrimitiveKind::Line => {
let line = &self.cpu_lines[metadata.cpu_prim_index.0];
line.write_gpu_blocks(&mut request);
// TODO(gw): This is a bit of a hack. The Line type
// is drawn by the brush_line shader, so the
// layout here needs to conform to the same
// BrushPrimitive layout. We should tidy this
// up in the future so it's enforced that these
// types use a shared function to write out the
// GPU blocks...
request.push(metadata.local_rect);
request.push([
EdgeAaSegmentMask::empty().bits() as f32,
0.0,
0.0,
0.0
]);
}
PrimitiveKind::Border => {
let border = &self.cpu_borders[metadata.cpu_prim_index.0];
border.write_gpu_blocks(request);
@ -1306,13 +1273,7 @@ impl PrimitiveStore {
// up in the future so it's enforced that these
// types use a shared function to write out the
// GPU blocks...
request.push(metadata.local_rect);
request.push([
EdgeAaSegmentMask::empty().bits() as f32,
0.0,
0.0,
0.0
]);
request.write_segment(metadata.local_rect);
}
PrimitiveKind::Brush => {
let brush = &self.cpu_brushes[metadata.cpu_prim_index.0];
@ -1321,23 +1282,11 @@ impl PrimitiveStore {
Some(ref segment_desc) => {
for segment in &segment_desc.segments {
// has to match VECS_PER_SEGMENT
request.push(segment.local_rect);
request.push([
segment.edge_flags.bits() as f32,
0.0,
0.0,
0.0
]);
request.write_segment(segment.local_rect);
}
}
None => {
request.push(metadata.local_rect);
request.push([
EdgeAaSegmentMask::empty().bits() as f32,
0.0,
0.0,
0.0
]);
request.write_segment(metadata.local_rect);
}
}
}
@ -1513,7 +1462,6 @@ impl PrimitiveStore {
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,
@ -1555,12 +1503,13 @@ impl PrimitiveStore {
}
};
let clip_chain = prim_context.clip_node.clip_chain_node.clone();
let mut combined_outer_rect = match clip_chain {
Some(ref node) => prim_screen_rect.intersection(&node.combined_outer_screen_rect),
let mut combined_outer_rect = match prim_context.clip_chain {
Some(ref chain) => prim_screen_rect.intersection(&chain.combined_outer_screen_rect),
None => Some(prim_screen_rect),
};
let clip_chain = prim_context.clip_chain.map_or(None, |x| x.nodes.clone());
let prim_coordinate_system_id = prim_context.scroll_node.coordinate_system_id;
let transform = &prim_context.scroll_node.world_content_transform;
let extra_clip = {
@ -1588,9 +1537,6 @@ impl PrimitiveStore {
local_clip_rect: LayerRect::zero(),
screen_inner_rect,
screen_outer_rect: screen_outer_rect.unwrap_or(prim_screen_rect),
combined_outer_screen_rect:
combined_outer_rect.unwrap_or_else(DeviceIntRect::zero),
combined_inner_screen_rect: DeviceIntRect::zero(),
prev: None,
}))
} else {
@ -1653,7 +1599,6 @@ impl PrimitiveStore {
}
let clip_task = RenderTask::new_mask(
None,
combined_outer_rect,
clips,
prim_coordinate_system_id,
@ -1788,7 +1733,7 @@ impl PrimitiveStore {
prim_context.device_pixel_scale,
);
let clip_bounds = match prim_context.clip_node.clip_chain_node {
let clip_bounds = match prim_context.clip_chain {
Some(ref node) => node.combined_outer_screen_rect,
None => *screen_rect,
};
@ -1871,13 +1816,24 @@ impl PrimitiveStore {
// a new primitive context for every run (if the hash
// lookups ever show up in a profile).
let scroll_node = &clip_scroll_tree.nodes[&run.clip_and_scroll.scroll_node_id];
let clip_node = &clip_scroll_tree.nodes[&run.clip_and_scroll.clip_node_id()];
let clip_chain = clip_scroll_tree.get_clip_chain(&run.clip_and_scroll.clip_node_id());
if perform_culling && !clip_node.is_visible() {
debug!("{:?} of clipped out {:?}", run.base_prim_index, pipeline_id);
if perform_culling {
if !scroll_node.invertible {
debug!("{:?} {:?}: position not invertible", run.base_prim_index, pipeline_id);
continue;
}
match clip_chain {
Some(ref chain) if chain.combined_outer_screen_rect.is_empty() => {
debug!("{:?} {:?}: clipped out", run.base_prim_index, pipeline_id);
continue;
}
_ => {},
}
}
let parent_relative_transform = parent_prim_context
.scroll_node
.world_content_transform
@ -1905,13 +1861,13 @@ impl PrimitiveStore {
let child_prim_context = PrimitiveContext::new(
parent_prim_context.device_pixel_scale,
display_list,
clip_node,
clip_chain,
scroll_node,
);
let clip_chain_rect = match perform_culling {
true => get_local_clip_rect_for_nodes(scroll_node, clip_node),
true => get_local_clip_rect_for_nodes(scroll_node, clip_chain),
false => None,
};
@ -1994,17 +1950,14 @@ impl InsideTest<ComplexClipRegion> for ComplexClipRegion {
}
fn convert_clip_chain_to_clip_vector(
clip_chain: ClipChain,
extra_clip: ClipChain,
clip_chain_nodes: ClipChainNodeRef,
extra_clip: ClipChainNodeRef,
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)
})
.chain(ClipChainNodeIter { current: clip_chain_nodes })
.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
@ -2025,9 +1978,14 @@ fn convert_clip_chain_to_clip_vector(
fn get_local_clip_rect_for_nodes(
scroll_node: &ClipScrollNode,
clip_node: &ClipScrollNode,
clip_chain: Option<&ClipChain>,
) -> Option<LayerRect> {
let local_rect = ClipChainNodeIter { current: clip_node.clip_chain_node.clone() }.fold(
let clip_chain_nodes = match clip_chain {
Some(ref clip_chain) => clip_chain.nodes.clone(),
None => return None,
};
let local_rect = ClipChainNodeIter { current: clip_chain_nodes }.fold(
None,
|combined_local_clip_rect: Option<LayerRect>, node| {
if node.work_item.coordinate_system_id != scroll_node.coordinate_system_id {
@ -2048,3 +2006,23 @@ fn get_local_clip_rect_for_nodes(
None => None,
}
}
impl<'a> GpuDataRequest<'a> {
// Write the GPU cache data for an individual segment.
// TODO(gw): The second block is currently unused. In
// the future, it will be used to store a
// UV rect, allowing segments to reference
// part of an image.
fn write_segment(
&mut self,
local_rect: LayerRect,
) {
self.push(local_rect);
self.push([
0.0,
0.0,
0.0,
0.0
]);
}
}

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

@ -944,6 +944,7 @@ impl Profiler {
&renderer_profile.color_targets,
&renderer_profile.alpha_targets,
&renderer_profile.draw_calls,
&renderer_profile.vertices,
&self.backend_time,
&self.compositor_time,
&self.gpu_time,

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

@ -801,6 +801,7 @@ impl ToDebugString for SpecificDisplayItem {
SpecificDisplayItem::PushStackingContext(..) => String::from("push_stacking_context"),
SpecificDisplayItem::Iframe(..) => String::from("iframe"),
SpecificDisplayItem::Clip(..) => String::from("clip"),
SpecificDisplayItem::ClipChain(..) => String::from("clip_chain"),
SpecificDisplayItem::ScrollFrame(..) => String::from("scroll_frame"),
SpecificDisplayItem::StickyFrame(..) => String::from("sticky_frame"),
SpecificDisplayItem::SetGradientStops => String::from("set_gradient_stops"),
@ -816,16 +817,17 @@ impl ToDebugString for SpecificDisplayItem {
impl RenderBackend {
// Note: the mutable `self` is only needed here for resolving blob images
fn save_capture(&mut self, root: &PathBuf) -> Vec<ExternalCaptureImage> {
use ron::ser::pretty;
use ron::ser::{to_string_pretty, PrettyConfig};
use std::fs;
use std::io::Write;
info!("capture: saving {}", root.to_string_lossy());
let ron_config = PrettyConfig::default();
let (resources, deferred) = self.resource_cache.save_capture(root);
for (&id, doc) in &self.documents {
info!("\tdocument {:?}", id);
let ron = pretty::to_string(&doc.scene).unwrap();
let ron = to_string_pretty(&doc.scene, ron_config.clone()).unwrap();
let file_name = format!("scene-{}-{}.ron", (id.0).0, id.1);
let ron_path = root.clone().join(file_name);
let mut file = fs::File::create(ron_path).unwrap();
@ -844,7 +846,7 @@ impl RenderBackend {
resources,
};
let ron = pretty::to_string(&serial).unwrap();
let ron = to_string_pretty(&serial, ron_config).unwrap();
let ron_path = root.clone().join("backend.ron");
let mut file = fs::File::create(ron_path).unwrap();
write!(file, "{}\n", ron).unwrap();

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

@ -2,19 +2,23 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ClipId, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{LayerRect, PremultipliedColorF};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{ImageDescriptor, ImageFormat, LayerRect, PremultipliedColorF};
use box_shadow::BoxShadowCacheKey;
use clip::{ClipSourcesWeakHandle};
use clip_scroll_tree::CoordinateSystemId;
use device::TextureFilter;
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, PictureType};
use internal_types::RenderPassIndex;
use internal_types::{FastHashMap, RenderPassIndex, SourceTexture};
use picture::ContentOrigin;
use prim_store::{PrimitiveIndex};
#[cfg(feature = "debugger")]
use print_tree::{PrintTreePrinter};
use resource_cache::CacheItem;
use std::{cmp, ops, usize, f32, i32};
use std::rc::Rc;
use texture_cache::{TextureCache, TextureCacheHandle};
use tiling::{RenderPass, RenderTargetIndex};
use tiling::{RenderTargetKind};
@ -35,72 +39,82 @@ pub struct RenderTaskTree {
pub task_data: Vec<RenderTaskData>,
}
pub type ClipChain = Option<Rc<ClipChainNode>>;
pub type ClipChainNodeRef = Option<Rc<ClipChainNode>>;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ClipChainNode {
pub work_item: ClipWorkItem,
pub local_clip_rect: LayerRect,
pub screen_outer_rect: DeviceIntRect,
pub screen_inner_rect: DeviceIntRect,
pub combined_outer_screen_rect: DeviceIntRect,
pub combined_inner_screen_rect: DeviceIntRect,
pub prev: ClipChain,
pub prev: ClipChainNodeRef,
}
impl ClipChainNode {
pub fn new(
#[derive(Debug, Clone)]
pub struct ClipChain {
pub combined_outer_screen_rect: DeviceIntRect,
pub combined_inner_screen_rect: DeviceIntRect,
pub nodes: ClipChainNodeRef,
}
impl ClipChain {
pub fn empty(screen_rect: &DeviceIntRect) -> ClipChain {
ClipChain {
combined_inner_screen_rect: *screen_rect,
combined_outer_screen_rect: *screen_rect,
nodes: None,
}
}
pub fn new_with_added_node(
&self,
work_item: ClipWorkItem,
local_clip_rect: LayerRect,
screen_outer_rect: DeviceIntRect,
screen_inner_rect: DeviceIntRect,
parent_chain: ClipChain,
) -> ClipChainNode {
let mut node = ClipChainNode {
) -> ClipChain {
let new_node = ClipChainNode {
work_item,
local_clip_rect,
screen_outer_rect,
screen_inner_rect,
combined_outer_screen_rect: screen_outer_rect,
combined_inner_screen_rect: screen_inner_rect,
prev: None,
};
node.set_parent(parent_chain);
node
let mut new_chain = self.clone();
new_chain.add_node(new_node);
new_chain
}
fn set_parent(&mut self, new_parent: ClipChain) {
self.prev = new_parent.clone();
let parent_node = match new_parent {
Some(ref parent_node) => parent_node,
None => return,
};
pub fn add_node(&mut self, mut new_node: ClipChainNode) {
new_node.prev = self.nodes.clone();
// If this clip's outer rectangle is completely enclosed by the clip
// chain's inner rectangle, then the only clip that matters from this point
// on is this clip. We can disconnect this clip from the parent clip chain.
if parent_node.combined_inner_screen_rect.contains_rect(&self.screen_outer_rect) {
self.prev = None;
if self.combined_inner_screen_rect.contains_rect(&new_node.screen_outer_rect) {
new_node.prev = None;
}
self.combined_outer_screen_rect =
parent_node.combined_outer_screen_rect.intersection(&self.screen_outer_rect)
self.combined_outer_screen_rect.intersection(&new_node.screen_outer_rect)
.unwrap_or_else(DeviceIntRect::zero);
self.combined_inner_screen_rect =
parent_node.combined_inner_screen_rect.intersection(&self.screen_inner_rect)
self.combined_inner_screen_rect.intersection(&new_node.screen_inner_rect)
.unwrap_or_else(DeviceIntRect::zero);
self.nodes = Some(Rc::new(new_node));
}
}
pub struct ClipChainNodeIter {
pub current: ClipChain,
pub current: ClipChainNodeRef,
}
impl Iterator for ClipChainNodeIter {
type Item = Rc<ClipChainNode>;
fn next(&mut self) -> ClipChain {
fn next(&mut self) -> ClipChainNodeRef {
let previous = self.current.clone();
self.current = match self.current {
Some(ref item) => item.prev.clone(),
@ -150,7 +164,8 @@ impl RenderTaskTree {
RenderTaskLocation::Fixed => {
debug_assert!(pass_index == passes.len() - 1);
}
RenderTaskLocation::Dynamic(..) => {
RenderTaskLocation::Dynamic(..) |
RenderTaskLocation::TextureCache(..) => {
debug_assert!(pass_index < passes.len() - 1);
}
}
@ -170,10 +185,7 @@ impl RenderTaskTree {
}
pub fn get_task_address(&self, id: RenderTaskId) -> RenderTaskAddress {
match self[id].kind {
RenderTaskKind::Alias(alias_id) => RenderTaskAddress(alias_id.0),
_ => RenderTaskAddress(id.0),
}
RenderTaskAddress(id.0)
}
pub fn build(&mut self) {
@ -196,19 +208,11 @@ impl ops::IndexMut<RenderTaskId> for RenderTaskTree {
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum RenderTaskKey {
/// Draw the alpha mask for a shared clip.
CacheMask(ClipId),
CacheScaling(BoxShadowCacheKey, DeviceIntSize),
CacheBlur(BoxShadowCacheKey, i32),
CachePicture(BoxShadowCacheKey),
}
#[derive(Debug)]
pub enum RenderTaskLocation {
Fixed,
Dynamic(Option<(DeviceIntPoint, RenderTargetIndex)>, DeviceIntSize),
TextureCache(SourceTexture, i32, DeviceIntRect),
}
#[derive(Debug, Clone)]
@ -238,7 +242,6 @@ pub struct PictureTask {
pub struct BlurTask {
pub blur_std_deviation: f32,
pub target_kind: RenderTargetKind,
pub regions: Vec<LayerRect>,
pub color: PremultipliedColorF,
pub scale_factor: f32,
}
@ -249,9 +252,6 @@ impl BlurTask {
pt.add_item(format!("std deviation: {}", self.blur_std_deviation));
pt.add_item(format!("target: {:?}", self.target_kind));
pt.add_item(format!("scale: {}", self.scale_factor));
for region in &self.regions {
pt.add_item(format!("region {:?}", region));
}
}
}
@ -267,7 +267,6 @@ pub enum RenderTaskKind {
VerticalBlur(BlurTask),
HorizontalBlur(BlurTask),
Readback(DeviceIntRect),
Alias(RenderTaskId),
Scaling(RenderTargetKind),
}
@ -283,7 +282,6 @@ pub enum ClearMode {
#[derive(Debug)]
pub struct RenderTask {
pub cache_key: Option<RenderTaskKey>,
pub location: RenderTaskLocation,
pub children: Vec<RenderTaskId>,
pub kind: RenderTaskKind,
@ -300,7 +298,6 @@ impl RenderTask {
color: PremultipliedColorF,
clear_mode: ClearMode,
children: Vec<RenderTaskId>,
box_shadow_cache_key: Option<BoxShadowCacheKey>,
pic_type: PictureType,
) -> Self {
let location = match size {
@ -309,10 +306,6 @@ impl RenderTask {
};
RenderTask {
cache_key: match box_shadow_cache_key {
Some(key) => Some(RenderTaskKey::CachePicture(key)),
None => None,
},
children,
location,
kind: RenderTaskKind::Picture(PictureTask {
@ -329,7 +322,6 @@ impl RenderTask {
pub fn new_readback(screen_rect: DeviceIntRect) -> Self {
RenderTask {
cache_key: None,
children: Vec::new(),
location: RenderTaskLocation::Dynamic(None, screen_rect.size),
kind: RenderTaskKind::Readback(screen_rect),
@ -339,13 +331,11 @@ impl RenderTask {
}
pub fn new_mask(
key: Option<ClipId>,
outer_rect: DeviceIntRect,
clips: Vec<ClipWorkItem>,
prim_coordinate_system_id: CoordinateSystemId,
) -> RenderTask {
RenderTask {
cache_key: key.map(RenderTaskKey::CacheMask),
children: Vec::new(),
location: RenderTaskLocation::Dynamic(None, outer_rect.size),
kind: RenderTaskKind::CacheMask(CacheMaskTask {
@ -381,11 +371,9 @@ impl RenderTask {
src_task_id: RenderTaskId,
render_tasks: &mut RenderTaskTree,
target_kind: RenderTargetKind,
regions: &[LayerRect],
clear_mode: ClearMode,
color: PremultipliedColorF,
box_shadow_cache_key: Option<BoxShadowCacheKey>,
) -> Self {
) -> (Self, f32) {
// Adjust large std deviation value.
let mut adjusted_blur_std_deviation = blur_std_deviation;
let blur_target_size = render_tasks[src_task_id].get_dynamic_size();
@ -404,23 +392,17 @@ impl RenderTask {
target_kind,
downscaling_src_task_id,
adjusted_blur_target_size,
box_shadow_cache_key,
);
downscaling_src_task_id = render_tasks.add(downscaling_task);
}
scale_factor = blur_target_size.width as f32 / adjusted_blur_target_size.width as f32;
let blur_task_v = RenderTask {
cache_key: match box_shadow_cache_key {
Some(key) => Some(RenderTaskKey::CacheBlur(key, 0)),
None => None,
},
children: vec![downscaling_src_task_id],
location: RenderTaskLocation::Dynamic(None, adjusted_blur_target_size),
kind: RenderTaskKind::VerticalBlur(BlurTask {
blur_std_deviation: adjusted_blur_std_deviation,
target_kind,
regions: regions.to_vec(),
color,
scale_factor,
}),
@ -431,16 +413,11 @@ impl RenderTask {
let blur_task_v_id = render_tasks.add(blur_task_v);
let blur_task_h = RenderTask {
cache_key: match box_shadow_cache_key {
Some(key) => Some(RenderTaskKey::CacheBlur(key, 1)),
None => None,
},
children: vec![blur_task_v_id],
location: RenderTaskLocation::Dynamic(None, adjusted_blur_target_size),
kind: RenderTaskKind::HorizontalBlur(BlurTask {
blur_std_deviation: adjusted_blur_std_deviation,
target_kind,
regions: regions.to_vec(),
color,
scale_factor,
}),
@ -448,20 +425,15 @@ impl RenderTask {
pass_index: None,
};
blur_task_h
(blur_task_h, scale_factor)
}
pub fn new_scaling(
target_kind: RenderTargetKind,
src_task_id: RenderTaskId,
target_size: DeviceIntSize,
box_shadow_cache_key: Option<BoxShadowCacheKey>,
) -> Self {
RenderTask {
cache_key: match box_shadow_cache_key {
Some(key) => Some(RenderTaskKey::CacheScaling(key, target_size)),
None => None,
},
children: vec![src_task_id],
location: RenderTaskLocation::Dynamic(None, target_size),
kind: RenderTaskKind::Scaling(target_kind),
@ -527,8 +499,7 @@ impl RenderTask {
)
}
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) |
RenderTaskKind::Alias(..) => {
RenderTaskKind::Scaling(..) => {
(
[0.0; 3],
[0.0; 4],
@ -560,6 +531,7 @@ impl RenderTask {
match self.location {
RenderTaskLocation::Fixed => DeviceIntSize::zero(),
RenderTaskLocation::Dynamic(_, size) => size,
RenderTaskLocation::TextureCache(_, _, rect) => rect.size,
}
}
@ -588,6 +560,9 @@ impl RenderTask {
RenderTaskLocation::Dynamic(None, _) => {
(DeviceIntRect::zero(), RenderTargetIndex(0))
}
RenderTaskLocation::TextureCache(_, layer, rect) => {
(rect, RenderTargetIndex(layer as usize))
}
}
}
@ -611,10 +586,6 @@ impl RenderTask {
RenderTaskKind::Picture(ref task_info) => {
task_info.target_kind
}
RenderTaskKind::Alias(..) => {
panic!("BUG: target_kind() called on invalidated task");
}
}
}
@ -633,10 +604,6 @@ impl RenderTask {
RenderTaskKind::Scaling(..) => false,
RenderTaskKind::CacheMask(..) => true,
RenderTaskKind::Alias(..) => {
panic!("BUG: is_shared() called on aliased task");
}
}
}
@ -667,10 +634,6 @@ impl RenderTask {
pt.new_level("Scaling".to_owned());
pt.add_item(format!("kind: {:?}", kind));
}
RenderTaskKind::Alias(ref alias_id) => {
pt.add_item(format!("Alias of {:?}", alias_id));
return false
}
}
pt.add_item(format!("clear to: {:?}", self.clear_mode));
@ -685,3 +648,131 @@ impl RenderTask {
true
}
}
#[derive(Debug, Hash, PartialEq, Eq)]
pub enum RenderTaskCacheKeyKind {
BoxShadow(BoxShadowCacheKey),
}
#[derive(Debug, Hash, PartialEq, Eq)]
pub struct RenderTaskCacheKey {
pub size: DeviceIntSize,
pub kind: RenderTaskCacheKeyKind,
}
struct RenderTaskCacheEntry {
handle: TextureCacheHandle,
}
// A cache of render tasks that are stored in the texture
// cache for usage across frames.
pub struct RenderTaskCache {
entries: FastHashMap<RenderTaskCacheKey, RenderTaskCacheEntry>,
}
impl RenderTaskCache {
pub fn new() -> RenderTaskCache {
RenderTaskCache {
entries: FastHashMap::default(),
}
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn begin_frame(
&mut self,
texture_cache: &mut TextureCache,
) {
// Drop any items from the cache that have been
// evicted from the texture cache.
//
// This isn't actually necessary for the texture
// cache to be able to evict old render tasks.
// It will evict render tasks as required, since
// the access time in the texture cache entry will
// be stale if this task hasn't been requested
// for a while.
//
// Nonetheless, we should remove stale entries
// from here so that this hash map doesn't
// grow indefinitely!
self.entries.retain(|_, value| {
texture_cache.is_allocated(&value.handle)
});
}
pub fn request_render_task<F>(
&mut self,
key: RenderTaskCacheKey,
texture_cache: &mut TextureCache,
gpu_cache: &mut GpuCache,
render_tasks: &mut RenderTaskTree,
mut f: F,
) -> CacheItem where F: FnMut(&mut RenderTaskTree) -> (RenderTaskId, [f32; 3]) {
// Get the texture cache handle for this cache key,
// or create one.
let cache_entry = self.entries
.entry(key)
.or_insert(RenderTaskCacheEntry {
handle: TextureCacheHandle::new(),
});
// Check if this texture cache handle is valie.
if texture_cache.request(&mut cache_entry.handle, gpu_cache) {
// Invoke user closure to get render task chain
// to draw this into the texture cache.
let (render_task_id, user_data) = f(render_tasks);
let render_task = &mut render_tasks[render_task_id];
// Find out what size to alloc in the texture cache.
let size = match render_task.location {
RenderTaskLocation::Fixed |
RenderTaskLocation::TextureCache(..) => {
panic!("BUG: dynamic task was expected");
}
RenderTaskLocation::Dynamic(_, size) => size,
};
// TODO(gw): Support color tasks in the texture cache,
// and perhaps consider if we can determine
// if some tasks are opaque as an optimization.
let descriptor = ImageDescriptor::new(
size.width as u32,
size.height as u32,
ImageFormat::R8,
false,
);
// Allocate space in the texture cache, but don't supply
// and CPU-side data to be uploaded.
texture_cache.update(
&mut cache_entry.handle,
descriptor,
TextureFilter::Linear,
None,
user_data,
None,
gpu_cache,
);
// Get the allocation details in the texture cache, and store
// this in the render task. The renderer will draw this
// task into the appropriate layer and rect of the texture
// cache on this frame.
let (texture_id, texture_layer, uv_rect) =
texture_cache.get_cache_location(&cache_entry.handle);
render_task.location = RenderTaskLocation::TextureCache(
texture_id,
texture_layer,
uv_rect.to_i32()
);
}
// Finally, return the texture cache handle that we know
// is now up to date.
texture_cache.get(&cache_entry.handle)
}
}

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

@ -66,7 +66,7 @@ use texture_cache::TextureCache;
use thread_profiler::{register_thread_with_profiler, write_profile};
use tiling::{AlphaRenderTarget, ColorRenderTarget};
use tiling::{RenderPass, RenderPassKind, RenderTargetList};
use tiling::{Frame, RenderTarget, ScalingInfo};
use tiling::{Frame, RenderTarget, ScalingInfo, TextureCacheRenderTarget};
use time::precise_time_ns;
use util::TransformedRectKind;
@ -103,10 +103,6 @@ const GPU_TAG_CACHE_TEXT_RUN: GpuProfileTag = GpuProfileTag {
label: "C_TextRun",
color: debug_colors::MISTYROSE,
};
const GPU_TAG_CACHE_LINE: GpuProfileTag = GpuProfileTag {
label: "C_Line",
color: debug_colors::BROWN,
};
const GPU_TAG_SETUP_TARGET: GpuProfileTag = GpuProfileTag {
label: "target init",
color: debug_colors::SLATEGREY,
@ -413,11 +409,6 @@ const DESC_BLUR: VertexDescriptor = VertexDescriptor {
count: 1,
kind: VertexAttributeKind::I32,
},
VertexAttribute {
name: "aBlurRegion",
count: 4,
kind: VertexAttributeKind::F32
},
],
};
@ -769,6 +760,7 @@ impl SourceTextureResolver {
#[allow(dead_code)] // SubpixelVariableTextColor is not used at the moment.
pub enum BlendMode {
None,
Alpha,
PremultipliedAlpha,
PremultipliedDestOut,
SubpixelDualSource,
@ -1299,6 +1291,7 @@ impl BrushShader {
BlendMode::None => {
self.opaque.bind(device, projection, mode, renderer_errors)
}
BlendMode::Alpha |
BlendMode::PremultipliedAlpha |
BlendMode::PremultipliedDestOut |
BlendMode::SubpixelDualSource |
@ -2099,7 +2092,7 @@ impl Renderer {
&mut texture,
8,
8,
ImageFormat::A8,
ImageFormat::R8,
TextureFilter::Nearest,
None,
1,
@ -2553,11 +2546,6 @@ impl Renderer {
batch.len(),
);
}
debug_target.add(
debug_server::BatchKind::Cache,
"Lines",
target.alpha_batcher.line_cache_prims.len(),
);
for batch in target
.alpha_batcher
@ -2585,6 +2573,19 @@ impl Renderer {
debug_target
}
#[cfg(feature = "debugger")]
fn debug_texture_cache_target(target: &TextureCacheRenderTarget) -> debug_server::Target {
let mut debug_target = debug_server::Target::new("Texture Cache");
debug_target.add(
debug_server::BatchKind::Cache,
"Horizontal Blur",
target.horizontal_blurs.len(),
);
debug_target
}
#[cfg(feature = "debugger")]
fn get_passes_for_debugger(&self) -> String {
let mut debug_passes = debug_server::PassList::new();
@ -2596,9 +2597,10 @@ impl Renderer {
RenderPassKind::MainFramebuffer(ref target) => {
debug_targets.push(Self::debug_color_target(target));
}
RenderPassKind::OffScreen { ref alpha, ref color } => {
RenderPassKind::OffScreen { ref alpha, ref color, ref texture_cache } => {
debug_targets.extend(alpha.targets.iter().map(Self::debug_alpha_target));
debug_targets.extend(color.targets.iter().map(Self::debug_color_target));
debug_targets.extend(texture_cache.iter().map(|(_, target)| Self::debug_texture_cache_target(target)))
}
}
@ -3444,27 +3446,6 @@ impl Renderer {
);
}
}
if !target.alpha_batcher.line_cache_prims.is_empty() {
// TODO(gw): Technically, we don't need blend for solid
// lines. We could check that here?
self.device.set_blend(true);
self.device.set_blend_mode_premultiplied_alpha();
let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_LINE);
self.brush_line.bind(
&mut self.device,
BlendMode::PremultipliedAlpha,
projection,
0,
&mut self.renderer_errors,
);
self.draw_instanced_batch(
&target.alpha_batcher.line_cache_prims,
VertexArrayKind::Primitive,
&BatchTextures::no_texture(),
stats,
);
}
//TODO: record the pixel count for cached primitives
@ -3512,6 +3493,7 @@ impl Renderer {
if self.debug_flags.contains(DebugFlags::ALPHA_PRIM_DBG) {
let color = match batch.key.blend_mode {
BlendMode::None => debug_colors::BLACK,
BlendMode::Alpha |
BlendMode::PremultipliedAlpha => debug_colors::GREY,
BlendMode::PremultipliedDestOut => debug_colors::SALMON,
BlendMode::SubpixelConstantTextColor(..) => debug_colors::GREEN,
@ -3538,6 +3520,7 @@ impl Renderer {
self.device.set_blend(true);
match batch.key.blend_mode {
BlendMode::Alpha => panic!("Attempt to composite non-premultiplied text primitives."),
BlendMode::PremultipliedAlpha => {
self.device.set_blend_mode_premultiplied_alpha();
@ -3706,6 +3689,10 @@ impl Renderer {
BlendMode::None => {
self.device.set_blend(false);
}
BlendMode::Alpha => {
self.device.set_blend(true);
self.device.set_blend_mode_alpha();
}
BlendMode::PremultipliedAlpha => {
self.device.set_blend(true);
self.device.set_blend_mode_premultiplied_alpha();
@ -3963,6 +3950,51 @@ impl Renderer {
self.gpu_profile.finish_sampler(alpha_sampler);
}
fn draw_texture_cache_target(
&mut self,
texture: &SourceTexture,
layer: i32,
target: &TextureCacheRenderTarget,
stats: &mut RendererStats,
) {
let projection = {
let texture = self.texture_resolver
.resolve(texture)
.expect("BUG: invalid target texture");
let target_size = texture.get_dimensions();
self.device
.bind_draw_target(Some((texture, layer)), Some(target_size));
self.device.disable_depth();
self.device.disable_depth_write();
self.device.set_blend(false);
Transform3D::ortho(
0.0,
target_size.width as f32,
0.0,
target_size.height as f32,
ORTHO_NEAR_PLANE,
ORTHO_FAR_PLANE,
)
};
// Draw any blurs for this target.
if !target.horizontal_blurs.is_empty() {
let _timer = self.gpu_profile.start_timer(GPU_TAG_BLUR);
self.cs_blur_a8
.bind(&mut self.device, &projection, 0, &mut self.renderer_errors);
self.draw_instanced_batch(
&target.horizontal_blurs,
VertexArrayKind::Blur,
&BatchTextures::no_texture(),
stats,
);
}
}
fn update_deferred_resolves(&mut self, frame: &Frame) -> Option<GpuCacheUpdateList> {
// The first thing we do is run through any pending deferred
// resolves, and use a callback to get the UV rect for this
@ -4082,6 +4114,7 @@ impl Renderer {
}
} else {
if list.texture.is_some() {
list.check_ready();
return
}
match self.texture_resolver.render_target_pool.pop() {
@ -4103,13 +4136,14 @@ impl Renderer {
None,
);
list.texture = Some(texture);
list.check_ready();
}
fn prepare_tile_frame(&mut self, frame: &mut Frame) {
// Init textures and render targets to match this scene.
// First pass grabs all the perfectly matching targets from the pool.
for pass in &mut frame.passes {
if let RenderPassKind::OffScreen { ref mut alpha, ref mut color } = pass.kind {
if let RenderPassKind::OffScreen { ref mut alpha, ref mut color, .. } = pass.kind {
self.prepare_target_list(alpha, true);
self.prepare_target_list(color, true);
}
@ -4123,7 +4157,7 @@ impl Renderer {
// 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 {
if let RenderPassKind::OffScreen { ref mut alpha, ref mut color, .. } = pass.kind {
self.prepare_target_list(alpha, false);
self.prepare_target_list(color, false);
}
@ -4216,9 +4250,17 @@ impl Renderer {
(None, None)
}
RenderPassKind::OffScreen { ref mut alpha, ref mut color } => {
assert!(alpha.targets.is_empty() || alpha.texture.is_some());
assert!(color.targets.is_empty() || color.texture.is_some());
RenderPassKind::OffScreen { ref mut alpha, ref mut color, ref mut texture_cache } => {
alpha.check_ready();
color.check_ready();
for (&(texture_id, target_index), target) in texture_cache {
self.draw_texture_cache_target(
&texture_id,
target_index,
target,
stats,
);
}
for (target_index, target) in alpha.targets.iter().enumerate() {
stats.alpha_target_count += 1;

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

@ -4,8 +4,7 @@
use api::{AddFont, BlobImageData, BlobImageResources, ResourceUpdate, ResourceUpdates};
use api::{BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest};
use api::ColorF;
use api::{DevicePoint, DeviceUintRect, DeviceUintSize};
use api::{ColorF, DevicePoint, DeviceUintRect, DeviceUintSize};
use api::{Epoch, FontInstanceKey, FontKey, FontTemplate};
use api::{ExternalImageData, ExternalImageType};
use api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
@ -25,6 +24,7 @@ use internal_types::{FastHashMap, FastHashSet, SourceTexture, TextureUpdateList}
use internal_types::ExternalCaptureImage;
use profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
use rayon::ThreadPool;
use render_task::{RenderTaskCache, RenderTaskCacheKey, RenderTaskId, RenderTaskTree};
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
use std::cmp;
use std::fmt::Debug;
@ -52,6 +52,7 @@ pub struct GlyphFetchResult {
// storing the coordinates as texel values
// we don't need to go through and update
// various CPU-side structures.
#[derive(Debug)]
pub struct CacheItem {
pub texture_id: SourceTexture,
pub uv_rect_handle: GpuCacheHandle,
@ -219,6 +220,7 @@ impl BlobImageResources for Resources {
pub struct ResourceCache {
cached_glyphs: GlyphCache,
cached_images: ImageCache,
cached_render_tasks: RenderTaskCache,
resources: Resources,
state: State,
@ -247,6 +249,7 @@ impl ResourceCache {
ResourceCache {
cached_glyphs: GlyphCache::new(),
cached_images: ResourceClassCache::new(),
cached_render_tasks: RenderTaskCache::new(),
resources: Resources {
font_templates: FastHashMap::default(),
font_instances: Arc::new(RwLock::new(FastHashMap::default())),
@ -278,6 +281,27 @@ impl ResourceCache {
}
}
// Request the texture cache item for a cacheable render
// task. If the item is already cached, the texture cache
// handle will be returned. Otherwise, the user supplied
// closure will be invoked to generate the render task
// chain that is required to draw this task.
pub fn request_render_task<F>(
&mut self,
key: RenderTaskCacheKey,
gpu_cache: &mut GpuCache,
render_tasks: &mut RenderTaskTree,
f: F,
) -> CacheItem where F: FnMut(&mut RenderTaskTree) -> (RenderTaskId, [f32; 3]) {
self.cached_render_tasks.request_render_task(
key,
&mut self.texture_cache,
gpu_cache,
render_tasks,
f
)
}
pub fn update_resources(
&mut self,
updates: ResourceUpdates,
@ -762,6 +786,7 @@ impl ResourceCache {
debug_assert_eq!(self.state, State::Idle);
self.state = State::AddResources;
self.texture_cache.begin_frame(frame_id);
self.cached_render_tasks.begin_frame(&mut self.texture_cache);
self.current_frame_id = frame_id;
}
@ -871,7 +896,7 @@ impl ResourceCache {
&mut entry.texture_cache_handle,
descriptor,
filter,
image_data,
Some(image_data),
[0.0; 3],
image_template.dirty_rect,
gpu_cache,
@ -896,6 +921,7 @@ impl ResourceCache {
// recently used resources.
self.cached_images.clear();
self.cached_glyphs.clear();
self.cached_render_tasks.clear();
}
pub fn clear_namespace(&mut self, namespace: IdNamespace) {
@ -1127,6 +1153,7 @@ impl ResourceCache {
info!("loading resource cache");
self.cached_glyphs.clear();
self.cached_images.clear();
self.cached_render_tasks.clear();
self.state = State::Idle;
self.current_frame_id = FrameId(0);

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

@ -206,7 +206,7 @@ impl TextureCache {
TextureCache {
max_texture_size,
array_a8_linear: TextureArray::new(
ImageFormat::A8,
ImageFormat::R8,
TextureFilter::Linear,
TEXTURE_ARRAY_LAYERS_LINEAR,
),
@ -284,7 +284,7 @@ impl TextureCache {
handle: &mut TextureCacheHandle,
descriptor: ImageDescriptor,
filter: TextureFilter,
data: ImageData,
data: Option<ImageData>,
user_data: [f32; 3],
mut dirty_rect: Option<DeviceUintRect>,
gpu_cache: &mut GpuCache,
@ -337,6 +337,7 @@ impl TextureCache {
// Create an update command, which the render thread processes
// to upload the new image data into the correct location
// in GPU memory.
if let Some(data) = data {
let (layer_index, origin) = match entry.kind {
EntryKind::Standalone { .. } => (0, DeviceUintPoint::zero()),
EntryKind::Cache {
@ -357,6 +358,7 @@ impl TextureCache {
);
self.pending_updates.push(op);
}
}
// Get a specific region by index from a shared texture array.
fn get_region_mut(&mut self,
@ -365,18 +367,26 @@ impl TextureCache {
region_index: u16
) -> &mut TextureRegion {
let texture_array = match (format, filter) {
(ImageFormat::A8, TextureFilter::Linear) => &mut self.array_a8_linear,
(ImageFormat::R8, TextureFilter::Linear) => &mut self.array_a8_linear,
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
(ImageFormat::Invalid, _) |
(ImageFormat::RGBAF32, _) |
(ImageFormat::RG8, _) |
(ImageFormat::A8, TextureFilter::Nearest) => unreachable!(),
(ImageFormat::R8, TextureFilter::Nearest) => unreachable!(),
};
&mut texture_array.regions[region_index as usize]
}
// Check if a given texture handle has a valid allocation
// in the texture cache.
pub fn is_allocated(&self, handle: &TextureCacheHandle) -> bool {
handle.entry.as_ref().map_or(false, |handle| {
self.entries.get_opt(handle).is_some()
})
}
// Retrieve the details of an item in the cache. This is used
// during batch creation to provide the resource rect address
// to the shaders and texture ID to the batching logic.
@ -398,6 +408,36 @@ impl TextureCache {
}
}
// A more detailed version of get(). This allows access to the actual
// device rect of the cache allocation.
pub fn get_cache_location(
&self,
handle: &TextureCacheHandle,
) -> (SourceTexture, i32, DeviceUintRect) {
let handle = handle
.entry
.as_ref()
.expect("BUG: handle not requested earlier in frame");
let entry = self.entries
.get_opt(handle)
.expect("BUG: was dropped from cache or not updated!");
debug_assert_eq!(entry.last_access, self.frame_id);
let (layer_index, origin) = match entry.kind {
EntryKind::Standalone { .. } => {
(0, DeviceUintPoint::zero())
}
EntryKind::Cache {
layer_index,
origin,
..
} => (layer_index, origin),
};
(SourceTexture::TextureCache(entry.texture_id),
layer_index as i32,
DeviceUintRect::new(origin, entry.size))
}
// Expire old standalone textures.
fn expire_old_standalone_entries(&mut self) {
let mut eviction_candidates = Vec::new();
@ -470,7 +510,7 @@ impl TextureCache {
// want to evict everything we can, since that will result in
// more items being uploaded than necessary.
// Instead, we say we will keep evicting until both of these
// consitions are met:
// conditions are met:
// - We have evicted some arbitrary number of items (512 currently).
// AND
// - We have freed an item that will definitely allow us to
@ -537,12 +577,12 @@ impl TextureCache {
) -> Option<CacheEntry> {
// Work out which cache it goes in, based on format.
let texture_array = match (descriptor.format, filter) {
(ImageFormat::A8, TextureFilter::Linear) => &mut self.array_a8_linear,
(ImageFormat::R8, TextureFilter::Linear) => &mut self.array_a8_linear,
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
(ImageFormat::Invalid, _) |
(ImageFormat::RGBAF32, _) |
(ImageFormat::A8, TextureFilter::Nearest) |
(ImageFormat::R8, TextureFilter::Nearest) |
(ImageFormat::RG8, _) => unreachable!(),
};

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

@ -14,16 +14,15 @@ use gpu_cache::{GpuCache, GpuCacheUpdateList};
use gpu_types::{BlurDirection, BlurInstance, BrushInstance, ClipChainRectIndex};
use gpu_types::{ClipScrollNodeData, ClipScrollNodeIndex};
use gpu_types::{PrimitiveInstance};
use internal_types::{FastHashMap, RenderPassIndex};
use internal_types::{FastHashMap, RenderPassIndex, SourceTexture};
use picture::{PictureKind};
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveStore};
use prim_store::{BrushMaskKind, BrushKind, DeferredResolve};
use prim_store::{BrushMaskKind, BrushKind, DeferredResolve, EdgeAaSegmentMask};
use profiler::FrameProfileCounters;
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKey, RenderTaskKind};
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind};
use render_task::{BlurTask, ClearMode, RenderTaskLocation, RenderTaskTree};
use resource_cache::{ResourceCache};
use std::{cmp, usize, f32, i32};
use std::collections::hash_map::Entry;
use texture_allocator::GuillotineAllocator;
const MIN_TARGET_SIZE: u32 = 2048;
@ -38,12 +37,6 @@ pub struct ScrollbarPrimitive {
#[derive(Debug, Copy, Clone)]
pub struct RenderTargetIndex(pub usize);
#[derive(Debug)]
struct DynamicTaskInfo {
task_id: RenderTaskId,
rect: DeviceIntRect,
}
pub struct RenderTargetContext<'a> {
pub device_pixel_scale: DevicePixelScale,
pub prim_store: &'a PrimitiveStore,
@ -201,6 +194,22 @@ impl<T: RenderTarget> RenderTargetList<T> {
pub fn needs_depth(&self) -> bool {
self.targets.iter().any(|target| target.needs_depth())
}
pub fn check_ready(&self) {
match self.texture {
Some(ref t) => {
assert_eq!(t.get_dimensions(), self.max_size);
assert_eq!(t.get_format(), self.format);
assert_eq!(t.get_render_target_layer_count(), self.targets.len());
assert_eq!(t.get_layer_count() as usize, self.targets.len());
assert_eq!(t.has_depth(), t.get_rt_info().unwrap().has_depth);
assert_eq!(t.has_depth(), self.needs_depth());
}
None => {
assert!(self.targets.is_empty())
}
}
}
}
/// Frame output information for a given pipeline ID.
@ -282,9 +291,6 @@ impl RenderTarget for ColorRenderTarget {
let task = &render_tasks[task_id];
match task.kind {
RenderTaskKind::Alias(..) => {
panic!("BUG: add_task() called on invalidated task");
}
RenderTaskKind::VerticalBlur(ref info) => {
info.add_instances(
&mut self.vertical_blurs,
@ -409,9 +415,6 @@ impl RenderTarget for AlphaRenderTarget {
}
match task.kind {
RenderTaskKind::Alias(..) => {
panic!("BUG: add_task() called on invalidated task");
}
RenderTaskKind::Readback(..) => {
panic!("Should not be added to alpha target!");
}
@ -465,13 +468,15 @@ impl RenderTarget for AlphaRenderTarget {
clip_task_address: RenderTaskAddress(0),
z: 0,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
user_data0: 0,
user_data1: 0,
};
let brush = &ctx.prim_store.cpu_brushes[sub_metadata.cpu_prim_index.0];
let batch = match brush.kind {
BrushKind::Solid { .. } |
BrushKind::Clear => {
BrushKind::Clear |
BrushKind::Line { .. } => {
unreachable!("bug: unexpected brush here");
}
BrushKind::Mask { ref kind, .. } => {
@ -525,12 +530,54 @@ impl RenderTarget for AlphaRenderTarget {
}
}
pub struct TextureCacheRenderTarget {
pub horizontal_blurs: Vec<BlurInstance>,
}
impl TextureCacheRenderTarget {
fn new(
_size: Option<DeviceUintSize>,
_screen_size: DeviceIntSize,
) -> Self {
TextureCacheRenderTarget {
horizontal_blurs: Vec::new(),
}
}
fn add_task(
&mut self,
task_id: RenderTaskId,
render_tasks: &RenderTaskTree,
) {
let task = &render_tasks[task_id];
match task.kind {
RenderTaskKind::HorizontalBlur(ref info) => {
info.add_instances(
&mut self.horizontal_blurs,
task_id,
task.children[0],
BlurDirection::Horizontal,
render_tasks,
);
}
RenderTaskKind::VerticalBlur(..) |
RenderTaskKind::Picture(..) |
RenderTaskKind::CacheMask(..) |
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) => {
panic!("BUG: unexpected task kind for texture cache target");
}
}
}
}
pub enum RenderPassKind {
MainFramebuffer(ColorRenderTarget),
OffScreen {
alpha: RenderTargetList<AlphaRenderTarget>,
color: RenderTargetList<ColorRenderTarget>,
texture_cache: FastHashMap<(SourceTexture, i32), TextureCacheRenderTarget>,
},
}
@ -542,7 +589,6 @@ pub enum RenderPassKind {
pub struct RenderPass {
pub kind: RenderPassKind,
tasks: Vec<RenderTaskId>,
dynamic_tasks: FastHashMap<RenderTaskKey, DynamicTaskInfo>,
}
impl RenderPass {
@ -551,7 +597,6 @@ impl RenderPass {
RenderPass {
kind: RenderPassKind::MainFramebuffer(target),
tasks: vec![],
dynamic_tasks: FastHashMap::default(),
}
}
@ -559,10 +604,10 @@ impl RenderPass {
RenderPass {
kind: RenderPassKind::OffScreen {
color: RenderTargetList::new(screen_size, ImageFormat::BGRA8),
alpha: RenderTargetList::new(screen_size, ImageFormat::A8),
alpha: RenderTargetList::new(screen_size, ImageFormat::R8),
texture_cache: FastHashMap::default(),
},
tasks: vec![],
dynamic_tasks: FastHashMap::default(),
}
}
@ -572,7 +617,7 @@ impl RenderPass {
size: DeviceIntSize,
target_kind: RenderTargetKind,
) {
if let RenderPassKind::OffScreen { ref mut color, ref mut alpha } = self.kind {
if let RenderPassKind::OffScreen { ref mut color, ref mut alpha, .. } = self.kind {
let max_size = match target_kind {
RenderTargetKind::Color => &mut color.max_size,
RenderTargetKind::Alpha => &mut alpha.max_size,
@ -604,10 +649,10 @@ impl RenderPass {
}
target.build(ctx, gpu_cache, render_tasks, deferred_resolves);
}
RenderPassKind::OffScreen { ref mut color, ref mut alpha } => {
RenderPassKind::OffScreen { ref mut color, ref mut alpha, ref mut texture_cache } => {
// Step through each task, adding to batches as appropriate.
for &task_id in &self.tasks {
let target_kind = {
let (target_kind, texture_target) = {
let task = &mut render_tasks[task_id];
task.pass_index = Some(pass_index);
let target_kind = task.target_kind();
@ -615,22 +660,16 @@ impl RenderPass {
// Find a target to assign this task to, or create a new
// one if required.
match task.location {
RenderTaskLocation::Fixed => {}
RenderTaskLocation::TextureCache(texture_id, layer, _) => {
// TODO(gw): When we support caching color items, we will
// need to calculate that here to get the
// correct target kind.
(RenderTargetKind::Alpha, Some((texture_id, layer)))
}
RenderTaskLocation::Fixed => {
(RenderTargetKind::Color, None)
}
RenderTaskLocation::Dynamic(ref mut origin, size) => {
let dynamic_entry = match task.cache_key {
// See if this task is a duplicate.
// If so, just skip adding it!
Some(cache_key) => match self.dynamic_tasks.entry(cache_key) {
Entry::Occupied(entry) => {
debug_assert_eq!(entry.get().rect.size, size);
task.kind = RenderTaskKind::Alias(entry.get().task_id);
continue;
},
Entry::Vacant(entry) => Some(entry),
},
None => None,
};
let alloc_size = DeviceUintSize::new(size.width as u32, size.height as u32);
let (alloc_origin, target_index) = match target_kind {
RenderTargetKind::Color => color.allocate(alloc_size),
@ -638,25 +677,28 @@ impl RenderPass {
};
*origin = Some((alloc_origin.to_i32(), target_index));
// If this task is cacheable / sharable, store it in the task hash
// for this pass.
if let Some(entry) = dynamic_entry {
entry.insert(DynamicTaskInfo {
task_id,
rect: DeviceIntRect::new(alloc_origin.to_i32(), size),
});
(target_kind, None)
}
}
}
target_kind
};
match texture_target {
Some(texture_target) => {
let texture = texture_cache
.entry(texture_target)
.or_insert(
TextureCacheRenderTarget::new(None, DeviceIntSize::zero())
);
texture.add_task(task_id, render_tasks);
}
None => {
match target_kind {
RenderTargetKind::Color => color.add_task(task_id, ctx, gpu_cache, render_tasks, clip_store),
RenderTargetKind::Alpha => alpha.add_task(task_id, ctx, gpu_cache, render_tasks, clip_store),
}
}
}
}
color.build(ctx, gpu_cache, render_tasks, deferred_resolves);
alpha.build(ctx, gpu_cache, render_tasks, deferred_resolves);
@ -726,18 +768,8 @@ impl BlurTask {
task_address: render_tasks.get_task_address(task_id),
src_task_address: render_tasks.get_task_address(source_task_id),
blur_direction,
region: LayerRect::zero(),
};
if self.regions.is_empty() {
instances.push(instance);
} else {
for region in &self.regions {
instances.push(BlurInstance {
region: *region,
..instance
});
}
}
}
}

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

@ -111,6 +111,7 @@ pub enum SpecificDisplayItem {
BoxShadow(BoxShadowDisplayItem),
Gradient(GradientDisplayItem),
RadialGradient(RadialGradientDisplayItem),
ClipChain(ClipChainItem),
Iframe(IframeDisplayItem),
PushStackingContext(PushStackingContextDisplayItem),
PopStackingContext,
@ -126,6 +127,7 @@ pub enum SpecificDisplayItem {
#[derive(Deserialize, Serialize)]
pub enum CompletelySpecificDisplayItem {
Clip(ClipDisplayItem, Vec<ComplexClipRegion>),
ClipChain(ClipChainItem, Vec<ClipId>),
ScrollFrame(ScrollFrameDisplayItem, Vec<ComplexClipRegion>),
StickyFrame(StickyFrameDisplayItem),
Rectangle(RectangleDisplayItem),
@ -426,6 +428,12 @@ pub struct RadialGradient {
pub extend_mode: ExtendMode,
} // IMPLICIT stops: Vec<GradientStop>
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct ClipChainItem {
pub id: ClipChainId,
pub parent: Option<ClipChainId>,
} // IMPLICIT stops: Vec<ClipId>
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct RadialGradientDisplayItem {
pub gradient: RadialGradient,
@ -507,6 +515,7 @@ pub struct ImageDisplayItem {
pub stretch_size: LayoutSize,
pub tile_spacing: LayoutSize,
pub image_rendering: ImageRendering,
pub alpha_type: AlphaType,
}
#[repr(u32)]
@ -517,6 +526,12 @@ pub enum ImageRendering {
Pixelated = 2,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum AlphaType {
Alpha = 0,
PremultipliedAlpha = 1,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct YuvImageDisplayItem {
pub yuv_data: YuvData,
@ -727,9 +742,14 @@ impl ComplexClipRegion {
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ClipChainId(pub u64, pub PipelineId);
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ClipId {
Clip(u64, PipelineId),
ClipChain(ClipChainId),
ClipExternalId(u64, PipelineId),
DynamicallyAddedNode(u64, PipelineId),
}
@ -756,6 +776,7 @@ impl ClipId {
pub fn pipeline_id(&self) -> PipelineId {
match *self {
ClipId::Clip(_, pipeline_id) |
ClipId::ClipChain(ClipChainId(_, pipeline_id)) |
ClipId::ClipExternalId(_, pipeline_id) |
ClipId::DynamicallyAddedNode(_, pipeline_id) => pipeline_id,
}

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

@ -2,17 +2,17 @@
* 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 {BorderDetails, BorderDisplayItem, BorderRadius, BorderWidths, BoxShadowClipMode};
use {BoxShadowDisplayItem, ClipAndScrollInfo, ClipDisplayItem, ClipId, ColorF, ComplexClipRegion};
use {DisplayItem, ExtendMode, FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, Gradient};
use {GradientDisplayItem, GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask};
use {ImageRendering, LayerPrimitiveInfo, LayoutPoint, LayoutPrimitiveInfo, LayoutRect, LayoutSize};
use {LayoutTransform, LayoutVector2D, LineDisplayItem, LineOrientation, LineStyle, LocalClip};
use {MixBlendMode, PipelineId, PropertyBinding, PushStackingContextDisplayItem, RadialGradient};
use {RadialGradientDisplayItem, RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy};
use {ScrollSensitivity, Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem};
use {StickyOffsetBounds, TextDisplayItem, TransformStyle, YuvColorSpace, YuvData};
use YuvImageDisplayItem;
use {AlphaType, BorderDetails, BorderDisplayItem, BorderRadius, BorderWidths, BoxShadowClipMode};
use {BoxShadowDisplayItem, ClipAndScrollInfo, ClipChainId, ClipChainItem, ClipDisplayItem, ClipId};
use {ColorF, ComplexClipRegion, DisplayItem, ExtendMode, FilterOp, FontInstanceKey, GlyphInstance};
use {GlyphOptions, Gradient, GradientDisplayItem, GradientStop, IframeDisplayItem};
use {ImageDisplayItem, ImageKey, ImageMask, ImageRendering, LayerPrimitiveInfo, LayoutPoint};
use {LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
use {LineDisplayItem, LineOrientation, LineStyle, LocalClip, MixBlendMode, PipelineId};
use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow};
use {SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, StickyOffsetBounds};
use {TextDisplayItem, TransformStyle, YuvColorSpace, YuvData, YuvImageDisplayItem};
use bincode;
use euclid::SideOffsets2D;
use serde::{Deserialize, Serialize};
@ -86,6 +86,7 @@ pub struct BuiltDisplayListIter<'a> {
cur_stops: ItemRange<GradientStop>,
cur_glyphs: ItemRange<GlyphInstance>,
cur_filters: ItemRange<FilterOp>,
cur_clip_chain_items: ItemRange<ClipId>,
cur_complex_clip: (ItemRange<ComplexClipRegion>, usize),
peeking: Peek,
}
@ -197,6 +198,7 @@ impl<'a> BuiltDisplayListIter<'a> {
cur_stops: ItemRange::default(),
cur_glyphs: ItemRange::default(),
cur_filters: ItemRange::default(),
cur_clip_chain_items: ItemRange::default(),
cur_complex_clip: (ItemRange::default(), 0),
peeking: Peek::NotPeeking,
}
@ -223,6 +225,7 @@ impl<'a> BuiltDisplayListIter<'a> {
// Don't let these bleed into another item
self.cur_stops = ItemRange::default();
self.cur_complex_clip = (ItemRange::default(), 0);
self.cur_clip_chain_items = ItemRange::default();
loop {
if self.data.len() == 0 {
@ -243,6 +246,9 @@ impl<'a> BuiltDisplayListIter<'a> {
// This is a dummy item, skip over it
continue;
}
ClipChain(_) => {
self.cur_clip_chain_items = skip_slice::<ClipId>(self.list, &mut self.data).0;
}
Clip(_) | ScrollFrame(_) => {
self.cur_complex_clip = self.skip_slice::<ComplexClipRegion>()
}
@ -356,6 +362,10 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
self.iter.cur_filters
}
pub fn clip_chain_items(&self) -> ItemRange<ClipId> {
self.iter.cur_clip_chain_items
}
pub fn display_list(&self) -> &BuiltDisplayList {
self.iter.display_list()
}
@ -418,20 +428,27 @@ impl Serialize for BuiltDisplayList {
let mut seq = serializer.serialize_seq(None)?;
let mut traversal = self.iter();
while let Some(item) = traversal.next() {
let di = item.display_item();
let display_item = item.display_item();
let serial_di = GenericDisplayItem {
item: match di.item {
SpecificDisplayItem::Clip(v) => Clip(v,
item: match display_item.item {
SpecificDisplayItem::Clip(v) => Clip(
v,
item.iter.list.get(item.iter.cur_complex_clip.0).collect()
),
SpecificDisplayItem::ScrollFrame(v) => ScrollFrame(v,
SpecificDisplayItem::ClipChain(v) => ClipChain(
v,
item.iter.list.get(item.iter.cur_clip_chain_items).collect(),
),
SpecificDisplayItem::ScrollFrame(v) => ScrollFrame(
v,
item.iter.list.get(item.iter.cur_complex_clip.0).collect()
),
SpecificDisplayItem::StickyFrame(v) => StickyFrame(v),
SpecificDisplayItem::Rectangle(v) => Rectangle(v),
SpecificDisplayItem::ClearRectangle => ClearRectangle,
SpecificDisplayItem::Line(v) => Line(v),
SpecificDisplayItem::Text(v) => Text(v,
SpecificDisplayItem::Text(v) => Text(
v,
item.iter.list.get(item.iter.cur_glyphs).collect()
),
SpecificDisplayItem::Image(v) => Image(v),
@ -441,7 +458,8 @@ impl Serialize for BuiltDisplayList {
SpecificDisplayItem::Gradient(v) => Gradient(v),
SpecificDisplayItem::RadialGradient(v) => RadialGradient(v),
SpecificDisplayItem::Iframe(v) => Iframe(v),
SpecificDisplayItem::PushStackingContext(v) => PushStackingContext(v,
SpecificDisplayItem::PushStackingContext(v) => PushStackingContext(
v,
item.iter.list.get(item.iter.cur_filters).collect()
),
SpecificDisplayItem::PopStackingContext => PopStackingContext,
@ -451,8 +469,8 @@ impl Serialize for BuiltDisplayList {
SpecificDisplayItem::PushShadow(v) => PushShadow(v),
SpecificDisplayItem::PopAllShadows => PopAllShadows,
},
clip_and_scroll: di.clip_and_scroll,
info: di.info,
clip_and_scroll: display_item.clip_and_scroll,
info: display_item.info,
};
seq.serialize_element(&serial_di)?
}
@ -492,39 +510,44 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
for complete in list {
let item = DisplayItem {
item: match complete.item {
Clip(v, complex_clips) => {
Clip(specific_item, complex_clips) => {
push_vec(&mut temp, complex_clips);
SpecificDisplayItem::Clip(v)
SpecificDisplayItem::Clip(specific_item)
},
ScrollFrame(v, complex_clips) => {
ClipChain(specific_item, clip_chain_ids) => {
push_vec(&mut temp, clip_chain_ids);
SpecificDisplayItem::ClipChain(specific_item)
}
ScrollFrame(specific_item, complex_clips) => {
push_vec(&mut temp, complex_clips);
SpecificDisplayItem::ScrollFrame(v)
SpecificDisplayItem::ScrollFrame(specific_item)
},
StickyFrame(v) => SpecificDisplayItem::StickyFrame(v),
Rectangle(v) => SpecificDisplayItem::Rectangle(v),
StickyFrame(specific_item) => SpecificDisplayItem::StickyFrame(specific_item),
Rectangle(specific_item) => SpecificDisplayItem::Rectangle(specific_item),
ClearRectangle => SpecificDisplayItem::ClearRectangle,
Line(v) => SpecificDisplayItem::Line(v),
Text(v, glyphs) => {
Line(specific_item) => SpecificDisplayItem::Line(specific_item),
Text(specific_item, glyphs) => {
push_vec(&mut temp, glyphs);
SpecificDisplayItem::Text(v)
SpecificDisplayItem::Text(specific_item)
},
Image(v) => SpecificDisplayItem::Image(v),
YuvImage(v) => SpecificDisplayItem::YuvImage(v),
Border(v) => SpecificDisplayItem::Border(v),
BoxShadow(v) => SpecificDisplayItem::BoxShadow(v),
Gradient(v) => SpecificDisplayItem::Gradient(v),
RadialGradient(v) => SpecificDisplayItem::RadialGradient(v),
Iframe(v) => SpecificDisplayItem::Iframe(v),
PushStackingContext(v, filters) => {
Image(specific_item) => SpecificDisplayItem::Image(specific_item),
YuvImage(specific_item) => SpecificDisplayItem::YuvImage(specific_item),
Border(specific_item) => SpecificDisplayItem::Border(specific_item),
BoxShadow(specific_item) => SpecificDisplayItem::BoxShadow(specific_item),
Gradient(specific_item) => SpecificDisplayItem::Gradient(specific_item),
RadialGradient(specific_item) =>
SpecificDisplayItem::RadialGradient(specific_item),
Iframe(specific_item) => SpecificDisplayItem::Iframe(specific_item),
PushStackingContext(specific_item, filters) => {
push_vec(&mut temp, filters);
SpecificDisplayItem::PushStackingContext(v)
SpecificDisplayItem::PushStackingContext(specific_item)
},
PopStackingContext => SpecificDisplayItem::PopStackingContext,
SetGradientStops(stops) => {
push_vec(&mut temp, stops);
SpecificDisplayItem::SetGradientStops
},
PushShadow(v) => SpecificDisplayItem::PushShadow(v),
PushShadow(specific_item) => SpecificDisplayItem::PushShadow(specific_item),
PopAllShadows => SpecificDisplayItem::PopAllShadows,
},
clip_and_scroll: complete.clip_and_scroll,
@ -766,6 +789,7 @@ pub struct SaveState {
dl_len: usize,
clip_stack_len: usize,
next_clip_id: u64,
next_clip_chain_id: u64,
}
#[derive(Clone)]
@ -774,6 +798,7 @@ pub struct DisplayListBuilder {
pub pipeline_id: PipelineId,
clip_stack: Vec<ClipAndScrollInfo>,
next_clip_id: u64,
next_clip_chain_id: u64,
builder_start_time: u64,
/// The size of the content of this display list. This is used to allow scrolling
@ -804,6 +829,7 @@ impl DisplayListBuilder {
ClipAndScrollInfo::simple(ClipId::root_scroll_node(pipeline_id)),
],
next_clip_id: FIRST_CLIP_ID,
next_clip_chain_id: 0,
builder_start_time: start_time,
content_size,
save_state: None,
@ -829,6 +855,7 @@ impl DisplayListBuilder {
clip_stack_len: self.clip_stack.len(),
dl_len: self.data.len(),
next_clip_id: self.next_clip_id,
next_clip_chain_id: self.next_clip_chain_id,
});
}
@ -839,6 +866,7 @@ impl DisplayListBuilder {
self.clip_stack.truncate(state.clip_stack_len);
self.data.truncate(state.dl_len);
self.next_clip_id = state.next_clip_id;
self.next_clip_chain_id = state.next_clip_chain_id;
}
/// Discards the builder's save (indicating the attempted operation was sucessful).
@ -964,6 +992,7 @@ impl DisplayListBuilder {
stretch_size: LayoutSize,
tile_spacing: LayoutSize,
image_rendering: ImageRendering,
alpha_type: AlphaType,
key: ImageKey,
) {
let item = SpecificDisplayItem::Image(ImageDisplayItem {
@ -971,6 +1000,7 @@ impl DisplayListBuilder {
stretch_size,
tile_spacing,
image_rendering,
alpha_type,
});
self.push_item(item, info);
@ -1315,6 +1345,11 @@ impl DisplayListBuilder {
})
}
fn generate_clip_chain_id(&mut self) -> ClipChainId {
self.next_clip_chain_id += 1;
ClipChainId(self.next_clip_chain_id - 1, self.pipeline_id)
}
pub fn define_scroll_frame<I>(
&mut self,
id: Option<ClipId>,
@ -1355,8 +1390,8 @@ impl DisplayListBuilder {
{
let id = self.generate_clip_id(id);
let item = SpecificDisplayItem::ScrollFrame(ScrollFrameDisplayItem {
id: id,
image_mask: image_mask,
id,
image_mask,
scroll_sensitivity,
});
let info = LayoutPrimitiveInfo::with_clip_rect(content_rect, clip_rect);
@ -1367,6 +1402,21 @@ impl DisplayListBuilder {
id
}
pub fn define_clip_chain<I>(
&mut self,
parent: Option<ClipChainId>,
clips: I,
) -> ClipChainId
where
I: IntoIterator<Item = ClipId>,
I::IntoIter: ExactSizeIterator + Clone,
{
let id = self.generate_clip_chain_id();
self.push_new_empty_item(SpecificDisplayItem::ClipChain(ClipChainItem { id, parent}));
self.push_iter(clips);
id
}
pub fn define_clip<I>(
&mut self,
id: Option<ClipId>,

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

@ -199,6 +199,16 @@ impl Hash for FontVariation {
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct GlyphOptions {
pub render_mode: FontRenderMode,
pub flags: FontInstanceFlags,
}
impl Default for GlyphOptions {
fn default() -> GlyphOptions {
GlyphOptions {
render_mode: FontRenderMode::Subpixel,
flags: FontInstanceFlags::empty(),
}
}
}
bitflags! {
@ -210,6 +220,9 @@ bitflags! {
const SYNTHETIC_BOLD = 1 << 1;
const EMBEDDED_BITMAPS = 1 << 2;
const SUBPIXEL_BGR = 1 << 3;
const TRANSPOSE = 1 << 4;
const FLIP_X = 1 << 5;
const FLIP_Y = 1 << 6;
// Windows flags
const FORCE_GDI = 1 << 16;

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

@ -51,7 +51,7 @@ pub struct ExternalImageData {
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ImageFormat {
Invalid = 0,
A8 = 1,
R8 = 1,
BGRA8 = 3,
RGBAF32 = 4,
RG8 = 5,
@ -60,7 +60,7 @@ pub enum ImageFormat {
impl ImageFormat {
pub fn bytes_per_pixel(self) -> u32 {
match self {
ImageFormat::A8 => 1,
ImageFormat::R8 => 1,
ImageFormat::BGRA8 => 4,
ImageFormat::RGBAF32 => 16,
ImageFormat::RG8 => 2,