Bug 1480433 - Update webrender to commit c939a61b83bcc9dc10742977704793e9a85b3858. r=jrmuizel

MozReview-Commit-ID: 8msYpcE1tCx
This commit is contained in:
Kartikaya Gupta 2018-08-07 14:44:43 -04:00
parent 1ca6fd6782
commit 56cfeb9660
16 changed files with 207 additions and 216 deletions

View File

@ -31,7 +31,7 @@ image = { optional = true, version = "0.19" }
lazy_static = "1"
log = "0.4"
num-traits = "0.2"
plane-split = "0.12"
plane-split = "0.12.1"
png = { optional = true, version = "0.12" }
rayon = "1"
ron = { optional = true, version = "0.1.7" }

View File

@ -2,13 +2,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{AlphaType, ClipMode, DeviceIntRect, DeviceIntSize};
use api::{DeviceUintRect, DeviceUintPoint, ExternalImageType, FilterOp, ImageRendering, LayoutRect};
use api::{DeviceIntPoint, YuvColorSpace, YuvFormat};
use api::{LayoutToWorldTransform, WorldPixel};
use api::{AlphaType, ClipMode, DeviceIntRect, DeviceIntSize, DeviceIntPoint};
use api::{DeviceUintRect, DeviceUintPoint, ExternalImageType, FilterOp, ImageRendering};
use api::{YuvColorSpace, YuvFormat, WorldPixel};
use clip::{ClipSource, ClipStore, ClipWorkItem};
use clip_scroll_tree::{CoordinateSystemId};
use euclid::{TypedTransform3D, vec3};
use euclid::vec3;
use glyph_rasterizer::GlyphFormat;
use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress};
use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders};
@ -17,17 +16,17 @@ use gpu_types::{PrimitiveInstance, RasterizationSpace, GlyphInstance};
use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
use plane_split::{BspSplitter, Polygon, Splitter};
use plane_split::{BspSplitter, Clipper, Polygon, Splitter};
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentTaskId, DeferredResolve};
use prim_store::{EdgeAaSegmentMask, ImageSource, PictureIndex, PrimitiveIndex, PrimitiveKind};
use prim_store::{PrimitiveMetadata, PrimitiveRun, PrimitiveStore, VisibleGradientTile};
use prim_store::{BorderSource};
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
use renderer::{BlendMode, ImageBufferKind};
use renderer::{BLOCKS_PER_UV_RECT, ShaderColorMode};
use renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
use renderer::BLOCKS_PER_UV_RECT;
use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache};
use scene::FilterOpHelpers;
use std::{usize, f32, i32};
use std::{f32, i32};
use tiling::{RenderTargetContext};
use util::{TransformedRectKind};
@ -676,19 +675,30 @@ impl AlphaBatchBuilder {
if picture.is_in_3d_context {
// Push into parent plane splitter.
debug_assert!(picture.surface.is_some());
let real_xf = &ctx
.transforms
let transform = &ctx.transforms
.get_transform(picture.reference_frame_index);
match make_polygon(
picture.real_local_rect,
&real_xf.m,
prim_index.0,
) {
Some(polygon) => splitter.add(polygon),
None => {
// this shouldn't happen, the path will ultimately be
// turned into `expect` when the splitting code is fixed
match transform.transform_kind {
TransformedRectKind::AxisAligned => {
let polygon = Polygon::from_transformed_rect(
picture.real_local_rect.cast(),
transform.m.cast(),
prim_index.0,
).unwrap();
splitter.add(polygon);
}
TransformedRectKind::Complex => {
let mut clipper = Clipper::new();
let bounds = (screen_rect.clipped.to_f32() / ctx.device_pixel_scale).to_f64();
let matrix = transform.m.cast();
let results = clipper.clip_transformed(
Polygon::from_rect(picture.real_local_rect.cast(), prim_index.0),
&matrix,
Some(bounds),
);
for poly in results {
splitter.add(poly);
}
}
}
@ -1709,33 +1719,6 @@ pub fn resolve_image(
}
}
/// Construct a polygon from stacking context boundaries.
/// `anchor` here is an index that's going to be preserved in all the
/// splits of the polygon.
fn make_polygon(
rect: LayoutRect,
transform: &LayoutToWorldTransform,
anchor: usize,
) -> Option<Polygon<f64, WorldPixel>> {
let mat = TypedTransform3D::row_major(
transform.m11 as f64,
transform.m12 as f64,
transform.m13 as f64,
transform.m14 as f64,
transform.m21 as f64,
transform.m22 as f64,
transform.m23 as f64,
transform.m24 as f64,
transform.m31 as f64,
transform.m32 as f64,
transform.m33 as f64,
transform.m34 as f64,
transform.m41 as f64,
transform.m42 as f64,
transform.m43 as f64,
transform.m44 as f64);
Polygon::from_transformed_rect(rect.cast(), mat, anchor)
}
/// Batcher managing draw calls into the clip mask (in the RT cache).
#[derive(Debug)]

View File

@ -9,9 +9,8 @@ use app_units::Au;
use ellipse::Ellipse;
use display_list_flattener::DisplayListFlattener;
use gpu_types::{BorderInstance, BorderSegment, BrushFlags};
use prim_store::{BrushKind, BrushPrimitive, BrushSegment, VECS_PER_SEGMENT};
use prim_store::{BrushKind, BrushPrimitive, BrushSegment};
use prim_store::{BorderSource, EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain};
use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
use util::{lerp, RectHelpers};
// Using 2048 as the maximum radius in device space before which we
@ -22,6 +21,10 @@ use util::{lerp, RectHelpers};
/// Maximum resolution in device pixels at which borders are rasterized.
pub const MAX_BORDER_RESOLUTION: u32 = 2048;
/// Maximum number of dots or dashes per segment to avoid freezing and filling up
/// memory with unreasonable inputs. It would be better to address this by not building
/// a list of per-dot information in the first place.
pub const MAX_DASH_COUNT: usize = 2048;
trait AuSizeConverter {
fn to_au(&self) -> LayoutSizeAu;
@ -355,11 +358,7 @@ impl BorderCornerClipSource {
1.0 - 2.0 * outer_scale.y,
);
// No point in pushing more clips as it will blow up the maximum amount of
// segments per primitive later down the road.
// See #2915 for a better fix.
let clip_limit = MAX_VERTEX_TEXTURE_WIDTH / VECS_PER_SEGMENT;
let max_clip_count = self.max_clip_count.min(clip_limit);
let max_clip_count = self.max_clip_count.min(MAX_DASH_COUNT);
match self.kind {
BorderCornerClipKind::Dash => {
@ -372,6 +371,7 @@ impl BorderCornerClipSource {
// sophisticated dash placement algorithm that takes into account
// the offset of the dashes along edge segments.
let mut current_arc_length = 0.25 * dash_arc_length;
dot_dash_data.reserve(max_clip_count);
for _ in 0 .. max_clip_count {
let arc_length0 = current_arc_length;
current_arc_length += dash_arc_length;
@ -425,8 +425,8 @@ impl BorderCornerClipSource {
]);
}
BorderCornerClipKind::Dot => {
let mut forward_dots = Vec::new();
let mut back_dots = Vec::new();
let mut forward_dots = Vec::with_capacity(max_clip_count / 2 + 1);
let mut back_dots = Vec::with_capacity(max_clip_count / 2 + 1);
let mut leftover_arc_length = 0.0;
// Alternate between adding dots at the start and end of the
@ -501,6 +501,8 @@ impl BorderCornerClipSource {
[center.x, center.y, radius, 0.0, 0.0, 0.0, 0.0, 0.0]
};
dot_dash_data.reserve(forward_dots.len() + back_dots.len());
for (i, dot) in forward_dots.iter().enumerate() {
let extra_dist = i as f32 * extra_space_per_dot;
let dot_data = create_dot_data(&self.ellipse, dot.arc_pos + extra_dist, 0.5 * dot.diameter);

View File

@ -2313,10 +2313,20 @@ impl<'a, T> TextureUploader<'a, T> {
layer_index: i32,
stride: Option<u32>,
data: &[T],
) {
) -> usize {
let bytes_pp = self.target.texture.format.bytes_per_pixel();
let upload_size = match stride {
Some(stride) => ((rect.size.height - 1) * stride + rect.size.width * bytes_pp) as usize,
None => (rect.size.area() * bytes_pp) as usize,
};
assert!(upload_size <= data.len() * mem::size_of::<T>());
match self.buffer {
Some(ref mut buffer) => {
let upload_size = mem::size_of::<T>() * data.len();
let elem_count = upload_size / mem::size_of::<T>();
assert_eq!(elem_count * mem::size_of::<T>(), upload_size);
let slice = &data[.. elem_count];
if buffer.size_used + upload_size > buffer.size_allocated {
// flush
for chunk in buffer.chunks.drain() {
@ -2329,7 +2339,7 @@ impl<'a, T> TextureUploader<'a, T> {
gl::buffer_data(
self.target.gl,
gl::PIXEL_UNPACK_BUFFER,
data,
slice,
buffer.usage,
);
buffer.size_allocated = upload_size;
@ -2338,7 +2348,7 @@ impl<'a, T> TextureUploader<'a, T> {
self.target.gl,
gl::PIXEL_UNPACK_BUFFER,
buffer.size_used as _,
data,
slice,
);
}
@ -2355,6 +2365,8 @@ impl<'a, T> TextureUploader<'a, T> {
});
}
}
upload_size
}
}

View File

@ -283,7 +283,7 @@ pub struct GpuMarker {
impl GpuMarker {
fn new(gl: &Rc<gl::Gl>, message: &str, ext_debug_marker: bool) -> Self {
let gl = if ext_debug_marker {
gl.push_group_marker_ext(message);
gl.push_group_marker_ext(message);
Some(Rc::clone(gl))
} else {
None

View File

@ -15,7 +15,7 @@ use platform::font::FontContext;
use glyph_rasterizer::{FontInstance, FontContexts, GlyphKey};
use glyph_rasterizer::{GlyphRasterizer, GlyphRasterJob, GlyphRasterJobs, GlyphRasterResult};
use glyph_cache::{GlyphCache, CachedGlyphInfo, GlyphCacheEntry};
use texture_cache::{TextureCache, TextureCacheHandle};
use texture_cache::{TextureCache, TextureCacheHandle, Eviction};
use gpu_cache::GpuCache;
use render_task::{RenderTaskTree, RenderTaskCache};
use tiling::SpecialRenderPasses;
@ -188,6 +188,7 @@ impl GlyphRasterizer {
gpu_cache,
Some(glyph_key_cache.eviction_notice()),
UvRectKind::Rect,
Eviction::Auto,
);
GlyphCacheEntry::Cached(CachedGlyphInfo {
texture_cache_handle,

View File

@ -37,7 +37,7 @@ pub struct GpuProfileTag {
pub label: &'static str,
pub color: ColorF,
}
impl NamedTag for GpuProfileTag {
fn get_label(&self) -> &str {
self.label
@ -457,6 +457,7 @@ pub struct RendererProfileCounters {
pub vao_count_and_size: ResourceProfileCounter,
pub color_targets: IntProfileCounter,
pub alpha_targets: IntProfileCounter,
pub texture_data_uploaded: IntProfileCounter,
}
pub struct RendererProfileTimers {
@ -475,6 +476,7 @@ impl RendererProfileCounters {
vao_count_and_size: ResourceProfileCounter::new("VAO"),
color_targets: IntProfileCounter::new("Color Targets"),
alpha_targets: IntProfileCounter::new("Alpha Targets"),
texture_data_uploaded: IntProfileCounter::new("Texture data, kb"),
}
}
@ -483,6 +485,7 @@ impl RendererProfileCounters {
self.vertices.reset();
self.color_targets.reset();
self.alpha_targets.reset();
self.texture_data_uploaded.reset();
}
}
@ -792,7 +795,6 @@ pub struct Profiler {
#[cfg(feature = "debug_renderer")]
impl Profiler {
pub fn new() -> Self {
Profiler {
draw_state: DrawState {
@ -1021,6 +1023,7 @@ impl Profiler {
&renderer_profile.alpha_targets,
&renderer_profile.draw_calls,
&renderer_profile.vertices,
&renderer_profile.texture_data_uploaded,
&self.backend_time,
&self.compositor_time,
&self.gpu_time,
@ -1047,6 +1050,7 @@ impl Profiler {
&renderer_profile.frame_counter,
&renderer_profile.color_targets,
&renderer_profile.alpha_targets,
&renderer_profile.texture_data_uploaded,
],
debug_renderer,
true,

View File

@ -26,7 +26,7 @@ use print_tree::{PrintTreePrinter};
use render_backend::FrameId;
use resource_cache::{CacheItem, ResourceCache};
use std::{cmp, ops, usize, f32, i32};
use texture_cache::{TextureCache, TextureCacheHandle};
use texture_cache::{TextureCache, TextureCacheHandle, Eviction};
use tiling::{RenderPass, RenderTargetIndex};
use tiling::{RenderTargetKind};
#[cfg(feature = "pathfinder")]
@ -1104,6 +1104,7 @@ impl RenderTaskCache {
gpu_cache,
None,
render_task.uv_rect_kind(),
Eviction::Auto,
);
// Get the allocation details in the texture cache, and store

View File

@ -2585,23 +2585,23 @@ impl Renderer {
0,
);
match source {
let bytes_uploaded = match source {
TextureUpdateSource::Bytes { data } => {
uploader.upload(
rect, layer_index, stride,
&data[offset as usize ..],
);
)
}
TextureUpdateSource::External { id, channel_index } => {
let handler = self.external_image_handler
.as_mut()
.expect("Found external image, but no handler set!");
match handler.lock(id, channel_index).source {
let size = match handler.lock(id, channel_index).source {
ExternalImageSource::RawData(data) => {
uploader.upload(
rect, layer_index, stride,
&data[offset as usize ..],
);
)
}
ExternalImageSource::Invalid => {
// Create a local buffer to fill the pbo.
@ -2611,15 +2611,18 @@ impl Renderer {
// WR haven't support RGBAF32 format in texture_cache, so
// we use u8 type here.
let dummy_data: Vec<u8> = vec![255; total_size as usize];
uploader.upload(rect, layer_index, stride, &dummy_data);
uploader.upload(rect, layer_index, stride, &dummy_data)
}
ExternalImageSource::NativeTexture(eid) => {
panic!("Unexpected external texture {:?} for the texture cache update of {:?}", eid, id);
}
};
handler.unlock(id, channel_index);
size
}
}
};
self.profile_counters.texture_data_uploaded.add(bytes_uploaded >> 10);
}
TextureUpdateOp::Free => {
let texture = &mut self.texture_resolver.cache_texture_map[update.id.0];

View File

@ -40,7 +40,7 @@ use std::hash::Hash;
#[cfg(any(feature = "capture", feature = "replay"))]
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
use texture_cache::{TextureCache, TextureCacheHandle};
use texture_cache::{TextureCache, TextureCacheHandle, Eviction};
use tiling::SpecialRenderPasses;
const DEFAULT_TILE_SIZE: TileSize = 512;
@ -217,6 +217,10 @@ where
.expect("Didn't find a cached resource with that ID!")
}
pub fn try_get(&self, key: &K) -> Option<&V> {
self.resources.get(key)
}
pub fn insert(&mut self, key: K, value: V) {
self.resources.insert(key, value);
}
@ -772,6 +776,18 @@ impl ResourceCache {
pub fn delete_image_template(&mut self, image_key: ImageKey) {
let value = self.resources.image_templates.remove(image_key);
match self.cached_images.try_get(&image_key) {
Some(&ImageResult::UntiledAuto(ref entry)) => {
self.texture_cache.mark_unused(&entry.texture_cache_handle);
}
Some(&ImageResult::Multi(ref entries)) => {
for (_, entry) in &entries.resources {
self.texture_cache.mark_unused(&entry.texture_cache_handle);
}
}
_ => {}
}
self.cached_images.remove(&image_key);
match value {
@ -1009,6 +1025,9 @@ impl ResourceCache {
format: template.descriptor.format,
};
// TODO: We only track dirty rects for non-tiled blobs but we
// should also do it with tiled ones unless we settle for a small
// tile size.
blob_request_params.push(
BlobImageParams {
request: BlobImageRequest {
@ -1021,14 +1040,20 @@ impl ResourceCache {
);
});
} else {
// TODO: to support partial rendering of non-tiled blobs we
// need to know that the current version of the blob is uploaded
// to the texture cache and get the guarantee that it will not
// get evicted by the time the updated blob is rasterized and
// uploaded.
// Alternatively we could make it the responsibility of the blob
// renderer to always output the full image. This could be based
// a similar copy-on-write mechanism as gecko tiling.
let needs_upload = match self.cached_images.try_get(&key) {
Some(&ImageResult::UntiledAuto(ref entry)) => {
self.texture_cache.needs_upload(&entry.texture_cache_handle)
}
_ => true,
};
let dirty_rect = if needs_upload {
// The texture cache entry has been evicted, treat it as all dirty.
None
} else {
template.dirty_rect
};
blob_request_params.push(
BlobImageParams {
request: BlobImageRequest {
@ -1040,7 +1065,7 @@ impl ResourceCache {
size: template.descriptor.size,
format: template.descriptor.format,
},
dirty_rect: None,
dirty_rect,
}
);
}
@ -1353,6 +1378,7 @@ impl ResourceCache {
let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
debug_assert!(image_template.data.uses_texture_cache());
let mut blob_rasterized_rect = None;
let image_data = match image_template.data {
ImageData::Raw(..) | ImageData::External(..) => {
// Safe to clone here since the Raw image data is an
@ -1369,6 +1395,8 @@ impl ResourceCache {
// TODO: we may want to not panic and show a placeholder instead.
blob_rasterized_rect = Some(result.rasterized_rect);
ImageData::Raw(Arc::clone(&result.data))
}
None => {
@ -1384,6 +1412,14 @@ impl ResourceCache {
ImageResult::Multi(ref mut entries) => entries.get_mut(&request.into()),
ImageResult::Err(_) => panic!("Update requested for invalid entry")
};
match (blob_rasterized_rect, entry.dirty_rect) {
(Some(rasterized), Some(dirty)) => {
debug_assert!(request.tile.is_some() || rasterized.contains_rect(&dirty));
}
_ => {}
}
let mut descriptor = image_template.descriptor.clone();
let local_dirty_rect;
@ -1446,6 +1482,12 @@ impl ResourceCache {
}
};
let eviction = if image_template.data.is_blob() {
Eviction::Manual
} else {
Eviction::Auto
};
//Note: at this point, the dirty rectangle is local to the descriptor space
self.texture_cache.update(
&mut entry.texture_cache_handle,
@ -1457,6 +1499,7 @@ impl ResourceCache {
gpu_cache,
None,
UvRectKind::Rect,
eviction,
);
}
}
@ -1482,6 +1525,9 @@ impl ResourceCache {
if what.contains(ClearCache::TEXTURE_CACHE) {
self.texture_cache.clear();
}
if what.contains(ClearCache::RASTERIZED_BLOBS) {
self.rasterized_blob_images.clear();
}
}
pub fn clear_namespace(&mut self, namespace: IdNamespace) {
@ -1710,7 +1756,7 @@ impl ResourceCache {
let (_, result) = rasterizer.rasterize(blob_request_params).pop().unwrap();
let result = result.expect("Blob rasterization failed");
assert_eq!(result.size, desc.size);
assert_eq!(result.rasterized_rect.size, desc.size);
assert_eq!(result.data.len(), desc.compute_total_size() as usize);
num_blobs += 1;

View File

@ -93,25 +93,27 @@ pub enum CacheEntryMarker {}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct CacheEntry {
// Size the requested item, in device pixels.
/// Size the requested item, in device pixels.
size: DeviceUintSize,
// Details specific to standalone or shared items.
/// Details specific to standalone or shared items.
kind: EntryKind,
// Arbitrary user data associated with this item.
/// Arbitrary user data associated with this item.
user_data: [f32; 3],
// The last frame this item was requested for rendering.
/// The last frame this item was requested for rendering.
last_access: FrameId,
// Handle to the resource rect in the GPU cache.
/// Handle to the resource rect in the GPU cache.
uv_rect_handle: GpuCacheHandle,
// Image format of the item.
/// Image format of the item.
format: ImageFormat,
filter: TextureFilter,
// The actual device texture ID this is part of.
/// The actual device texture ID this is part of.
texture_id: CacheTextureId,
// Optional notice when the entry is evicted from the cache.
/// Optional notice when the entry is evicted from the cache.
eviction_notice: Option<EvictionNotice>,
// The type of UV rect this entry specifies.
/// The type of UV rect this entry specifies.
uv_rect_kind: UvRectKind,
/// If set to `Auto` the cache entry may be evicted if unused for a number of frames.
eviction: Eviction,
}
impl CacheEntry {
@ -136,6 +138,7 @@ impl CacheEntry {
uv_rect_handle: GpuCacheHandle::new(),
eviction_notice: None,
uv_rect_kind,
eviction: Eviction::Auto,
}
}
@ -192,6 +195,14 @@ impl TextureCacheHandle {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum Eviction {
Auto,
Manual,
}
// An eviction notice is a shared condition useful for detecting
// when a TextureCacheHandle gets evicted from the TextureCache.
// It is optionally installed to the TextureCache when an update()
@ -410,6 +421,7 @@ impl TextureCache {
gpu_cache: &mut GpuCache,
eviction_notice: Option<&EvictionNotice>,
uv_rect_kind: UvRectKind,
eviction: Eviction,
) {
// Determine if we need to allocate texture cache memory
// for this item. We need to reallocate if any of the following
@ -463,6 +475,8 @@ impl TextureCache {
// Upload the resource rect and texture array layer.
entry.update_gpu_cache(gpu_cache);
entry.eviction = eviction;
// Create an update command, which the render thread processes
// to upload the new image data into the correct location
// in GPU memory.
@ -581,6 +595,17 @@ impl TextureCache {
DeviceUintRect::new(origin, entry.size))
}
pub fn mark_unused(&mut self, handle: &TextureCacheHandle) {
if let Some(ref handle) = handle.entry {
if let Some(entry) = self.entries.get_opt_mut(handle) {
// Set a very low last accessed frame to make it very likely that this entry
// will get cleaned up next time we try to expire entries.
entry.last_access = FrameId(0);
entry.eviction = Eviction::Auto;
}
}
}
// Expire old standalone textures.
fn expire_old_standalone_entries(&mut self) {
let mut eviction_candidates = Vec::new();
@ -590,7 +615,7 @@ impl TextureCache {
// anything not used this frame).
for handle in self.standalone_entry_handles.drain(..) {
let entry = self.entries.get(&handle);
if entry.last_access == self.frame_id {
if entry.eviction == Eviction::Manual || entry.last_access == self.frame_id {
retained_entries.push(handle);
} else {
eviction_candidates.push(handle);
@ -1205,6 +1230,7 @@ impl TextureArray {
texture_id: self.texture_id.unwrap(),
eviction_notice: None,
uv_rect_kind,
eviction: Eviction::Auto,
}
})
}

View File

@ -4,12 +4,12 @@
use api::{BorderRadius, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
use api::{DevicePoint, DeviceRect, DeviceSize, LayoutPixel, LayoutPoint, LayoutRect, LayoutSize};
use api::{WorldPixel, WorldPoint, WorldRect};
use api::{WorldPixel, WorldRect};
use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D};
use euclid::{TypedTransform2D, TypedTransform3D, TypedVector2D, TypedVector3D};
use euclid::{TypedTransform2D, TypedTransform3D, TypedVector2D};
use euclid::{HomogeneousVector};
use num_traits::Zero;
use plane_split::{Clipper, Plane, Polygon};
use plane_split::{Clipper, Polygon};
use std::{i32, f32};
use std::borrow::Cow;
@ -175,16 +175,13 @@ pub fn calculate_screen_bounding_rect(
device_pixel_scale: DevicePixelScale,
screen_bounds: Option<&DeviceIntRect>,
) -> Option<DeviceIntRect> {
debug!("rect {:?}", rect);
debug!("transform {:?}", transform);
debug!("screen_bounds: {:?}", screen_bounds);
debug!("calculate_screen_bounding_rect for {:?}", rect);
let homogens = [
transform.transform_point2d_homogeneous(&rect.origin),
transform.transform_point2d_homogeneous(&rect.top_right()),
transform.transform_point2d_homogeneous(&rect.bottom_left()),
transform.transform_point2d_homogeneous(&rect.bottom_right()),
];
debug!("homogeneous points {:?}", homogens);
let max_rect = match screen_bounds {
Some(bounds) => bounds.to_f32(),
None => DeviceRect::max_rect(),
@ -193,60 +190,17 @@ pub fn calculate_screen_bounding_rect(
// Note: we only do the full frustum collision when the polygon approaches the camera plane.
// Otherwise, it will be clamped to the screen bounds anyway.
let world_rect = if homogens.iter().any(|h| h.w <= 0.0) {
debug!("transform {:?}", transform);
debug!("screen_bounds: {:?}", screen_bounds);
debug!("homogeneous points {:?}", homogens);
let mut clipper = Clipper::new();
// using inverse-transpose of the inversed transform
let t = transform.to_transform();
// camera plane
{
let normal = TypedVector3D::new(t.m14, t.m24, t.m34);
let kf = 1.0 / normal.length();
clipper.add(Plane {
normal: normal * kf,
offset: t.m44 * kf,
});
}
// The equations for clip planes come from the following one:
// (v * M).x < right
// (v, Mx) < right
// (v, Mx) - right = 0;
// left/right planes
if let Some(bounds) = screen_bounds {
let normal = TypedVector3D::new(t.m11, t.m21, t.m31);
let kf = 1.0 / normal.length();
clipper.add(Plane {
normal: normal * kf,
offset: t.m41 * kf - (bounds.origin.x) as f32 / device_pixel_scale.0,
});
clipper.add(Plane {
normal: normal * -kf,
offset: t.m41 * -kf + (bounds.origin.x + bounds.size.width) as f32 / device_pixel_scale.0,
});
}
// top/bottom planes
if let Some(bounds) = screen_bounds {
let normal = TypedVector3D::new(t.m12, t.m22, t.m32);
let kf = 1.0 / normal.length();
clipper.add(Plane {
normal: normal * kf,
offset: t.m42 * kf - (bounds.origin.y) as f32 / device_pixel_scale.0,
});
clipper.add(Plane {
normal: normal * -kf,
offset: t.m42 * -kf + (bounds.origin.y + bounds.size.height) as f32 / device_pixel_scale.0,
});
}
let polygon = Polygon::from_points(
[
rect.origin.to_3d(),
rect.top_right().to_3d(),
rect.bottom_left().to_3d(),
rect.bottom_right().to_3d(),
],
1,
clipper.add_frustum(
&transform.to_transform(),
screen_bounds.map(|b| b.to_f32() / device_pixel_scale),
);
let polygon = Polygon::from_rect(*rect, 1);
debug!("crossing detected for poly {:?}", polygon);
let results = clipper.clip(polygon);
debug!("clip results: {:?}", results);
@ -260,14 +214,10 @@ pub fn calculate_screen_bounding_rect(
// filter out parts behind the view plane
.flat_map(|poly| &poly.points)
.map(|p| {
debug!("\tpoint {:?} -> {:?} -> {:?}", p,
transform.transform_point2d_homogeneous(&p.to_2d()),
transform.transform_point2d(&p.to_2d())
);
//TODO: change to `expect` when the near splitting code is ready
transform
.transform_point2d(&p.to_2d())
.unwrap_or(WorldPoint::zero())
let mut homo = transform.transform_point2d_homogeneous(&p.to_2d());
homo.w = homo.w.max(0.00000001); // avoid infinite values
debug!("\tpoint {:?} -> {:?} -> {:?}", p, homo, homo.to_point2d());
homo.to_point2d().unwrap()
})
)
} else {
@ -280,56 +230,18 @@ pub fn calculate_screen_bounding_rect(
])
};
debug!("world rect {:?}", world_rect);
(world_rect * device_pixel_scale)
.round_out()
.intersection(&max_rect)
.map(|r| r.to_i32())
}
pub fn _subtract_rect<U>(
rect: &TypedRect<f32, U>,
other: &TypedRect<f32, U>,
results: &mut Vec<TypedRect<f32, U>>,
) {
results.clear();
let int = rect.intersection(other);
match int {
Some(int) => {
let rx0 = rect.origin.x;
let ry0 = rect.origin.y;
let rx1 = rx0 + rect.size.width;
let ry1 = ry0 + rect.size.height;
let ox0 = int.origin.x;
let oy0 = int.origin.y;
let ox1 = ox0 + int.size.width;
let oy1 = oy0 + int.size.height;
let r = TypedRect::from_untyped(&rect_from_points_f(rx0, ry0, ox0, ry1));
if r.size.width > 0.0 && r.size.height > 0.0 {
results.push(r);
}
let r = TypedRect::from_untyped(&rect_from_points_f(ox0, ry0, ox1, oy0));
if r.size.width > 0.0 && r.size.height > 0.0 {
results.push(r);
}
let r = TypedRect::from_untyped(&rect_from_points_f(ox0, oy1, ox1, ry1));
if r.size.width > 0.0 && r.size.height > 0.0 {
results.push(r);
}
let r = TypedRect::from_untyped(&rect_from_points_f(ox1, ry0, rx1, ry1));
if r.size.width > 0.0 && r.size.height > 0.0 {
results.push(r);
}
}
None => {
results.push(*rect);
}
let result = (world_rect * device_pixel_scale)
.round_out()
.intersection(&max_rect)
.map(|r| r.to_i32());
if homogens.iter().any(|h| h.w <= 0.0) {
debug!("world rect {:?}", world_rect);
debug!("result {:?}", result);
}
result
}
#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]

View File

@ -535,11 +535,12 @@ bitflags!{
/// Mask for clearing caches in debug commands.
#[derive(Deserialize, Serialize)]
pub struct ClearCache: u8 {
const IMAGES = 0x1;
const GLYPHS = 0x2;
const GLYPH_DIMENSIONS = 0x4;
const RENDER_TASKS = 0x8;
const TEXTURE_CACHE = 0x16;
const IMAGES = 0b1;
const GLYPHS = 0b01;
const GLYPH_DIMENSIONS = 0b001;
const RENDER_TASKS = 0b0001;
const TEXTURE_CACHE = 0b00001;
const RASTERIZED_BLOBS = 0b000001;
}
}

View File

@ -245,7 +245,7 @@ pub struct BlobImageDescriptor {
}
pub struct RasterizedBlobImage {
pub size: DeviceUintSize,
pub rasterized_rect: DeviceUintRect,
pub data: Arc<Vec<u8>>,
}

View File

@ -1 +1 @@
7a1b919e37d6cd0155077aa90f98cfcdf9fa5bae
c939a61b83bcc9dc10742977704793e9a85b3858

View File

@ -103,7 +103,7 @@ fn render_blob(
Ok(RasterizedBlobImage {
data: Arc::new(texels),
size: descriptor.size,
rasterized_rect: dirty_rect,
})
}