Bug 1457241 - Update webrender to commit 4b65822a2f7e1fed246a492f9fe193ede2f37d74. r=jrmuizel

MozReview-Commit-ID: EIE8tuyH8Ai

--HG--
extra : rebase_source : 8886acf54a54822ee1de326a6ad082edd069dea1
This commit is contained in:
Kartikaya Gupta 2018-04-30 10:12:52 -04:00
Родитель 2eb85c90dd
Коммит 4e2f121981
21 изменённых файлов: 573 добавлений и 343 удалений

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

@ -40,24 +40,6 @@ ImageBrushData fetch_image_data(int address) {
return data;
}
struct ImageBrushExtraData {
RectWithSize rendered_task_rect;
vec2 offset;
};
ImageBrushExtraData fetch_image_extra_data(int address) {
vec4[2] raw_data = fetch_from_resource_cache_2(address);
RectWithSize rendered_task_rect = RectWithSize(
raw_data[0].xy,
raw_data[0].zw
);
ImageBrushExtraData data = ImageBrushExtraData(
rendered_task_rect,
raw_data[1].xy
);
return data;
}
#ifdef WR_FEATURE_ALPHA_PASS
vec2 transform_point_snapped(
vec2 local_pos,
@ -105,7 +87,7 @@ void brush_vs(
max_uv - vec2(0.5)
) / texture_size.xyxy;
vec2 f;
vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
#ifdef WR_FEATURE_ALPHA_PASS
int color_mode = user_data.y >> 16;
@ -121,41 +103,18 @@ void brush_vs(
// image.
switch (raster_space) {
case RASTER_SCREEN: {
ImageBrushExtraData extra_data = fetch_image_extra_data(user_data.z);
vec2 snapped_device_pos;
// For drop-shadows, we need to apply a local offset
// in order to generate the correct screen-space UV.
// For other effects, we can use the 1:1 mapping of
// the vertex device position for the UV generation.
switch (color_mode) {
case COLOR_MODE_ALPHA: {
vec2 local_pos = vi.local_pos - extra_data.offset;
snapped_device_pos = transform_point_snapped(
local_pos,
local_rect,
transform
);
break;
}
default:
snapped_device_pos = vi.snapped_device_pos;
break;
}
f = (snapped_device_pos - extra_data.rendered_task_rect.p0) / extra_data.rendered_task_rect.size;
// Since the screen space UVs specify an arbitrary quad, do
// a bilinear interpolation to get the correct UV for this
// local position.
ImageResourceExtra extra_data = fetch_image_resource_extra(user_data.x);
vec2 x = mix(extra_data.st_tl, extra_data.st_tr, f.x);
vec2 y = mix(extra_data.st_bl, extra_data.st_br, f.x);
f = mix(x, y, f.y);
break;
}
case RASTER_LOCAL:
default: {
f = (vi.local_pos - local_rect.p0) / local_rect.size;
default:
break;
}
}
#else
f = (vi.local_pos - local_rect.p0) / local_rect.size;
#endif
// Offset and scale vUv here to avoid doing it in the fragment shader.

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

@ -58,8 +58,6 @@ void brush_vs(
vRepeatedSize = local_rect.size / tile_repeat.xy;
vRepeatedSize.y *= ratio_xy;
vPos;
vGradientAddress = user_data.x;
// Whether to repeat the gradient instead of clamping.

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

@ -15,6 +15,7 @@ flat varying vec4 vPoint_Tangent0;
flat varying vec4 vPoint_Tangent1;
flat varying vec3 vDotParams;
flat varying vec2 vAlphaMask;
flat varying vec4 vTaskRect;
#ifdef WR_VERTEX_SHADER
// Matches BorderCorner enum in border.rs
@ -145,9 +146,13 @@ void main(void) {
vec2 device_pos = world_pos.xy * uDevicePixelRatio;
// Position vertex within the render task area.
vec2 final_pos = device_pos -
area.screen_origin +
area.common_data.task_rect.p0;
vec2 task_rect_origin = area.common_data.task_rect.p0;
vec2 final_pos = device_pos - area.screen_origin + task_rect_origin;
// We pass the task rectangle to the fragment shader so that we can do one last clip
// in order to ensure that we don't draw outside the task rectangle.
vTaskRect.xy = task_rect_origin;
vTaskRect.zw = task_rect_origin + area.common_data.task_rect.size;
// Calculate the local space position for this vertex.
vec4 node_pos = get_node_pos(world_pos.xy, scroll_node);
@ -190,6 +195,9 @@ void main(void) {
// Completely mask out clip if zero'ing out the rect.
d = d * vAlphaMask.y;
// Make sure that we don't draw outside the task rectangle.
d = d * point_inside_rect(gl_FragCoord.xy, vTaskRect.xy, vTaskRect.zw);
oFragColor = vec4(d, 0.0, 0.0, 1.0);
}
#endif

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

@ -4,6 +4,8 @@
uniform HIGHP_SAMPLER_FLOAT sampler2D sResourceCache;
#define VECS_PER_IMAGE_RESOURCE 2
// TODO(gw): This is here temporarily while we have
// both GPU store and cache. When the GPU
// store code is removed, we can change the
@ -113,4 +115,23 @@ ImageResource fetch_image_resource_direct(ivec2 address) {
return ImageResource(uv_rect, data[1].x, data[1].yzw);
}
// Fetch optional extra data for a texture cache resource. This can contain
// a polygon defining a UV rect within the texture cache resource.
struct ImageResourceExtra {
vec2 st_tl;
vec2 st_tr;
vec2 st_bl;
vec2 st_br;
};
ImageResourceExtra fetch_image_resource_extra(int address) {
vec4 data[2] = fetch_from_resource_cache_2(address + VECS_PER_IMAGE_RESOURCE);
return ImageResourceExtra(
data[0].xy,
data[0].zw,
data[1].xy,
data[1].zw
);
}
#endif //WR_VERTEX_SHADER

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

@ -18,7 +18,6 @@ use gpu_types::{PrimitiveInstance, RasterizationSpace, SimplePrimitiveInstance,
use gpu_types::ZBufferIdGenerator;
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
use picture::{IMAGE_BRUSH_BLOCKS, IMAGE_BRUSH_EXTRA_BLOCKS};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{CachedGradient, ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PictureIndex, PrimitiveRun};
@ -700,7 +699,7 @@ impl AlphaBatchBuilder {
uv_rect_address.as_int(),
(ShaderColorMode::ColorBitmap as i32) << 16 |
RasterizationSpace::Screen as i32,
picture.extra_gpu_data_handle.as_int(gpu_cache),
0,
],
};
batch.push(PrimitiveInstance::from(instance));
@ -750,11 +749,7 @@ impl AlphaBatchBuilder {
.as_int();
// Get the GPU cache address of the extra data handle.
let extra_data_address = gpu_cache.get_address(&picture.extra_gpu_data_handle);
let shadow_prim_address = extra_data_address
.offset(IMAGE_BRUSH_EXTRA_BLOCKS);
let shadow_data_address = extra_data_address
.offset(IMAGE_BRUSH_EXTRA_BLOCKS + IMAGE_BRUSH_BLOCKS);
let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_data_handle);
let shadow_instance = BrushInstance {
picture_address: task_address,
@ -770,7 +765,7 @@ impl AlphaBatchBuilder {
shadow_uv_rect_address,
(ShaderColorMode::Alpha as i32) << 16 |
RasterizationSpace::Screen as i32,
shadow_data_address.as_int(),
0,
],
};
@ -780,7 +775,7 @@ impl AlphaBatchBuilder {
content_uv_rect_address,
(ShaderColorMode::ColorBitmap as i32) << 16 |
RasterizationSpace::Screen as i32,
extra_data_address.as_int(),
0,
],
..shadow_instance
};
@ -953,7 +948,7 @@ impl AlphaBatchBuilder {
uv_rect_address,
(ShaderColorMode::ColorBitmap as i32) << 16 |
RasterizationSpace::Screen as i32,
picture.extra_gpu_data_handle.as_int(gpu_cache),
0,
],
};
batch.push(PrimitiveInstance::from(instance));

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

@ -101,6 +101,9 @@ pub struct ClipScrollNode {
/// World transform for content transformed by this node.
pub world_content_transform: LayoutToWorldFastTransform,
/// The current transform kind of world_content_transform.
pub transform_kind: TransformedRectKind,
/// Pipeline that this layer belongs to
pub pipeline_id: PipelineId,
@ -142,6 +145,7 @@ impl ClipScrollNode {
local_viewport_rect: *rect,
world_viewport_transform: LayoutToWorldFastTransform::identity(),
world_content_transform: LayoutToWorldFastTransform::identity(),
transform_kind: TransformedRectKind::AxisAligned,
parent: parent_index,
children: Vec::new(),
pipeline_id,
@ -285,15 +289,10 @@ impl ClipScrollNode {
}
};
let transform_kind = if self.world_content_transform.preserves_2d_axis_alignment() {
TransformedRectKind::AxisAligned
} else {
TransformedRectKind::Complex
};
let data = ClipScrollNodeData {
transform: self.world_content_transform.into(),
inv_transform,
transform_kind: transform_kind as u32 as f32,
transform_kind: self.transform_kind as u32 as f32,
padding: [0.0; 3],
};
@ -321,6 +320,12 @@ impl ClipScrollNode {
self.update_transform(state, next_coordinate_system_id, scene_properties);
self.transform_kind = if self.world_content_transform.preserves_2d_axis_alignment() {
TransformedRectKind::AxisAligned
} else {
TransformedRectKind::Complex
};
// If this node is a reference frame, we check if it has a non-invertible matrix.
// For non-reference-frames we assume that they will produce only additional
// translations which should be invertible.

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

@ -1843,6 +1843,7 @@ impl<'a> DisplayListFlattener<'a> {
stops_count: usize,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
stretch_size: LayoutSize,
) {
// Try to ensure that if the gradient is specified in reverse, then so long as the stops
// are also supplied in reverse that the rendered result will be equivalent. To do this,
@ -1871,6 +1872,7 @@ impl<'a> DisplayListFlattener<'a> {
start_point: sp,
end_point: ep,
gradient_index,
stretch_size,
},
None,
);
@ -1889,43 +1891,49 @@ impl<'a> DisplayListFlattener<'a> {
stops: ItemRange<GradientStop>,
stops_count: usize,
extend_mode: ExtendMode,
tile_size: LayoutSize,
stretch_size: LayoutSize,
tile_spacing: LayoutSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());
let prim_infos = info.decompose(
tile_size,
tile_spacing,
64 * 64,
);
if prim_infos.is_empty() {
self.add_gradient_impl(
clip_and_scroll,
info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
if tile_spacing != LayoutSize::zero() {
let prim_infos = info.decompose(
stretch_size,
tile_spacing,
64 * 64,
);
} else {
for prim_info in prim_infos {
self.add_gradient_impl(
clip_and_scroll,
&prim_info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
);
if !prim_infos.is_empty() {
for prim_info in prim_infos {
self.add_gradient_impl(
clip_and_scroll,
&prim_info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
prim_info.rect.size,
);
}
return;
}
}
self.add_gradient_impl(
clip_and_scroll,
info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
stretch_size,
);
}
fn add_radial_gradient_impl(
@ -1939,6 +1947,7 @@ impl<'a> DisplayListFlattener<'a> {
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
stretch_size: LayoutSize,
) {
let prim = BrushPrimitive::new(
BrushKind::RadialGradient {
@ -1949,6 +1958,7 @@ impl<'a> DisplayListFlattener<'a> {
end_radius,
ratio_xy,
gradient_index,
stretch_size,
},
None,
);
@ -1971,45 +1981,51 @@ impl<'a> DisplayListFlattener<'a> {
ratio_xy: f32,
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
tile_size: LayoutSize,
stretch_size: LayoutSize,
tile_spacing: LayoutSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());
let prim_infos = info.decompose(
tile_size,
tile_spacing,
64 * 64,
);
if prim_infos.is_empty() {
self.add_radial_gradient_impl(
clip_and_scroll,
info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
if tile_spacing != LayoutSize::zero() {
let prim_infos = info.decompose(
stretch_size,
tile_spacing,
64 * 64,
);
} else {
for prim_info in prim_infos {
self.add_radial_gradient_impl(
clip_and_scroll,
&prim_info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
);
if !prim_infos.is_empty() {
for prim_info in prim_infos {
self.add_radial_gradient_impl(
clip_and_scroll,
&prim_info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
stretch_size,
);
}
return;
}
}
self.add_radial_gradient_impl(
clip_and_scroll,
info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
stretch_size,
);
}
pub fn add_text(
@ -2137,7 +2153,6 @@ impl<'a> DisplayListFlattener<'a> {
// See if conditions are met to run through the new
// image brush shader, which supports segments.
if tile_spacing == LayoutSize::zero() &&
stretch_size == info.rect.size &&
tile_offset.is_none() {
let prim = BrushPrimitive::new(
BrushKind::Image {

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

@ -10,7 +10,7 @@ use clip_scroll_node::{ClipScrollNode};
use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree};
use display_list_flattener::{DisplayListFlattener};
use gpu_cache::GpuCache;
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData};
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, UvRectKind};
use hit_test::{HitTester, HitTestingRun};
use internal_types::{FastHashMap};
use picture::PictureSurface;
@ -233,6 +233,7 @@ impl FrameBuilder {
PrimitiveIndex(0),
DeviceIntPoint::zero(),
pic_state.tasks,
UvRectKind::Rect,
);
let render_task_id = frame_state.render_tasks.add(root_render_task);

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

@ -21,6 +21,7 @@ use device::TextureFilter;
use euclid::{TypedPoint2D, TypedSize2D, TypedVector2D};
use glyph_cache::{CachedGlyphInfo, GlyphCache, GlyphCacheEntry};
use gpu_cache::GpuCache;
use gpu_types::UvRectKind;
use internal_types::ResourceCacheError;
#[cfg(feature = "pathfinder")]
use pathfinder_font_renderer;
@ -800,6 +801,7 @@ impl GlyphRasterizer {
None,
gpu_cache,
Some(glyph_key_cache.eviction_notice()),
UvRectKind::Rect,
);
GlyphCacheEntry::Cached(CachedGlyphInfo {
texture_cache_handle,

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

@ -151,13 +151,6 @@ impl GpuCacheAddress {
v: u16::MAX,
}
}
pub fn offset(&self, offset: usize) -> Self {
GpuCacheAddress {
u: self.u + offset as u16,
v: self.v
}
}
}
impl Add<usize> for GpuCacheAddress {

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

@ -277,15 +277,38 @@ impl ClipScrollNodeData {
#[repr(C)]
pub struct ClipChainRectIndex(pub usize);
// Texture cache resources can be either a simple rect, or define
// a polygon within a rect by specifying a UV coordinate for each
// corner. This is useful for rendering screen-space rasterized
// off-screen surfaces.
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum UvRectKind {
// The 2d bounds of the texture cache entry define the
// valid UV space for this texture cache entry.
Rect,
// The four vertices below define a quad within
// the texture cache entry rect. The shader can
// use a bilerp() to correctly interpolate a
// UV coord in the vertex shader.
Quad {
top_left: DevicePoint,
top_right: DevicePoint,
bottom_left: DevicePoint,
bottom_right: DevicePoint,
},
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct ImageSource {
pub p0: DevicePoint,
pub p1: DevicePoint,
pub texture_layer: f32,
pub user_data: [f32; 3],
pub uv_rect_kind: UvRectKind,
}
impl ImageSource {
@ -302,5 +325,22 @@ impl ImageSource {
self.user_data[1],
self.user_data[2],
]);
// If this is a polygon uv kind, then upload the four vertices.
if let UvRectKind::Quad { top_left, top_right, bottom_left, bottom_right } = self.uv_rect_kind {
request.push([
top_left.x,
top_left.y,
top_right.x,
top_right.y,
]);
request.push([
bottom_left.x,
bottom_left.y,
bottom_right.x,
bottom_right.y,
]);
}
}
}

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

@ -2,13 +2,15 @@
* 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::{FilterOp, MixBlendMode, PipelineId, PremultipliedColorF};
use api::{DeviceIntRect, DeviceIntSize, LayoutRect};
use api::{PictureIntPoint, PictureIntRect, PictureIntSize};
use api::{DeviceRect, FilterOp, MixBlendMode, PipelineId, PremultipliedColorF};
use api::{DeviceIntRect, DeviceIntSize, DevicePoint, LayoutPoint, LayoutRect};
use api::{DevicePixelScale, PictureIntPoint, PictureIntRect, PictureIntSize};
use box_shadow::{BLUR_SAMPLE_SCALE};
use clip_scroll_node::ClipScrollNode;
use clip_scroll_tree::ClipScrollNodeIndex;
use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState};
use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState, PrimitiveRunContext};
use gpu_cache::{GpuCacheHandle};
use gpu_types::UvRectKind;
use prim_store::{PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
use prim_store::{PrimitiveMetadata, ScrollNodeAndClipChain};
use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle};
@ -16,6 +18,7 @@ use render_task::{RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId, Rend
use scene::{FilterOpHelpers, SceneProperties};
use std::mem;
use tiling::RenderTargetKind;
use util::TransformedRectKind;
/*
A picture represents a dynamically rendered image. It consists of:
@ -27,9 +30,6 @@ use tiling::RenderTargetKind;
this picture (e.g. in screen space or local space).
*/
pub const IMAGE_BRUSH_EXTRA_BLOCKS: usize = 2;
pub const IMAGE_BRUSH_BLOCKS: usize = 6;
/// Specifies how this Picture should be composited
/// onto the target it belongs to.
#[derive(Debug, Copy, Clone, PartialEq)]
@ -127,10 +127,6 @@ pub struct PicturePrimitive {
// in this picture.
pub apply_local_clip_rect: bool,
// The current screen-space rect of the rendered
// portion of this picture.
task_rect: DeviceIntRect,
// If a mix-blend-mode, contains the render task for
// the readback of the framebuffer that we use to sample
// from in the mix-blend-mode shader.
@ -199,7 +195,6 @@ impl PicturePrimitive {
extra_gpu_data_handle: GpuCacheHandle::new(),
apply_local_clip_rect,
pipeline_id,
task_rect: DeviceIntRect::zero(),
id,
}
}
@ -281,11 +276,12 @@ impl PicturePrimitive {
&mut self,
prim_index: PrimitiveIndex,
prim_metadata: &mut PrimitiveMetadata,
prim_run_context: &PrimitiveRunContext,
mut pic_state_for_children: PictureState,
pic_state: &mut PictureState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) -> Option<DeviceIntRect> {
) {
let prim_screen_rect = prim_metadata
.screen_rect
.as_ref()
@ -293,10 +289,9 @@ impl PicturePrimitive {
if self.can_draw_directly_to_parent_surface() {
pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
return None;
return;
}
// TODO(gw): Almost all of the Picture types below use extra_gpu_cache_data
// to store the same type of data. The exception is the filter
// with a ColorMatrix, which stores the color matrix here. It's
@ -322,6 +317,13 @@ impl PicturePrimitive {
.intersection(&prim_screen_rect.unclipped)
.unwrap();
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_run_context.scroll_node,
&device_rect,
frame_context.device_pixel_scale,
);
// If we are drawing a blur that has primitives or clips that contain
// a complex coordinate system, don't bother caching them (for now).
// It's likely that they are animating and caching may not help here
@ -334,6 +336,7 @@ impl PicturePrimitive {
prim_index,
device_rect.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let picture_task_id = frame_state.render_tasks.add(picture_task);
@ -388,6 +391,7 @@ impl PicturePrimitive {
prim_index,
device_rect.origin,
child_tasks,
uv_rect_kind,
);
let picture_task_id = render_tasks.add(picture_task);
@ -412,10 +416,8 @@ impl PicturePrimitive {
};
self.surface = Some(surface);
Some(device_rect)
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(_, blur_radius, _))) => {
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
@ -433,11 +435,19 @@ impl PicturePrimitive {
.intersection(&prim_screen_rect.unclipped)
.unwrap();
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_run_context.scroll_node,
&device_rect,
frame_context.device_pixel_scale,
);
let mut picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, Some(device_rect.size)),
prim_index,
device_rect.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
picture_task.mark_for_saving();
@ -457,112 +467,7 @@ impl PicturePrimitive {
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
Some(device_rect)
}
Some(PictureCompositeMode::MixBlend(..)) => {
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, Some(prim_screen_rect.clipped.size)),
prim_index,
prim_screen_rect.clipped.origin,
pic_state_for_children.tasks,
);
let readback_task_id = frame_state.render_tasks.add(
RenderTask::new_readback(prim_screen_rect.clipped)
);
self.secondary_render_task_id = Some(readback_task_id);
pic_state.tasks.push(readback_task_id);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
Some(prim_screen_rect.clipped)
}
Some(PictureCompositeMode::Filter(filter)) => {
let device_rect = match filter {
FilterOp::ColorMatrix(m) => {
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
for i in 0..5 {
request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
}
}
None
}
_ => Some(prim_screen_rect.clipped),
};
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, Some(prim_screen_rect.clipped.size)),
prim_index,
prim_screen_rect.clipped.origin,
pic_state_for_children.tasks,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
device_rect
}
Some(PictureCompositeMode::Blit) | None => {
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, Some(prim_screen_rect.clipped.size)),
prim_index,
prim_screen_rect.clipped.origin,
pic_state_for_children.tasks,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
Some(prim_screen_rect.clipped)
}
}
}
pub fn prepare_for_render(
&mut self,
prim_index: PrimitiveIndex,
prim_metadata: &mut PrimitiveMetadata,
pic_state_for_children: PictureState,
pic_state: &mut PictureState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) {
let device_rect = self.prepare_for_render_inner(
prim_index,
prim_metadata,
pic_state_for_children,
pic_state,
frame_context,
frame_state,
);
// If this picture type uses the common / general GPU data
// format, then write it now.
if let Some(device_rect) = device_rect {
// If scrolling or property animation has resulted in the task
// rect being different than last time, invalidate the GPU
// cache entry for this picture to ensure that the correct
// task rect is provided to the image shader.
if self.task_rect != device_rect {
frame_state.gpu_cache.invalidate(&self.extra_gpu_data_handle);
self.task_rect = device_rect;
}
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
// [GLSL ImageBrushExtraData: task_rect, offset]
request.push(self.task_rect.to_f32());
request.push([0.0; 4]);
// TODO(gw): It would make the shaders a bit simpler if the offset
// was provided as part of the brush::picture instance,
// rather than in the Picture data itself.
if let Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, _, color))) = self.composite_mode {
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
// TODO(gw): This is very hacky code below! It stores an extra
// brush primitive below for the special case of a
// drop-shadow where we need a different local
@ -570,9 +475,6 @@ impl PicturePrimitive {
// we could consider abstracting the code in prim_store.rs
// that writes a brush primitive header.
// NOTE: If any of the layout below changes, the IMAGE_BRUSH_EXTRA_BLOCKS and
// IMAGE_BRUSH_BLOCKS fields above *must* be updated.
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
// local_rect
// clip_rect
@ -592,12 +494,175 @@ impl PicturePrimitive {
// segment rect / repetitions
request.push(shadow_rect);
request.push([1.0, 1.0, 0.0, 0.0]);
// Now write another GLSL ImageBrush struct, for the shadow to reference.
request.push(self.task_rect.to_f32());
request.push([offset.x, offset.y, 0.0, 0.0]);
}
}
Some(PictureCompositeMode::MixBlend(..)) => {
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_run_context.scroll_node,
&prim_screen_rect.clipped,
frame_context.device_pixel_scale,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, Some(prim_screen_rect.clipped.size)),
prim_index,
prim_screen_rect.clipped.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let readback_task_id = frame_state.render_tasks.add(
RenderTask::new_readback(prim_screen_rect.clipped)
);
self.secondary_render_task_id = Some(readback_task_id);
pic_state.tasks.push(readback_task_id);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::Filter(filter)) => {
if let FilterOp::ColorMatrix(m) = filter {
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
for i in 0..5 {
request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
}
}
}
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_run_context.scroll_node,
&prim_screen_rect.clipped,
frame_context.device_pixel_scale,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, Some(prim_screen_rect.clipped.size)),
prim_index,
prim_screen_rect.clipped.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::Blit) | None => {
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_run_context.scroll_node,
&prim_screen_rect.clipped,
frame_context.device_pixel_scale,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, Some(prim_screen_rect.clipped.size)),
prim_index,
prim_screen_rect.clipped.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
}
}
pub fn prepare_for_render(
&mut self,
prim_index: PrimitiveIndex,
prim_metadata: &mut PrimitiveMetadata,
prim_run_context: &PrimitiveRunContext,
pic_state_for_children: PictureState,
pic_state: &mut PictureState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) {
self.prepare_for_render_inner(
prim_index,
prim_metadata,
prim_run_context,
pic_state_for_children,
pic_state,
frame_context,
frame_state,
);
}
}
// Calculate a single screen-space UV for a picture.
fn calculate_screen_uv(
local_pos: &LayoutPoint,
clip_scroll_node: &ClipScrollNode,
rendered_rect: &DeviceRect,
device_pixel_scale: DevicePixelScale,
) -> DevicePoint {
let world_pos = clip_scroll_node
.world_content_transform
.transform_point2d(local_pos);
let mut device_pos = world_pos * device_pixel_scale;
// Apply snapping for axis-aligned scroll nodes, as per prim_shared.glsl.
if clip_scroll_node.transform_kind == TransformedRectKind::AxisAligned {
device_pos.x = (device_pos.x + 0.5).floor();
device_pos.y = (device_pos.y + 0.5).floor();
}
DevicePoint::new(
(device_pos.x - rendered_rect.origin.x) / rendered_rect.size.width,
(device_pos.y - rendered_rect.origin.y) / rendered_rect.size.height,
)
}
// Calculate a UV rect within an image based on the screen space
// vertex positions of a picture.
fn calculate_uv_rect_kind(
local_rect: &LayoutRect,
clip_scroll_node: &ClipScrollNode,
rendered_rect: &DeviceIntRect,
device_pixel_scale: DevicePixelScale,
) -> UvRectKind {
let rendered_rect = rendered_rect.to_f32();
let top_left = calculate_screen_uv(
&local_rect.origin,
clip_scroll_node,
&rendered_rect,
device_pixel_scale,
);
let top_right = calculate_screen_uv(
&local_rect.top_right(),
clip_scroll_node,
&rendered_rect,
device_pixel_scale,
);
let bottom_left = calculate_screen_uv(
&local_rect.bottom_left(),
clip_scroll_node,
&rendered_rect,
device_pixel_scale,
);
let bottom_right = calculate_screen_uv(
&local_rect.bottom_right(),
clip_scroll_node,
&rendered_rect,
device_pixel_scale,
);
UvRectKind::Quad {
top_left,
top_right,
bottom_left,
bottom_right,
}
}

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

@ -131,7 +131,10 @@ impl FontContext {
}
let system_fc = dwrote::FontCollection::system();
let font = system_fc.get_font_from_descriptor(&font_handle).unwrap();
let font = match system_fc.get_font_from_descriptor(&font_handle) {
Some(font) => font,
None => { panic!("missing descriptor {:?}", font_handle) }
};
let face = font.create_font_face();
self.fonts.insert(*font_key, face);
}

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

@ -276,6 +276,7 @@ pub enum BrushKind {
start_radius: f32,
end_radius: f32,
ratio_xy: f32,
stretch_size: LayoutSize,
},
LinearGradient {
gradient_index: CachedGradientIndex,
@ -285,6 +286,7 @@ pub enum BrushKind {
reverse_stops: bool,
start_point: LayoutPoint,
end_point: LayoutPoint,
stretch_size: LayoutSize,
}
}
@ -1641,6 +1643,7 @@ impl PrimitiveStore {
pic.prepare_for_render(
prim_index,
metadata,
prim_run_context,
pic_state_for_children,
pic_state,
frame_context,
@ -1684,15 +1687,32 @@ impl PrimitiveStore {
PrimitiveKind::Brush => {
let brush = &self.cpu_brushes[metadata.cpu_prim_index.0];
brush.write_gpu_blocks(&mut request);
let repeat = match brush.kind {
BrushKind::Image { stretch_size, .. } |
BrushKind::LinearGradient { stretch_size, .. } |
BrushKind::RadialGradient { stretch_size, .. } => {
[
metadata.local_rect.size.width / stretch_size.width,
metadata.local_rect.size.height / stretch_size.height,
0.0,
0.0,
]
}
_ => {
[1.0, 1.0, 0.0, 0.0]
}
};
match brush.segment_desc {
Some(ref segment_desc) => {
for segment in &segment_desc.segments {
// has to match VECS_PER_SEGMENT
request.write_segment(segment.local_rect);
request.write_segment(segment.local_rect, repeat);
}
}
None => {
request.write_segment(metadata.local_rect);
request.write_segment(metadata.local_rect, repeat);
}
}
}
@ -2462,13 +2482,9 @@ impl<'a> GpuDataRequest<'a> {
fn write_segment(
&mut self,
local_rect: LayoutRect,
extra_params: [f32; 4],
) {
self.push(local_rect);
self.push([
1.0,
1.0,
0.0,
0.0
]);
self.push(extra_params);
}
}

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

@ -732,6 +732,9 @@ impl RenderBackend {
);
}
},
SceneBuilderResult::FlushComplete(tx) => {
tx.send(()).ok();
}
SceneBuilderResult::Stopped => {
panic!("We haven't sent a Stop yet, how did we get a Stopped back?");
}
@ -754,6 +757,13 @@ impl RenderBackend {
// inflight messages, otherwise the scene builder might panic.
while let Ok(msg) = self.scene_rx.recv() {
match msg {
SceneBuilderResult::FlushComplete(tx) => {
// If somebody's blocked waiting for a flush, how did they
// trigger the RB thread to shut down? This shouldn't happen
// but handle it gracefully anyway.
debug_assert!(false);
tx.send(()).ok();
}
SceneBuilderResult::Stopped => break,
_ => continue,
}
@ -778,6 +788,9 @@ impl RenderBackend {
ApiMsg::WakeSceneBuilder => {
self.scene_tx.send(SceneBuilderRequest::WakeUp).unwrap();
}
ApiMsg::FlushSceneBuilder(tx) => {
self.scene_tx.send(SceneBuilderRequest::Flush(tx)).unwrap();
}
ApiMsg::UpdateResources(updates) => {
self.resource_cache
.update_resources(updates, &mut profile_counters.resources);

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

@ -14,7 +14,7 @@ use euclid::{TypedPoint2D, TypedVector2D};
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
use glyph_rasterizer::GpuGlyphCacheKey;
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
use gpu_types::{ImageSource, RasterizationSpace};
use gpu_types::{ImageSource, RasterizationSpace, UvRectKind};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
#[cfg(feature = "pathfinder")]
use pathfinder_partitioner::mesh::Mesh;
@ -196,6 +196,7 @@ pub struct PictureTask {
pub prim_index: PrimitiveIndex,
pub content_origin: DeviceIntPoint,
pub uv_rect_handle: GpuCacheHandle,
uv_rect_kind: UvRectKind,
}
#[derive(Debug)]
@ -205,6 +206,7 @@ pub struct BlurTask {
pub blur_std_deviation: f32,
pub target_kind: RenderTargetKind,
pub uv_rect_handle: GpuCacheHandle,
uv_rect_kind: UvRectKind,
}
impl BlurTask {
@ -306,6 +308,7 @@ impl RenderTask {
prim_index: PrimitiveIndex,
content_origin: DeviceIntPoint,
children: Vec<RenderTaskId>,
uv_rect_kind: UvRectKind,
) -> Self {
RenderTask {
children,
@ -314,6 +317,7 @@ impl RenderTask {
prim_index,
content_origin,
uv_rect_handle: GpuCacheHandle::new(),
uv_rect_kind,
}),
clear_mode: ClearMode::Transparent,
saved_index: None,
@ -488,7 +492,10 @@ impl RenderTask {
) -> Self {
// 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();
let (blur_target_size, uv_rect_kind) = {
let src_task = &render_tasks[src_task_id];
(src_task.get_dynamic_size(), src_task.uv_rect_kind())
};
let mut adjusted_blur_target_size = blur_target_size;
let mut downscaling_src_task_id = src_task_id;
let mut scale_factor = 1.0;
@ -515,6 +522,7 @@ impl RenderTask {
blur_std_deviation: adjusted_blur_std_deviation,
target_kind,
uv_rect_handle: GpuCacheHandle::new(),
uv_rect_kind,
}),
clear_mode,
saved_index: None,
@ -529,6 +537,7 @@ impl RenderTask {
blur_std_deviation: adjusted_blur_std_deviation,
target_kind,
uv_rect_handle: GpuCacheHandle::new(),
uv_rect_kind,
}),
clear_mode,
saved_index: None,
@ -575,6 +584,31 @@ impl RenderTask {
}
}
fn uv_rect_kind(&self) -> UvRectKind {
match self.kind {
RenderTaskKind::CacheMask(..) |
RenderTaskKind::Glyph(_) |
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) => {
unreachable!("bug: unexpected render task");
}
RenderTaskKind::Picture(ref task) => {
task.uv_rect_kind
}
RenderTaskKind::VerticalBlur(ref task) |
RenderTaskKind::HorizontalBlur(ref task) => {
task.uv_rect_kind
}
RenderTaskKind::ClipRegion(..) |
RenderTaskKind::Blit(..) => {
UvRectKind::Rect
}
}
}
// Write (up to) 8 floats of data specific to the type
// of render task that is provided to the GPU shaders
// via a vertex texture.
@ -778,13 +812,13 @@ impl RenderTask {
) {
let (target_rect, target_index) = self.get_target_rect();
let cache_handle = match self.kind {
let (cache_handle, uv_rect_kind) = match self.kind {
RenderTaskKind::HorizontalBlur(ref mut info) |
RenderTaskKind::VerticalBlur(ref mut info) => {
&mut info.uv_rect_handle
(&mut info.uv_rect_handle, info.uv_rect_kind)
}
RenderTaskKind::Picture(ref mut info) => {
&mut info.uv_rect_handle
(&mut info.uv_rect_handle, info.uv_rect_kind)
}
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) |
@ -797,11 +831,15 @@ impl RenderTask {
};
if let Some(mut request) = gpu_cache.request(cache_handle) {
let p0 = target_rect.origin.to_f32();
let p1 = target_rect.bottom_right().to_f32();
let image_source = ImageSource {
p0: target_rect.origin.to_f32(),
p1: target_rect.bottom_right().to_f32(),
p0,
p1,
texture_layer: target_index.0 as f32,
user_data: [0.0; 3],
uv_rect_kind,
};
image_source.write_gpu_blocks(&mut request);
}
@ -1012,6 +1050,7 @@ impl RenderTaskCache {
None,
gpu_cache,
None,
render_task.uv_rect_kind(),
);
// Get the allocation details in the texture cache, and store

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

@ -24,6 +24,7 @@ use glyph_cache::GlyphCache;
use glyph_cache::GlyphCacheEntry;
use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphRasterizer, GlyphRequest};
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
use gpu_types::UvRectKind;
use internal_types::{FastHashMap, FastHashSet, SourceTexture, TextureUpdateList};
use profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
use render_backend::FrameId;
@ -1057,6 +1058,7 @@ impl ResourceCache {
dirty_rect,
gpu_cache,
None,
UvRectKind::Rect,
);
image_template.dirty_rect = None;
}

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

@ -25,6 +25,7 @@ pub enum SceneBuilderRequest {
current_epochs: FastHashMap<PipelineId, Epoch>,
},
WakeUp,
Flush(MsgSender<()>),
Stop
}
@ -38,6 +39,7 @@ pub enum SceneBuilderResult {
render: bool,
result_tx: Sender<SceneSwapResult>,
},
FlushComplete(MsgSender<()>),
Stopped,
}
@ -125,6 +127,10 @@ impl SceneBuilder {
fn process_message(&mut self, msg: SceneBuilderRequest) -> bool {
match msg {
SceneBuilderRequest::WakeUp => {}
SceneBuilderRequest::Flush(tx) => {
self.tx.send(SceneBuilderResult::FlushComplete(tx)).unwrap();
let _ = self.api_tx.send(ApiMsg::WakeUp);
}
SceneBuilderRequest::Transaction {
document_id,
scene,

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

@ -8,7 +8,7 @@ use api::ImageDescriptor;
use device::TextureFilter;
use freelist::{FreeList, FreeListHandle, UpsertResult, WeakFreeListHandle};
use gpu_cache::{GpuCache, GpuCacheHandle};
use gpu_types::ImageSource;
use gpu_types::{ImageSource, UvRectKind};
use internal_types::{CacheTextureId, FastHashMap, TextureUpdateList, TextureUpdateSource};
use internal_types::{RenderTargetInfo, SourceTexture, TextureUpdate, TextureUpdateOp};
use profiler::{ResourceProfileCounter, TextureCacheProfileCounters};
@ -110,6 +110,8 @@ struct CacheEntry {
texture_id: CacheTextureId,
// Optional notice when the entry is evicted from the cache.
eviction_notice: Option<EvictionNotice>,
// The type of UV rect this entry specifies.
uv_rect_kind: UvRectKind,
}
impl CacheEntry {
@ -121,6 +123,7 @@ impl CacheEntry {
filter: TextureFilter,
user_data: [f32; 3],
last_access: FrameId,
uv_rect_kind: UvRectKind,
) -> Self {
CacheEntry {
size,
@ -132,6 +135,7 @@ impl CacheEntry {
filter,
uv_rect_handle: GpuCacheHandle::new(),
eviction_notice: None,
uv_rect_kind,
}
}
@ -154,6 +158,7 @@ impl CacheEntry {
p1: (origin + self.size).to_f32(),
texture_layer: layer_index,
user_data: self.user_data,
uv_rect_kind: self.uv_rect_kind,
};
image_source.write_gpu_blocks(&mut request);
}
@ -394,6 +399,7 @@ impl TextureCache {
mut dirty_rect: Option<DeviceUintRect>,
gpu_cache: &mut GpuCache,
eviction_notice: Option<&EvictionNotice>,
uv_rect_kind: UvRectKind,
) {
// Determine if we need to allocate texture cache memory
// for this item. We need to reallocate if any of the following
@ -422,7 +428,13 @@ impl TextureCache {
};
if realloc {
self.allocate(handle, descriptor, filter, user_data);
self.allocate(
handle,
descriptor,
filter,
user_data,
uv_rect_kind,
);
// If we reallocated, we need to upload the whole item again.
dirty_rect = None;
@ -639,7 +651,7 @@ impl TextureCache {
// - We have freed an item that will definitely allow us to
// fit the currently requested allocation.
let needed_slab_size =
SlabSize::new(required_alloc.width, required_alloc.height).get_size();
SlabSize::new(required_alloc.width, required_alloc.height);
let mut found_matching_slab = false;
let mut freed_complete_page = false;
let mut evicted_items = 0;
@ -698,6 +710,7 @@ impl TextureCache {
descriptor: &ImageDescriptor,
filter: TextureFilter,
user_data: [f32; 3],
uv_rect_kind: UvRectKind,
) -> Option<CacheEntry> {
// Work out which cache it goes in, based on format.
let texture_array = match (descriptor.format, filter) {
@ -745,6 +758,7 @@ impl TextureCache {
descriptor.height,
user_data,
self.frame_id,
uv_rect_kind,
)
}
@ -765,11 +779,12 @@ impl TextureCache {
allowed_in_shared_cache = false;
}
// Anything larger than 512 goes in a standalone texture.
// Anything larger than TEXTURE_REGION_DIMENSIONS goes in a standalone texture.
// TODO(gw): If we find pages that suffer from batch breaks in this
// case, add support for storing these in a standalone
// texture array.
if descriptor.width > 512 || descriptor.height > 512 {
if descriptor.width > TEXTURE_REGION_DIMENSIONS ||
descriptor.height > TEXTURE_REGION_DIMENSIONS {
allowed_in_shared_cache = false;
}
@ -785,6 +800,7 @@ impl TextureCache {
descriptor: ImageDescriptor,
filter: TextureFilter,
user_data: [f32; 3],
uv_rect_kind: UvRectKind,
) {
assert!(descriptor.width > 0 && descriptor.height > 0);
@ -803,7 +819,8 @@ impl TextureCache {
new_cache_entry = self.allocate_from_shared_cache(
&descriptor,
filter,
user_data
user_data,
uv_rect_kind,
);
// If we failed to allocate in the shared cache, run an
@ -814,7 +831,8 @@ impl TextureCache {
new_cache_entry = self.allocate_from_shared_cache(
&descriptor,
filter,
user_data
user_data,
uv_rect_kind,
);
}
}
@ -847,6 +865,7 @@ impl TextureCache {
filter,
user_data,
frame_id,
uv_rect_kind,
));
allocated_in_shared_cache = false;
@ -900,43 +919,48 @@ impl TextureCache {
}
}
// A list of the block sizes that a region can be initialized with.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Copy, Clone, PartialEq)]
enum SlabSize {
Size16x16,
Size32x32,
Size64x64,
Size128x128,
Size256x256,
Size512x512,
struct SlabSize {
width: u32,
height: u32,
}
impl SlabSize {
fn new(width: u32, height: u32) -> SlabSize {
// TODO(gw): Consider supporting non-square
// allocator sizes here.
let max_dim = cmp::max(width, height);
let x_size = quantize_dimension(width);
let y_size = quantize_dimension(height);
match max_dim {
0 => unreachable!(),
1...16 => SlabSize::Size16x16,
17...32 => SlabSize::Size32x32,
33...64 => SlabSize::Size64x64,
65...128 => SlabSize::Size128x128,
129...256 => SlabSize::Size256x256,
257...512 => SlabSize::Size512x512,
_ => panic!("Invalid dimensions for cache!"),
assert!(x_size > 0 && x_size <= TEXTURE_REGION_DIMENSIONS);
assert!(y_size > 0 && y_size <= TEXTURE_REGION_DIMENSIONS);
let (width, height) = match (x_size, y_size) {
// Special cased rectangular slab pages.
(512, 256) => (512, 256),
(512, 128) => (512, 128),
(512, 64) => (512, 64),
(256, 512) => (256, 512),
(128, 512) => (128, 512),
( 64, 512) => ( 64, 512),
// If none of those fit, use a square slab size.
(x_size, y_size) => {
let square_size = cmp::max(x_size, y_size);
(square_size, square_size)
}
};
SlabSize {
width,
height,
}
}
fn get_size(&self) -> u32 {
match *self {
SlabSize::Size16x16 => 16,
SlabSize::Size32x32 => 32,
SlabSize::Size64x64 => 64,
SlabSize::Size128x128 => 128,
SlabSize::Size256x256 => 256,
SlabSize::Size512x512 => 512,
fn invalid() -> SlabSize {
SlabSize {
width: 0,
height: 0,
}
}
}
@ -960,9 +984,8 @@ impl TextureLocation {
struct TextureRegion {
layer_index: i32,
region_size: u32,
slab_size: u32,
slab_size: SlabSize,
free_slots: Vec<TextureLocation>,
slots_per_axis: u32,
total_slot_count: usize,
origin: DeviceUintPoint,
}
@ -972,9 +995,8 @@ impl TextureRegion {
TextureRegion {
layer_index,
region_size,
slab_size: 0,
slab_size: SlabSize::invalid(),
free_slots: Vec::new(),
slots_per_axis: 0,
total_slot_count: 0,
origin,
}
@ -982,15 +1004,16 @@ impl TextureRegion {
// Initialize a region to be an allocator for a specific slab size.
fn init(&mut self, slab_size: SlabSize) {
debug_assert!(self.slab_size == 0);
debug_assert!(self.slab_size == SlabSize::invalid());
debug_assert!(self.free_slots.is_empty());
self.slab_size = slab_size.get_size();
self.slots_per_axis = self.region_size / self.slab_size;
self.slab_size = slab_size;
let slots_per_x_axis = self.region_size / self.slab_size.width;
let slots_per_y_axis = self.region_size / self.slab_size.height;
// Add each block to a freelist.
for y in 0 .. self.slots_per_axis {
for x in 0 .. self.slots_per_axis {
for y in 0 .. slots_per_y_axis {
for x in 0 .. slots_per_x_axis {
self.free_slots.push(TextureLocation::new(x, y));
}
}
@ -1001,30 +1024,31 @@ impl TextureRegion {
// Deinit a region, allowing it to become a region with
// a different allocator size.
fn deinit(&mut self) {
self.slab_size = 0;
self.slab_size = SlabSize::invalid();
self.free_slots.clear();
self.slots_per_axis = 0;
self.total_slot_count = 0;
}
fn is_empty(&self) -> bool {
self.slab_size == 0
self.slab_size == SlabSize::invalid()
}
// Attempt to allocate a fixed size block from this region.
fn alloc(&mut self) -> Option<DeviceUintPoint> {
debug_assert!(self.slab_size != SlabSize::invalid());
self.free_slots.pop().map(|location| {
DeviceUintPoint::new(
self.origin.x + self.slab_size * location.0 as u32,
self.origin.y + self.slab_size * location.1 as u32,
self.origin.x + self.slab_size.width * location.0 as u32,
self.origin.y + self.slab_size.height * location.1 as u32,
)
})
}
// Free a block in this region.
fn free(&mut self, point: DeviceUintPoint) {
let x = (point.x - self.origin.x) / self.slab_size;
let y = (point.y - self.origin.y) / self.slab_size;
let x = (point.x - self.origin.x) / self.slab_size.width;
let y = (point.y - self.origin.y) / self.slab_size.height;
self.free_slots.push(TextureLocation::new(x, y));
// If this region is completely unused, deinit it
@ -1089,6 +1113,7 @@ impl TextureArray {
height: u32,
user_data: [f32; 3],
frame_id: FrameId,
uv_rect_kind: UvRectKind,
) -> Option<CacheEntry> {
// Lazily allocate the regions if not already created.
// This means that very rarely used image formats can be
@ -1118,7 +1143,6 @@ impl TextureArray {
// Quantize the size of the allocation to select a region to
// allocate from.
let slab_size = SlabSize::new(width, height);
let slab_size_dim = slab_size.get_size();
// TODO(gw): For simplicity, the initial implementation just
// has a single vec<> of regions. We could easily
@ -1134,9 +1158,9 @@ impl TextureArray {
// Run through the existing regions of this size, and see if
// we can find a free block in any of them.
for (i, region) in self.regions.iter_mut().enumerate() {
if region.slab_size == 0 {
if region.is_empty() {
empty_region_index = Some(i);
} else if region.slab_size == slab_size_dim {
} else if region.slab_size == slab_size {
if let Some(location) = region.alloc() {
entry_kind = Some(EntryKind::Cache {
layer_index: region.layer_index as u16,
@ -1174,6 +1198,7 @@ impl TextureArray {
filter: self.filter,
texture_id: self.texture_id.unwrap(),
eviction_notice: None,
uv_rect_kind,
}
})
}
@ -1244,3 +1269,16 @@ impl TextureUpdate {
}
}
}
fn quantize_dimension(size: u32) -> u32 {
match size {
0 => unreachable!(),
1...16 => 16,
17...32 => 32,
33...64 => 64,
65...128 => 128,
129...256 => 256,
257...512 => 512,
_ => panic!("Invalid dimensions for cache!"),
}
}

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

@ -633,6 +633,7 @@ pub enum ApiMsg {
/// through another channel.
WakeUp,
WakeSceneBuilder,
FlushSceneBuilder(MsgSender<()>),
ShutDown,
}
@ -653,6 +654,7 @@ impl fmt::Debug for ApiMsg {
ApiMsg::ShutDown => "ApiMsg::ShutDown",
ApiMsg::WakeUp => "ApiMsg::WakeUp",
ApiMsg::WakeSceneBuilder => "ApiMsg::WakeSceneBuilder",
ApiMsg::FlushSceneBuilder(..) => "ApiMsg::FlushSceneBuilder",
})
}
}
@ -965,6 +967,15 @@ impl RenderApi {
self.send_message(ApiMsg::WakeSceneBuilder);
}
/// Block until a round-trip to the scene builder thread has completed. This
/// ensures that any transactions (including ones deferred to the scene
/// builder thread) have been processed.
pub fn flush_scene_builder(&self) {
let (tx, rx) = channel::msg_channel().unwrap();
self.send_message(ApiMsg::FlushSceneBuilder(tx));
rx.recv().unwrap(); // block until done
}
/// Save a capture of the current frame state for debugging.
pub fn save_capture(&self, path: PathBuf, bits: CaptureBits) {
let msg = ApiMsg::DebugCommand(DebugCommand::SaveCapture(path, bits));

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

@ -1 +1 @@
751236199b39bb8dac78522713133ca18c603fb3
4b65822a2f7e1fed246a492f9fe193ede2f37d74