зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1429806 - Update webrender to commit eb9e1702df4b6dc036b649b3dd32ccc4bfbe43bf. r=jrmuizel
MozReview-Commit-ID: 7m0P5kgiWZF --HG-- extra : rebase_source : 4543ca28be94c735c24120892b5eb254afabd677
This commit is contained in:
Родитель
f8a2d60a78
Коммит
acf6b152ff
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче