mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-04 07:40:42 +00:00
Bug 1480433 - Update webrender to commit c939a61b83bcc9dc10742977704793e9a85b3858. r=jrmuizel
MozReview-Commit-ID: 8msYpcE1tCx
This commit is contained in:
parent
1ca6fd6782
commit
56cfeb9660
@ -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" }
|
||||
|
@ -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)]
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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))]
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,7 +245,7 @@ pub struct BlobImageDescriptor {
|
||||
}
|
||||
|
||||
pub struct RasterizedBlobImage {
|
||||
pub size: DeviceUintSize,
|
||||
pub rasterized_rect: DeviceUintRect,
|
||||
pub data: Arc<Vec<u8>>,
|
||||
}
|
||||
|
||||
|
@ -1 +1 @@
|
||||
7a1b919e37d6cd0155077aa90f98cfcdf9fa5bae
|
||||
c939a61b83bcc9dc10742977704793e9a85b3858
|
||||
|
@ -103,7 +103,7 @@ fn render_blob(
|
||||
|
||||
Ok(RasterizedBlobImage {
|
||||
data: Arc::new(texels),
|
||||
size: descriptor.size,
|
||||
rasterized_rect: dirty_rect,
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user