Bug 1389497 - Update webrender to commit 1007a65c6dd1fdfb8b39d57d7faff3cae7b32e0c. r=jrmuizel

MozReview-Commit-ID: LLg2tnX9LYu

--HG--
extra : rebase_source : 9fbbd518af8a3e2727edfe92ebf6171f272e9d65
This commit is contained in:
Kartikaya Gupta 2017-08-18 08:51:39 -04:00
parent 29fb7aad8e
commit 83c2515b8a
60 changed files with 2618 additions and 4044 deletions

View File

@ -79,4 +79,4 @@ to make sure that mozjs_sys also has its Cargo.lock file updated if needed, henc
the need to run the cargo update command in js/src as well. Hopefully this will
be resolved soon.
Latest Commit: 101c69db1a989fe89c308dabd53cf50aedfe4a96
Latest Commit: 1007a65c6dd1fdfb8b39d57d7faff3cae7b32e0c

View File

@ -1,16 +1,15 @@
[package]
name = "webrender"
version = "0.48.0"
version = "0.49.0"
authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
license = "MPL-2.0"
repository = "https://github.com/servo/webrender"
build = "build.rs"
[features]
default = ["freetype-lib", "webgl"]
default = ["freetype-lib"]
freetype-lib = ["freetype/servo-freetype-sys"]
profiler = ["thread_profiler/thread_profiler"]
webgl = ["offscreen_gl_context", "webrender_api/webgl"]
[dependencies]
app_units = "0.5"
@ -19,11 +18,10 @@ bit-set = "0.4"
byteorder = "1.0"
euclid = "0.15.1"
fxhash = "0.2.1"
gleam = "0.4.7"
gleam = "0.4.8"
lazy_static = "0.2"
log = "0.3"
num-traits = "0.1.32"
offscreen_gl_context = {version = "0.11", features = ["serde", "osmesa"], optional = true}
time = "0.1"
rayon = "0.8"
webrender_api = {path = "../webrender_api"}

View File

@ -1,22 +0,0 @@
#![feature(test)]
extern crate rand;
extern crate test;
extern crate webrender;
use rand::Rng;
use test::Bencher;
use webrender::TexturePage;
use webrender::api::{DeviceUintSize as Size};
#[bench]
fn bench_coalesce(b: &mut Bencher) {
let mut rng = rand::thread_rng();
let mut page = TexturePage::new_dummy(Size::new(10000, 10000));
let mut test_page = TexturePage::new_dummy(Size::new(10000, 10000));
while page.allocate(&Size::new(rng.gen_range(1, 100), rng.gen_range(1, 100))).is_some() {}
b.iter(|| {
test_page.fill_from(&page);
test_page.coalesce();
});
}

View File

@ -9,6 +9,7 @@ use std::path::PathBuf;
use webrender;
use webrender::api::*;
use webrender::renderer::{PROFILER_DBG, RENDER_TARGET_DBG, TEXTURE_CACHE_DBG};
use webrender::renderer::ExternalImageHandler;
struct Notifier {
window_proxy: glutin::WindowProxy,
@ -64,6 +65,9 @@ pub trait Example {
event: glutin::Event,
api: &RenderApi,
document_id: DocumentId) -> bool;
fn get_external_image_handler(&self) -> Option<Box<ExternalImageHandler>> {
None
}
}
pub fn main_wrapper(example: &mut Example,
@ -116,6 +120,10 @@ pub fn main_wrapper(example: &mut Example,
let notifier = Box::new(Notifier::new(window.create_window_proxy()));
renderer.set_render_notifier(notifier);
if let Some(external_image_handler) = example.get_external_image_handler() {
renderer.set_external_image_handler(external_image_handler);
}
let epoch = Epoch(0);
let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

View File

@ -0,0 +1,287 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern crate gleam;
extern crate glutin;
extern crate webrender;
#[path="common/boilerplate.rs"]
mod boilerplate;
use boilerplate::{Example, HandyDandyRectBuilder};
use std::mem;
use webrender::api::*;
use webrender::renderer::{ExternalImage, ExternalImageSource, ExternalImageHandler};
struct ImageGenerator {
patterns: [[u8; 3]; 6],
next_pattern: usize,
current_image: Vec<u8>,
}
impl ImageGenerator {
fn new() -> ImageGenerator {
ImageGenerator {
next_pattern: 0,
patterns: [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
[1, 1, 0],
[0, 1, 1],
[1, 0, 1],
],
current_image: Vec::new(),
}
}
fn generate_image(&mut self, size: u32) {
let pattern = &self.patterns[self.next_pattern];
self.current_image.clear();
for y in 0..size {
for x in 0..size {
let lum = 255 * (1 - (((x & 8) == 0) ^ ((y & 8) == 0)) as u8);
self.current_image.extend_from_slice(&[lum * pattern[0],
lum * pattern[1],
lum * pattern[2],
0xff]);
}
}
self.next_pattern = (self.next_pattern + 1) % self.patterns.len();
}
fn take(&mut self) -> Vec<u8> {
mem::replace(&mut self.current_image, Vec::new())
}
}
impl ExternalImageHandler for ImageGenerator {
fn lock(&mut self, _key: ExternalImageId, channel_index: u8) -> ExternalImage {
self.generate_image(channel_index as u32);
ExternalImage {
u0: 0.0,
v0: 0.0,
u1: 1.0,
v1: 1.0,
source: ExternalImageSource::RawData(&self.current_image)
}
}
fn unlock(&mut self, _key: ExternalImageId, _channel_index: u8) {
}
}
struct App {
stress_keys: Vec<ImageKey>,
image_key: Option<ImageKey>,
image_generator: ImageGenerator,
swap_keys: Vec<ImageKey>,
swap_index: usize,
}
impl Example for App {
fn render(&mut self,
api: &RenderApi,
builder: &mut DisplayListBuilder,
resources: &mut ResourceUpdates,
_layout_size: LayoutSize,
_pipeline_id: PipelineId,
_document_id: DocumentId) {
let bounds = (0,0).to(512, 512);
builder.push_stacking_context(ScrollPolicy::Scrollable,
bounds,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new());
let x0 = 50.0;
let y0 = 50.0;
let image_size = LayoutSize::new(4.0, 4.0);
if self.swap_keys.is_empty() {
let key0 = api.generate_image_key();
let key1 = api.generate_image_key();
self.image_generator.generate_image(128);
resources.add_image(
key0,
ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true),
ImageData::new(self.image_generator.take()),
None,
);
self.image_generator.generate_image(128);
resources.add_image(
key1,
ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true),
ImageData::new(self.image_generator.take()),
None,
);
self.swap_keys.push(key0);
self.swap_keys.push(key1);
}
for (i, key) in self.stress_keys.iter().enumerate() {
let x = (i % 128) as f32;
let y = (i / 128) as f32;
builder.push_image(
LayoutRect::new(LayoutPoint::new(x0 + image_size.width * x, y0 + image_size.height * y), image_size),
Some(LocalClip::from(bounds)),
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
*key
);
}
if let Some(image_key) = self.image_key {
let image_size = LayoutSize::new(100.0, 100.0);
builder.push_image(
LayoutRect::new(LayoutPoint::new(100.0, 100.0), image_size),
Some(LocalClip::from(bounds)),
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
image_key
);
}
let swap_key = self.swap_keys[self.swap_index];
let image_size = LayoutSize::new(64.0, 64.0);
builder.push_image(
LayoutRect::new(LayoutPoint::new(100.0, 400.0), image_size),
Some(LocalClip::from(bounds)),
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
swap_key
);
self.swap_index = 1 - self.swap_index;
builder.pop_stacking_context();
}
fn on_event(&mut self,
event: glutin::Event,
api: &RenderApi,
_document_id: DocumentId) -> bool {
match event {
glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(key)) => {
let mut updates = ResourceUpdates::new();
match key {
glutin::VirtualKeyCode::S => {
self.stress_keys.clear();
for _ in 0..16 {
for _ in 0..16 {
let size = 4;
let image_key = api.generate_image_key();
self.image_generator.generate_image(size);
updates.add_image(
image_key,
ImageDescriptor::new(size, size, ImageFormat::BGRA8, true),
ImageData::new(self.image_generator.take()),
None,
);
self.stress_keys.push(image_key);
}
}
}
glutin::VirtualKeyCode::D => {
if let Some(image_key) = self.image_key.take() {
updates.delete_image(image_key);
}
}
glutin::VirtualKeyCode::U => {
if let Some(image_key) = self.image_key {
let size = 128;
self.image_generator.generate_image(size);
updates.update_image(
image_key,
ImageDescriptor::new(size, size, ImageFormat::BGRA8, true),
ImageData::new(self.image_generator.take()),
None,
);
}
}
glutin::VirtualKeyCode::E => {
if let Some(image_key) = self.image_key.take() {
updates.delete_image(image_key);
}
let size = 32;
let image_key = api.generate_image_key();
let image_data = ExternalImageData {
id: ExternalImageId(0),
channel_index: size as u8,
image_type: ExternalImageType::ExternalBuffer,
};
updates.add_image(
image_key,
ImageDescriptor::new(size, size, ImageFormat::BGRA8, true),
ImageData::External(image_data),
None,
);
self.image_key = Some(image_key);
}
glutin::VirtualKeyCode::R => {
if let Some(image_key) = self.image_key.take() {
updates.delete_image(image_key);
}
let image_key = api.generate_image_key();
let size = 32;
self.image_generator.generate_image(size);
updates.add_image(
image_key,
ImageDescriptor::new(size, size, ImageFormat::BGRA8, true),
ImageData::new(self.image_generator.take()),
None,
);
self.image_key = Some(image_key);
}
_ => {}
}
api.update_resources(updates);
return true;
}
_ => {}
}
false
}
fn get_external_image_handler(&self) -> Option<Box<ExternalImageHandler>> {
Some(Box::new(ImageGenerator::new()))
}
}
fn main() {
let mut app = App {
image_key: None,
stress_keys: Vec::new(),
image_generator: ImageGenerator::new(),
swap_keys: Vec::new(),
swap_index: 0,
};
boilerplate::main_wrapper(&mut app, None);
}

View File

@ -13,16 +13,15 @@
in int aClipRenderTaskIndex;
in int aClipLayerIndex;
in int aClipDataIndex;
in int aClipSegmentIndex;
in int aClipResourceAddress;
in int aClipSegment;
in ivec4 aClipDataResourceAddress;
struct CacheClipInstance {
int render_task_index;
int layer_index;
int data_index;
int segment_index;
int resource_address;
int segment;
ivec2 clip_data_address;
ivec2 resource_address;
};
CacheClipInstance fetch_clip_item(int index) {
@ -30,9 +29,9 @@ CacheClipInstance fetch_clip_item(int index) {
cci.render_task_index = aClipRenderTaskIndex;
cci.layer_index = aClipLayerIndex;
cci.data_index = aClipDataIndex;
cci.segment_index = aClipSegmentIndex;
cci.resource_address = aClipResourceAddress;
cci.segment = aClipSegment;
cci.clip_data_address = aClipDataResourceAddress.xy;
cci.resource_address = aClipDataResourceAddress.zw;
return cci;
}
@ -48,7 +47,7 @@ struct ClipVertexInfo {
ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
Layer layer,
ClipArea area,
int segment_index) {
int segment) {
RectWithSize clipped_local_rect = intersect_rect(local_clip_rect,
layer.local_clip_rect);
@ -59,7 +58,7 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
vec2 inner_p1 = area.inner_rect.zw;
vec2 p0, p1;
switch (segment_index) {
switch (segment) {
case SEGMENT_ALL:
p0 = outer_p0;
p1 = outer_p1;

View File

@ -21,8 +21,8 @@ struct BorderCorner {
int clip_mode;
};
BorderCorner fetch_border_corner(int index) {
vec4 data[2] = fetch_from_resource_cache_2(index);
BorderCorner fetch_border_corner(ivec2 address) {
vec4 data[2] = fetch_from_resource_cache_2_direct(address);
return BorderCorner(RectWithSize(data[0].xy, data[0].zw),
data[1].xy,
int(data[1].z),
@ -35,8 +35,8 @@ struct BorderClipDash {
vec4 point_tangent_1;
};
BorderClipDash fetch_border_clip_dash(int index) {
vec4 data[2] = fetch_from_resource_cache_2(index);
BorderClipDash fetch_border_clip_dash(ivec2 address, int segment) {
vec4 data[2] = fetch_from_resource_cache_2_direct(address + ivec2(2 + 2 * (segment - 1), 0));
return BorderClipDash(data[0], data[1]);
}
@ -45,8 +45,8 @@ struct BorderClipDot {
vec3 center_radius;
};
BorderClipDot fetch_border_clip_dot(int index) {
vec4 data = fetch_from_resource_cache_1(index);
BorderClipDot fetch_border_clip_dot(ivec2 address, int segment) {
vec4 data = fetch_from_resource_cache_1_direct(address + ivec2(2 + (segment - 1), 0));
return BorderClipDot(data.xyz);
}
@ -56,10 +56,10 @@ void main(void) {
Layer layer = fetch_layer(cci.layer_index);
// Fetch the header information for this corner clip.
BorderCorner corner = fetch_border_corner(cci.data_index);
BorderCorner corner = fetch_border_corner(cci.clip_data_address);
vClipCenter = corner.clip_center;
if (cci.segment_index == 0) {
if (cci.segment == 0) {
// The first segment is used to zero out the border corner.
vAlphaMask = vec2(0.0);
vDotParams = vec3(0.0);
@ -85,7 +85,7 @@ void main(void) {
switch (corner.clip_mode) {
case CLIP_MODE_DASH: {
// Fetch the information about this particular dash.
BorderClipDash dash = fetch_border_clip_dash(cci.data_index + 2 + 2 * (cci.segment_index - 1));
BorderClipDash dash = fetch_border_clip_dash(cci.clip_data_address, cci.segment);
vPoint_Tangent0 = dash.point_tangent_0 * sign_modifier.xyxy;
vPoint_Tangent1 = dash.point_tangent_1 * sign_modifier.xyxy;
vDotParams = vec3(0.0);
@ -93,7 +93,7 @@ void main(void) {
break;
}
case CLIP_MODE_DOT: {
BorderClipDot cdot = fetch_border_clip_dot(cci.data_index + 2 + (cci.segment_index - 1));
BorderClipDot cdot = fetch_border_clip_dot(cci.clip_data_address, cci.segment);
vPoint_Tangent0 = vec4(1.0);
vPoint_Tangent1 = vec4(1.0);
vDotParams = vec3(cdot.center_radius.xy * sign_modifier, cdot.center_radius.z);

View File

@ -11,7 +11,7 @@ void main(void) {
clamp(vClipMaskUv.xy, vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 source_uv = clamp(clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy,
vClipMaskUvInnerRect.xy, vClipMaskUvInnerRect.zw);
float clip_alpha = texture(sColor0, source_uv).r; //careful: texture has type A8
float clip_alpha = texture(sColor0, vec3(source_uv, vLayer)).r; //careful: texture has type A8
oFragColor = vec4(min(alpha, clip_alpha), 1.0, 1.0, 1.0);
}

View File

@ -7,3 +7,4 @@
varying vec3 vPos;
flat varying vec4 vClipMaskUvRect;
flat varying vec4 vClipMaskUvInnerRect;
flat varying float vLayer;

View File

@ -7,8 +7,8 @@ struct ImageMaskData {
RectWithSize local_rect;
};
ImageMaskData fetch_mask_data(int index) {
vec4 data = fetch_from_resource_cache_1(index);
ImageMaskData fetch_mask_data(ivec2 address) {
vec4 data = fetch_from_resource_cache_1_direct(address);
return ImageMaskData(RectWithSize(data.xy, data.zw));
}
@ -16,16 +16,17 @@ void main(void) {
CacheClipInstance cci = fetch_clip_item(gl_InstanceID);
ClipArea area = fetch_clip_area(cci.render_task_index);
Layer layer = fetch_layer(cci.layer_index);
ImageMaskData mask = fetch_mask_data(cci.data_index);
ImageMaskData mask = fetch_mask_data(cci.clip_data_address);
RectWithSize local_rect = mask.local_rect;
ImageResource res = fetch_image_resource(cci.resource_address);
ImageResource res = fetch_image_resource_direct(cci.resource_address);
ClipVertexInfo vi = write_clip_tile_vertex(local_rect,
layer,
area,
cci.segment_index);
cci.segment);
vPos = vi.local_pos;
vLayer = res.layer;
vClipMaskUv = vec3((vPos.xy / vPos.z - local_rect.p0) / local_rect.size, 0.0);
vec2 texture_size = vec2(textureSize(sColor0, 0));

View File

@ -8,8 +8,8 @@ struct ClipRect {
vec4 mode;
};
ClipRect fetch_clip_rect(int index) {
vec4 data[2] = fetch_from_resource_cache_2(index);
ClipRect fetch_clip_rect(ivec2 address) {
vec4 data[2] = fetch_from_resource_cache_2_direct(address);
return ClipRect(RectWithSize(data[0].xy, data[0].zw), data[1]);
}
@ -18,8 +18,9 @@ struct ClipCorner {
vec4 outer_inner_radius;
};
ClipCorner fetch_clip_corner(int index) {
vec4 data[2] = fetch_from_resource_cache_2(index);
ClipCorner fetch_clip_corner(ivec2 address, int index) {
address += ivec2(2 + 2 * index, 0);
vec4 data[2] = fetch_from_resource_cache_2_direct(address);
return ClipCorner(RectWithSize(data[0].xy, data[0].zw), data[1]);
}
@ -31,14 +32,14 @@ struct ClipData {
ClipCorner bottom_right;
};
ClipData fetch_clip(int index) {
ClipData fetch_clip(ivec2 address) {
ClipData clip;
clip.rect = fetch_clip_rect(index + 0);
clip.top_left = fetch_clip_corner(index + 2);
clip.top_right = fetch_clip_corner(index + 4);
clip.bottom_left = fetch_clip_corner(index + 6);
clip.bottom_right = fetch_clip_corner(index + 8);
clip.rect = fetch_clip_rect(address);
clip.top_left = fetch_clip_corner(address, 0);
clip.top_right = fetch_clip_corner(address, 1);
clip.bottom_left = fetch_clip_corner(address, 2);
clip.bottom_right = fetch_clip_corner(address, 3);
return clip;
}
@ -47,13 +48,13 @@ void main(void) {
CacheClipInstance cci = fetch_clip_item(gl_InstanceID);
ClipArea area = fetch_clip_area(cci.render_task_index);
Layer layer = fetch_layer(cci.layer_index);
ClipData clip = fetch_clip(cci.data_index);
ClipData clip = fetch_clip(cci.clip_data_address);
RectWithSize local_rect = clip.rect.rect;
ClipVertexInfo vi = write_clip_tile_vertex(local_rect,
layer,
area,
cci.segment_index);
cci.segment);
vPos = vi.local_pos;
vClipMode = clip.rect.mode.x;

View File

@ -3,5 +3,5 @@
* 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/. */
varying vec2 vUv;
varying vec3 vUv;
flat varying vec4 vColor;

View File

@ -47,7 +47,7 @@ void main(void) {
local_rect.xy + local_rect.zw,
aPosition.xy);
vUv = mix(st0, st1, aPosition.xy);
vUv = vec3(mix(st0, st1, aPosition.xy), res.layer);
vColor = shadow.color;
gl_Position = uTransform * vec4(pos, 0.0, 1.0);

View File

@ -7,10 +7,6 @@ varying vec4 vColor;
void main(void)
{
#ifdef SERVO_ES2
float alpha = texture(sColor0, vColorTexCoord.xy).a;
#else
float alpha = texture(sColor0, vColorTexCoord.xy).r;
#endif
float alpha = texture(sColor0, vec3(vColorTexCoord.xy, 0.0)).r;
oFragColor = vec4(vColor.xyz, vColor.w * alpha);
}

View File

@ -3,25 +3,6 @@
* 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/. */
#if defined(GL_ES)
#if GL_ES == 1
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp sampler2DArray;
#else
precision mediump sampler2DArray;
#endif
// Sampler default precision is lowp on mobile GPUs.
// This causes RGBA32F texture data to be clamped to 16 bit floats on some GPUs (e.g. Mali-T880).
// Define highp precision macro to allow lossless FLOAT texture sampling.
#define HIGHP_SAMPLER_FLOAT highp
#else
#define HIGHP_SAMPLER_FLOAT
#endif
#else
#define HIGHP_SAMPLER_FLOAT
#endif
#define PST_TOP_LEFT 0
#define PST_TOP 1
#define PST_TOP_RIGHT 2
@ -129,6 +110,13 @@ ivec2 get_resource_cache_uv(int address) {
uniform HIGHP_SAMPLER_FLOAT sampler2D sResourceCache;
vec4[2] fetch_from_resource_cache_2_direct(ivec2 address) {
return vec4[2](
texelFetchOffset(sResourceCache, address, 0, ivec2(0, 0)),
texelFetchOffset(sResourceCache, address, 0, ivec2(1, 0))
);
}
vec4[2] fetch_from_resource_cache_2(int address) {
ivec2 uv = get_resource_cache_uv(address);
return vec4[2](
@ -193,6 +181,10 @@ vec4[4] fetch_from_resource_cache_4(int address) {
);
}
vec4 fetch_from_resource_cache_1_direct(ivec2 address) {
return texelFetch(sResourceCache, address, 0);
}
vec4 fetch_from_resource_cache_1(int address) {
ivec2 uv = get_resource_cache_uv(address);
return texelFetch(sResourceCache, uv, 0);
@ -771,21 +763,28 @@ TransformVertexInfo write_transform_vertex(RectWithSize instance_rect,
struct GlyphResource {
vec4 uv_rect;
float layer;
vec2 offset;
};
GlyphResource fetch_glyph_resource(int address) {
vec4 data[2] = fetch_from_resource_cache_2(address);
return GlyphResource(data[0], data[1].xy);
return GlyphResource(data[0], data[1].x, data[1].yz);
}
struct ImageResource {
vec4 uv_rect;
float layer;
};
ImageResource fetch_image_resource(int address) {
vec4 data = fetch_from_resource_cache_1(address);
return ImageResource(data);
vec4 data[2] = fetch_from_resource_cache_2(address);
return ImageResource(data[0], data[1].x);
}
ImageResource fetch_image_resource_direct(ivec2 address) {
vec4 data[2] = fetch_from_resource_cache_2_direct(address);
return ImageResource(data[0], data[1].x);
}
struct Rectangle {

View File

@ -5,5 +5,5 @@
void main(void) {
vec2 uv = clamp(vUv.xy, vUvBounds.xy, vUvBounds.zw);
oFragColor = texture(sCacheRGBA8, vec3(uv, vUv.z));
oFragColor = texture(sColor0, vec3(uv, vUv.z));
}

View File

@ -28,5 +28,5 @@ void main(void) {
alpha = alpha * float(all(bvec2(step(position_in_tile, vStretchSize))));
oFragColor = vec4(alpha) * TEX_SAMPLE(sColor0, st);
oFragColor = vec4(alpha) * TEX_SAMPLE(sColor0, vec3(st, vLayer));
}

View File

@ -9,6 +9,7 @@ flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas
flat varying vec2 vTextureSize; // Size of the image in the texture atlas.
flat varying vec2 vTileSpacing; // Amount of space between tiled instances of this image.
flat varying vec4 vStRect; // Rectangle of valid texture rect.
flat varying float vLayer;
#ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos;

View File

@ -50,6 +50,7 @@ void main(void) {
vec2 st0 = uv0 / texture_size_normalization_factor;
vec2 st1 = uv1 / texture_size_normalization_factor;
vLayer = res.layer;
vTextureSize = st1 - st0;
vTextureOffset = st0;
vTileSpacing = image.stretch_size_and_tile_spacing.zw;

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
void main(void) {
vec2 tc = clamp(vUv, vUvBorder.xy, vUvBorder.zw);
vec3 tc = vec3(clamp(vUv.xy, vUvBorder.xy, vUvBorder.zw), vUv.z);
#ifdef WR_FEATURE_SUBPIXEL_AA
//note: the blend mode is not compatible with clipping
oFragColor = texture(sColor0, tc);

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
flat varying vec4 vColor;
varying vec2 vUv;
varying vec3 vUv;
flat varying vec4 vUvBorder;
#ifdef WR_FEATURE_TRANSFORM

View File

@ -48,6 +48,6 @@ void main(void) {
vec2 st1 = res.uv_rect.zw / texture_size;
vColor = text.color;
vUv = mix(st0, st1, f);
vUv = vec3(mix(st0, st1, f), res.layer);
vUvBorder = (res.uv_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
}

View File

@ -73,17 +73,17 @@ void main(void) {
// "The Y, Cb and Cr color channels within the 422 data are mapped into
// the existing green, blue and red color channels."
// https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
yuv_value = TEX_SAMPLE(sColor0, st_y).gbr;
yuv_value = TEX_SAMPLE(sColor0, vec3(st_y, vLayers.x)).gbr;
#elif defined(WR_FEATURE_NV12)
yuv_value.x = TEX_SAMPLE(sColor0, st_y).r;
yuv_value.yz = TEX_SAMPLE(sColor1, st_u).rg;
yuv_value.x = TEX_SAMPLE(sColor0, vec3(st_y, vLayers.x)).r;
yuv_value.yz = TEX_SAMPLE(sColor1, vec3(st_u, vLayers.y)).rg;
#else
// The yuv_planar format should have this third texture coordinate.
vec2 st_v = vTextureOffsetV + uv_offset;
yuv_value.x = TEX_SAMPLE(sColor0, st_y).r;
yuv_value.y = TEX_SAMPLE(sColor1, st_u).r;
yuv_value.z = TEX_SAMPLE(sColor2, st_v).r;
yuv_value.x = TEX_SAMPLE(sColor0, vec3(st_y, vLayers.x)).r;
yuv_value.y = TEX_SAMPLE(sColor1, vec3(st_u, vLayers.y)).r;
yuv_value.z = TEX_SAMPLE(sColor2, vec3(st_v, vLayers.z)).r;
#endif
// See the YuvColorMatrix definition for an explanation of where the constants come from.

View File

@ -13,6 +13,7 @@ flat varying vec2 vTextureSizeUv; // Size of the u and v planes in the texture
flat varying vec2 vStretchSize;
flat varying vec2 vHalfTexelY; // Normalized length of the half of a Y texel.
flat varying vec2 vHalfTexelUv; // Normalized length of the half of u and v texels.
flat varying vec3 vLayers;
#ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos;

View File

@ -26,10 +26,14 @@ void main(void) {
write_clip(vi.screen_pos, prim.clip_area);
ImageResource y_rect = fetch_image_resource(prim.user_data0);
vLayers = vec3(y_rect.layer, 0.0, 0.0);
#ifndef WR_FEATURE_INTERLEAVED_Y_CB_CR // only 1 channel
ImageResource u_rect = fetch_image_resource(prim.user_data1);
vLayers.y = u_rect.layer;
#ifndef WR_FEATURE_NV12 // 2 channel
ImageResource v_rect = fetch_image_resource(prim.user_data2);
vLayers.z = v_rect.layer;
#endif
#endif

View File

@ -14,8 +14,8 @@
// The textureLod() doesn't support sampler2DRect for WR_FEATURE_TEXTURE_RECT, too.
//
// Use texture() instead.
#if defined(WR_FEATURE_TEXTURE_EXTERNAL) || defined(WR_FEATURE_TEXTURE_RECT)
#define TEX_SAMPLE(sampler, tex_coord) texture(sampler, tex_coord)
#if defined(WR_FEATURE_TEXTURE_EXTERNAL) || defined(WR_FEATURE_TEXTURE_RECT) || defined(WR_FEATURE_TEXTURE_2D)
#define TEX_SAMPLE(sampler, tex_coord) texture(sampler, tex_coord.xy)
#else
// In normal case, we use textureLod(). We haven't used the lod yet. So, we always pass 0.0 now.
#define TEX_SAMPLE(sampler, tex_coord) textureLod(sampler, tex_coord, 0.0)
@ -52,7 +52,30 @@
//======================================================================================
// Shared shader uniforms
//======================================================================================
#ifdef WR_FEATURE_TEXTURE_RECT
#if defined(GL_ES)
#if GL_ES == 1
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp sampler2DArray;
#else
precision mediump sampler2DArray;
#endif
// Sampler default precision is lowp on mobile GPUs.
// This causes RGBA32F texture data to be clamped to 16 bit floats on some GPUs (e.g. Mali-T880).
// Define highp precision macro to allow lossless FLOAT texture sampling.
#define HIGHP_SAMPLER_FLOAT highp
#else
#define HIGHP_SAMPLER_FLOAT
#endif
#else
#define HIGHP_SAMPLER_FLOAT
#endif
#ifdef WR_FEATURE_TEXTURE_2D
uniform sampler2D sColor0;
uniform sampler2D sColor1;
uniform sampler2D sColor2;
#elif defined WR_FEATURE_TEXTURE_RECT
uniform sampler2DRect sColor0;
uniform sampler2DRect sColor1;
uniform sampler2DRect sColor2;
@ -61,9 +84,9 @@ uniform samplerExternalOES sColor0;
uniform samplerExternalOES sColor1;
uniform samplerExternalOES sColor2;
#else
uniform sampler2D sColor0;
uniform sampler2D sColor1;
uniform sampler2D sColor2;
uniform sampler2DArray sColor0;
uniform sampler2DArray sColor1;
uniform sampler2DArray sColor2;
#endif
#ifdef WR_FEATURE_DITHERING

View File

@ -4,7 +4,9 @@
use api::{ClipId, DeviceIntRect, LayerPixel, LayerPoint, LayerRect, LayerSize};
use api::{LayerToScrollTransform, LayerToWorldTransform, LayerVector2D, PipelineId};
use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollSensitivity, WorldPoint};
use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollSensitivity, StickyFrameInfo};
use api::WorldPoint;
use clip_scroll_tree::TransformUpdateState;
use geometry::ray_intersects_rect;
use mask_cache::{ClipRegion, ClipSource, MaskCacheInfo};
use spring::{DAMPING, STIFFNESS, Spring};
@ -61,15 +63,21 @@ impl ClipInfo {
#[derive(Clone, Debug)]
pub enum NodeType {
/// Transform for this layer, relative to parent reference frame. A reference
/// frame establishes a new coordinate space in the tree.
ReferenceFrame(LayerToScrollTransform),
/// A reference frame establishes a new coordinate space in the tree.
ReferenceFrame(ReferenceFrameInfo),
/// Other nodes just do clipping, but no transformation.
Clip(ClipInfo),
/// Other nodes just do clipping, but no transformation.
/// Transforms it's content, but doesn't clip it. Can also be adjusted
/// by scroll events or setting scroll offsets.
ScrollFrame(ScrollingState),
/// A special kind of node that adjusts its position based on the position
/// of its parent node and a given set of sticky positioning constraints.
/// Sticky positioned is described in the CSS Positioned Layout Module Level 3 here:
/// https://www.w3.org/TR/css-position-3/#sticky-pos
StickyFrame(StickyFrameInfo),
}
/// Contains information common among all types of ClipScrollTree nodes.
@ -159,9 +167,15 @@ impl ClipScrollNode {
pub fn new_reference_frame(parent_id: Option<ClipId>,
local_viewport_rect: &LayerRect,
content_size: LayerSize,
local_transform: &LayerToScrollTransform,
transform: &LayerToScrollTransform,
origin_in_parent_reference_frame: LayerVector2D,
pipeline_id: PipelineId)
-> ClipScrollNode {
let info = ReferenceFrameInfo {
transform: *transform,
origin_in_parent_reference_frame,
};
ClipScrollNode {
content_size,
local_viewport_rect: *local_viewport_rect,
@ -173,26 +187,45 @@ impl ClipScrollNode {
parent: parent_id,
children: Vec::new(),
pipeline_id,
node_type: NodeType::ReferenceFrame(*local_transform),
node_type: NodeType::ReferenceFrame(info),
}
}
pub fn new_sticky_frame(parent_id: ClipId,
frame_rect: LayerRect,
sticky_frame_info: StickyFrameInfo,
pipeline_id: PipelineId)
-> ClipScrollNode {
ClipScrollNode {
content_size: frame_rect.size,
local_viewport_rect: frame_rect,
local_clip_rect: frame_rect,
combined_local_viewport_rect: LayerRect::zero(),
world_viewport_transform: LayerToWorldTransform::identity(),
world_content_transform: LayerToWorldTransform::identity(),
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
parent: Some(parent_id),
children: Vec::new(),
pipeline_id,
node_type: NodeType::StickyFrame(sticky_frame_info),
}
}
pub fn add_child(&mut self, child: ClipId) {
self.children.push(child);
}
pub fn apply_old_scrolling_state(&mut self, new_scrolling: &ScrollingState) {
match self.node_type {
NodeType::ReferenceFrame(_) | NodeType::Clip(_) => {
if new_scrolling.offset != LayerVector2D::zero() {
warn!("Tried to scroll a non-scroll node.");
}
}
NodeType::ScrollFrame(ref mut scrolling) => {
let scroll_sensitivity = scrolling.scroll_sensitivity;
*scrolling = *new_scrolling;
scrolling.scroll_sensitivity = scroll_sensitivity;
}
_ if new_scrolling.offset != LayerVector2D::zero() =>
warn!("Tried to scroll a non-scroll node."),
_ => {}
}
}
@ -201,11 +234,11 @@ impl ClipScrollNode {
let scrollable_width = self.scrollable_width();
let scrolling = match self.node_type {
NodeType::ReferenceFrame(_) | NodeType::Clip(_) => {
NodeType::ScrollFrame(ref mut scrolling) => scrolling,
_ => {
warn!("Tried to scroll a non-scroll node.");
return false;
}
NodeType::ScrollFrame(ref mut scrolling) => scrolling,
};
let new_offset = match clamp {
@ -231,41 +264,53 @@ impl ClipScrollNode {
true
}
pub fn update_transform(&mut self,
parent_reference_frame_transform: &LayerToWorldTransform,
parent_combined_viewport_rect: &LayerRect,
parent_scroll_offset: LayerVector2D,
parent_accumulated_scroll_offset: LayerVector2D) {
pub fn update_transform(&mut self, state: &TransformUpdateState) {
let scrolled_parent_combined_clip = state.parent_combined_viewport_rect
.translate(&-state.parent_scroll_offset);
let scrolled_parent_combined_clip = parent_combined_viewport_rect
.translate(&-parent_scroll_offset);
let (local_transform, combined_clip, reference_frame_scroll_offset) = match self.node_type {
NodeType::ReferenceFrame(transform) => {
let combined_clip = transform.with_destination::<LayerPixel>()
.inverse_rect_footprint(&scrolled_parent_combined_clip);
(transform, combined_clip, LayerVector2D::zero())
let (local_transform, accumulated_scroll_offset) = match self.node_type {
NodeType::ReferenceFrame(ref info) => {
self.combined_local_viewport_rect =
info.transform.with_destination::<LayerPixel>()
.inverse_rect_footprint(&scrolled_parent_combined_clip);
self.reference_frame_relative_scroll_offset = LayerVector2D::zero();
(info.transform, state.parent_accumulated_scroll_offset)
}
NodeType::Clip(_) | NodeType::ScrollFrame(_) => {
// Move the parent's viewport into the local space (of the node origin)
// and intersect with the local clip rectangle to get the local viewport.
let combined_clip = scrolled_parent_combined_clip.intersection(&self.local_clip_rect)
.unwrap_or(LayerRect::zero());
(LayerToScrollTransform::identity(), combined_clip, parent_accumulated_scroll_offset)
self.combined_local_viewport_rect =
scrolled_parent_combined_clip.intersection(&self.local_clip_rect)
.unwrap_or(LayerRect::zero());
self.reference_frame_relative_scroll_offset =
state.parent_accumulated_scroll_offset;
(LayerToScrollTransform::identity(), self.reference_frame_relative_scroll_offset)
}
NodeType::StickyFrame(sticky_frame_info) => {
let sticky_offset =
self.calculate_sticky_offset(&self.local_viewport_rect,
&sticky_frame_info,
&state.nearest_scrolling_ancestor_offset,
&state.nearest_scrolling_ancestor_viewport);
self.combined_local_viewport_rect =
scrolled_parent_combined_clip.translate(&-sticky_offset)
.intersection(&self.local_clip_rect)
.unwrap_or(LayerRect::zero());
self.reference_frame_relative_scroll_offset =
state.parent_accumulated_scroll_offset + sticky_offset;
(LayerToScrollTransform::identity(), self.reference_frame_relative_scroll_offset)
}
};
self.combined_local_viewport_rect = combined_clip;
self.reference_frame_relative_scroll_offset = reference_frame_scroll_offset;
// The transformation for this viewport in world coordinates is the transformation for
// our parent reference frame, plus any accumulated scrolling offsets from nodes
// between our reference frame and this node. For reference frames, we also include
// whatever local transformation this reference frame provides. This can be combined
// with the local_viewport_rect to get its position in world space.
self.world_viewport_transform =
parent_reference_frame_transform
.pre_translate(parent_accumulated_scroll_offset.to_3d())
state.parent_reference_frame_transform
.pre_translate(accumulated_scroll_offset.to_3d())
.pre_mul(&local_transform.with_destination::<LayerPixel>());
// The transformation for any content inside of us is the viewport transformation, plus
@ -275,6 +320,44 @@ impl ClipScrollNode {
self.world_viewport_transform.pre_translate(scroll_offset.to_3d());
}
fn calculate_sticky_offset(&self,
sticky_rect: &LayerRect,
sticky_frame_info: &StickyFrameInfo,
viewport_scroll_offset: &LayerVector2D,
viewport_rect: &LayerRect)
-> LayerVector2D {
let sticky_rect = sticky_rect.translate(viewport_scroll_offset);
let mut sticky_offset = LayerVector2D::zero();
if let Some(info) = sticky_frame_info.top {
sticky_offset.y = viewport_rect.min_y() + info.margin - sticky_rect.min_y();
sticky_offset.y = sticky_offset.y.max(0.0).min(info.max_offset);
}
if sticky_offset.y == 0.0 {
if let Some(info) = sticky_frame_info.bottom {
sticky_offset.y = (viewport_rect.max_y() - info.margin) -
(sticky_offset.y + sticky_rect.min_y() + sticky_rect.size.height);
sticky_offset.y = sticky_offset.y.min(0.0).max(info.max_offset);
}
}
if let Some(info) = sticky_frame_info.left {
sticky_offset.x = viewport_rect.min_x() + info.margin - sticky_rect.min_x();
sticky_offset.x = sticky_offset.x.max(0.0).min(info.max_offset);
}
if sticky_offset.x == 0.0 {
if let Some(info) = sticky_frame_info.right {
sticky_offset.x = (viewport_rect.max_x() - info.margin) -
(sticky_offset.x + sticky_rect.min_x() + sticky_rect.size.width);
sticky_offset.x = sticky_offset.x.min(0.0).max(info.max_offset);
}
}
sticky_offset
}
pub fn scrollable_height(&self) -> f32 {
self.content_size.height - self.local_viewport_rect.size.height
}
@ -288,8 +371,8 @@ impl ClipScrollNode {
let scrollable_height = self.scrollable_height();
let scrolling = match self.node_type {
NodeType::ReferenceFrame(_) | NodeType::Clip(_) => return false,
NodeType::ScrollFrame(ref mut scrolling) => scrolling,
_ => return false,
};
if scrolling.started_bouncing_back && phase == ScrollEventPhase::Move(false) {
@ -470,3 +553,15 @@ impl ScrollingState {
}
}
/// Contains information about reference frames.
#[derive(Copy, Clone, Debug)]
pub struct ReferenceFrameInfo {
/// The transformation that establishes this reference frame, relative to the parent
/// reference frame. The origin of the reference frame is included in the transformation.
pub transform: LayerToScrollTransform,
/// The original, not including the transform and relative to the parent reference frame,
/// origin of this reference frame. This is already rolled into the `transform' property, but
/// we also store it here to properly transform the viewport for sticky positioning.
pub origin_in_parent_reference_frame: LayerVector2D,
}

View File

@ -5,9 +5,9 @@
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollingState};
use internal_types::{FastHashSet, FastHashMap};
use print_tree::PrintTree;
use api::{ClipId, LayerPoint, LayerRect, LayerToScrollTransform};
use api::{LayerToWorldTransform, PipelineId, ScrollClamping, ScrollEventPhase};
use api::{LayerVector2D, ScrollLayerState, ScrollLocation, WorldPoint};
use api::{ClipId, LayerPoint, LayerRect, LayerToScrollTransform, LayerToWorldTransform};
use api::{LayerVector2D, PipelineId, ScrollClamping, ScrollEventPhase, ScrollLayerState};
use api::{ScrollLocation, StickyFrameInfo, WorldPoint};
pub type ScrollStates = FastHashMap<ClipId, ScrollingState>;
@ -37,6 +37,15 @@ pub struct ClipScrollTree {
pub pipelines_to_discard: FastHashSet<PipelineId>,
}
pub struct TransformUpdateState {
pub parent_reference_frame_transform: LayerToWorldTransform,
pub parent_combined_viewport_rect: LayerRect,
pub parent_scroll_offset: LayerVector2D,
pub parent_accumulated_scroll_offset: LayerVector2D,
pub nearest_scrolling_ancestor_offset: LayerVector2D,
pub nearest_scrolling_ancestor_viewport: LayerRect,
}
impl ClipScrollTree {
pub fn new() -> ClipScrollTree {
let dummy_pipeline = PipelineId::dummy();
@ -226,68 +235,62 @@ impl ClipScrollTree {
let root_reference_frame_id = self.root_reference_frame_id();
let root_viewport = self.nodes[&root_reference_frame_id].local_clip_rect;
self.update_node_transform(root_reference_frame_id,
&LayerToWorldTransform::create_translation(pan.x, pan.y, 0.0),
&root_viewport,
LayerVector2D::zero(),
LayerVector2D::zero());
let state = TransformUpdateState {
parent_reference_frame_transform:
LayerToWorldTransform::create_translation(pan.x, pan.y, 0.0),
parent_combined_viewport_rect: root_viewport,
parent_scroll_offset: LayerVector2D::zero(),
parent_accumulated_scroll_offset: LayerVector2D::zero(),
nearest_scrolling_ancestor_offset: LayerVector2D::zero(),
nearest_scrolling_ancestor_viewport: LayerRect::zero(),
};
self.update_node_transform(root_reference_frame_id, &state);
}
fn update_node_transform(&mut self,
layer_id: ClipId,
parent_reference_frame_transform: &LayerToWorldTransform,
parent_viewport_rect: &LayerRect,
parent_scroll_offset: LayerVector2D,
parent_accumulated_scroll_offset: LayerVector2D) {
fn update_node_transform(&mut self, layer_id: ClipId, state: &TransformUpdateState) {
// TODO(gw): This is an ugly borrow check workaround to clone these.
// Restructure this to avoid the clones!
let (reference_frame_transform,
combined_local_viewport_rect,
scroll_offset,
accumulated_scroll_offset,
node_children) = {
let (state, node_children) = {
let mut node = match self.nodes.get_mut(&layer_id) {
Some(node) => node,
None => return,
};
node.update_transform(parent_reference_frame_transform,
parent_viewport_rect,
parent_scroll_offset,
parent_accumulated_scroll_offset);
node.update_transform(&state);
// The transformation we are passing is the transformation of the parent
// reference frame and the offset is the accumulated offset of all the nodes
// between us and the parent reference frame. If we are a reference frame,
// we need to reset both these values.
let (reference_frame_transform, scroll_offset, accumulated_scroll_offset) = match node.node_type {
NodeType::ReferenceFrame(..) =>
(node.world_viewport_transform,
LayerVector2D::zero(),
LayerVector2D::zero()),
NodeType::Clip(..) =>
(*parent_reference_frame_transform,
LayerVector2D::zero(),
parent_accumulated_scroll_offset),
NodeType::ScrollFrame(ref scrolling) =>
(*parent_reference_frame_transform,
scrolling.offset,
scrolling.offset + parent_accumulated_scroll_offset),
let state = match node.node_type {
NodeType::ReferenceFrame(ref info) => TransformUpdateState {
parent_reference_frame_transform: node.world_viewport_transform,
parent_combined_viewport_rect: node.combined_local_viewport_rect,
parent_scroll_offset: LayerVector2D::zero(),
parent_accumulated_scroll_offset: LayerVector2D::zero(),
nearest_scrolling_ancestor_viewport:
state.nearest_scrolling_ancestor_viewport.translate(&info.origin_in_parent_reference_frame),
..*state
},
NodeType::Clip(..) | NodeType::StickyFrame(..) => TransformUpdateState {
parent_combined_viewport_rect: node.combined_local_viewport_rect,
parent_scroll_offset: LayerVector2D::zero(),
..*state
},
NodeType::ScrollFrame(ref scrolling) => TransformUpdateState {
parent_combined_viewport_rect: node.combined_local_viewport_rect,
parent_scroll_offset: scrolling.offset,
parent_accumulated_scroll_offset: scrolling.offset + state.parent_accumulated_scroll_offset,
nearest_scrolling_ancestor_offset: scrolling.offset,
nearest_scrolling_ancestor_viewport: node.local_viewport_rect,
..*state
},
};
(reference_frame_transform,
node.combined_local_viewport_rect,
scroll_offset,
accumulated_scroll_offset,
node.children.clone())
(state, node.children.clone())
};
for child_layer_id in node_children {
self.update_node_transform(child_layer_id,
&reference_frame_transform,
&combined_local_viewport_rect,
scroll_offset,
accumulated_scroll_offset);
self.update_node_transform(child_layer_id, &state);
}
}
@ -320,6 +323,7 @@ impl ClipScrollTree {
pub fn add_reference_frame(&mut self,
rect: &LayerRect,
transform: &LayerToScrollTransform,
origin_in_parent_reference_frame: LayerVector2D,
pipeline_id: PipelineId,
parent_id: Option<ClipId>)
-> ClipId {
@ -328,11 +332,24 @@ impl ClipScrollTree {
rect,
rect.size,
transform,
origin_in_parent_reference_frame,
pipeline_id);
self.add_node(node, reference_frame_id);
reference_frame_id
}
pub fn add_sticky_frame(&mut self,
id: ClipId,
parent_id: ClipId,
frame_rect: LayerRect,
sticky_frame_info: StickyFrameInfo) {
let node = ClipScrollNode::new_sticky_frame(parent_id,
frame_rect,
sticky_frame_info,
id.pipeline_id());
self.add_node(node, id);
}
pub fn add_node(&mut self, node: ClipScrollNode, id: ClipId) {
// When the parent node is None this means we are adding the root.
match node.parent {
@ -368,13 +385,17 @@ impl ClipScrollTree {
}
pt.end_level();
}
NodeType::ReferenceFrame(ref transform) => {
pt.new_level(format!("ReferenceFrame {:?}", transform));
NodeType::ReferenceFrame(ref info) => {
pt.new_level(format!("ReferenceFrame {:?}", info.transform));
}
NodeType::ScrollFrame(scrolling_info) => {
pt.new_level(format!("ScrollFrame"));
pt.add_item(format!("scroll.offset: {:?}", scrolling_info.offset));
}
NodeType::StickyFrame(sticky_frame_info) => {
pt.new_level(format!("StickyFrame"));
pt.add_item(format!("sticky info: {:?}", sticky_frame_info));
}
}
pt.add_item(format!("content_size: {:?}", node.content_size));

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use debug_font_data;
use device::{Device, GpuMarker, Program, VAOId, TextureId, VertexDescriptor};
use device::{Device, GpuMarker, Program, VAO, TextureId, VertexDescriptor};
use device::{TextureFilter, VertexAttribute, VertexUsageHint, VertexAttributeKind, TextureTarget};
use euclid::{Transform3D, Point2D, Size2D, Rect};
use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, TextureSampler};
@ -70,14 +70,14 @@ pub struct DebugRenderer {
font_vertices: Vec<DebugFontVertex>,
font_indices: Vec<u32>,
font_program: Program,
font_vao: VAOId,
font_vao: VAO,
font_texture_id: TextureId,
tri_vertices: Vec<DebugColorVertex>,
tri_indices: Vec<u32>,
tri_vao: VAOId,
tri_vao: VAO,
line_vertices: Vec<DebugColorVertex>,
line_vao: VAOId,
line_vao: VAO,
color_program: Program,
}
@ -90,13 +90,14 @@ impl DebugRenderer {
let line_vao = device.create_vao(&DESC_COLOR, 32);
let tri_vao = device.create_vao(&DESC_COLOR, 32);
let font_texture_id = device.create_texture_ids(1, TextureTarget::Default)[0];
let font_texture_id = device.create_texture_ids(1, TextureTarget::Array)[0];
device.init_texture(font_texture_id,
debug_font_data::BMP_WIDTH,
debug_font_data::BMP_HEIGHT,
ImageFormat::A8,
TextureFilter::Linear,
RenderTargetMode::None,
1,
Some(&debug_font_data::FONT_BITMAP));
DebugRenderer {
@ -114,9 +115,12 @@ impl DebugRenderer {
}
}
pub fn deinit(&mut self, device: &mut Device) {
device.delete_program(&mut self.font_program);
device.delete_program(&mut self.color_program);
pub fn deinit(self, device: &mut Device) {
device.delete_program(self.font_program);
device.delete_program(self.color_program);
device.delete_vao(self.tri_vao);
device.delete_vao(self.line_vao);
device.delete_vao(self.font_vao);
}
pub fn line_height(&self) -> f32 {
@ -232,11 +236,11 @@ impl DebugRenderer {
if !self.tri_vertices.is_empty() {
device.bind_program(&self.color_program);
device.set_uniforms(&self.color_program, &projection);
device.bind_vao(self.tri_vao);
device.update_vao_indices(self.tri_vao,
device.bind_vao(&self.tri_vao);
device.update_vao_indices(&self.tri_vao,
&self.tri_indices,
VertexUsageHint::Dynamic);
device.update_vao_main_vertices(self.tri_vao,
device.update_vao_main_vertices(&self.tri_vao,
&self.tri_vertices,
VertexUsageHint::Dynamic);
device.draw_triangles_u32(0, self.tri_indices.len() as i32);
@ -246,8 +250,8 @@ impl DebugRenderer {
if !self.line_vertices.is_empty() {
device.bind_program(&self.color_program);
device.set_uniforms(&self.color_program, &projection);
device.bind_vao(self.line_vao);
device.update_vao_main_vertices(self.line_vao,
device.bind_vao(&self.line_vao);
device.update_vao_main_vertices(&self.line_vao,
&self.line_vertices,
VertexUsageHint::Dynamic);
device.draw_nonindexed_lines(0, self.line_vertices.len() as i32);
@ -258,11 +262,11 @@ impl DebugRenderer {
device.bind_program(&self.font_program);
device.set_uniforms(&self.font_program, &projection);
device.bind_texture(TextureSampler::Color0, self.font_texture_id);
device.bind_vao(self.font_vao);
device.update_vao_indices(self.font_vao,
device.bind_vao(&self.font_vao);
device.update_vao_indices(&self.font_vao,
&self.font_indices,
VertexUsageHint::Dynamic);
device.update_vao_main_vertices(self.font_vao,
device.update_vao_main_vertices(&self.font_vao,
&self.font_vertices,
VertexUsageHint::Dynamic);
device.draw_triangles_u32(0, self.font_indices.len() as i32);

View File

@ -5,7 +5,6 @@
use euclid::Transform3D;
use gleam::gl;
use internal_types::{RenderTargetMode, TextureSampler, DEFAULT_TEXTURE, FastHashMap};
//use notify::{self, Watcher};
use super::shader_source;
use std::fs::File;
use std::io::Read;
@ -15,7 +14,6 @@ use std::ops::Add;
use std::path::PathBuf;
use std::ptr;
use std::rc::Rc;
//use std::sync::mpsc::{channel, Sender};
use std::thread;
use api::{ColorF, ImageFormat};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintSize};
@ -89,6 +87,7 @@ pub enum VertexAttributeKind {
F32,
U8Norm,
I32,
U16,
}
#[derive(Debug)]
@ -159,6 +158,7 @@ impl VertexAttributeKind {
VertexAttributeKind::F32 => 4,
VertexAttributeKind::U8Norm => 1,
VertexAttributeKind::I32 => 4,
VertexAttributeKind::U16 => 2,
}
}
}
@ -201,6 +201,13 @@ impl VertexAttribute {
stride,
offset);
}
VertexAttributeKind::U16 => {
gl.vertex_attrib_i_pointer(attr_index,
self.count as gl::GLint,
gl::UNSIGNED_SHORT,
stride,
offset);
}
}
}
}
@ -296,6 +303,7 @@ impl FBOId {
struct Texture {
gl: Rc<gl::Gl>,
id: gl::GLuint,
layer_count: i32,
format: ImageFormat,
width: u32,
height: u32,
@ -361,36 +369,22 @@ impl Program {
impl Drop for Program {
fn drop(&mut self) {
debug_assert!(thread::panicking() || self.id == 0);
debug_assert!(thread::panicking() || self.id == 0, "renderer::deinit not called");
}
}
struct VAO {
gl: Rc<gl::Gl>,
pub struct VAO {
id: gl::GLuint,
ibo_id: IBOId,
main_vbo_id: VBOId,
instance_vbo_id: VBOId,
instance_stride: gl::GLint,
owns_indices: bool,
owns_vertices: bool,
owns_instances: bool,
owns_vertices_and_indices: bool,
}
impl Drop for VAO {
fn drop(&mut self) {
self.gl.delete_vertex_arrays(&[self.id]);
if self.owns_indices {
// todo(gw): maybe make these their own type with hashmap?
self.gl.delete_buffers(&[self.ibo_id.0]);
}
if self.owns_vertices {
self.gl.delete_buffers(&[self.main_vbo_id.0]);
}
if self.owns_instances {
self.gl.delete_buffers(&[self.instance_vbo_id.0])
}
debug_assert!(thread::panicking() || self.id == 0, "renderer::deinit not called");
}
}
@ -400,9 +394,6 @@ pub struct TextureId {
target: gl::GLuint,
}
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub struct VAOId(gl::GLuint);
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub struct FBOId(gl::GLuint);
@ -690,75 +681,6 @@ impl UniformLocation {
}
}
// TODO(gw): Fix up notify cargo deps and re-enable this!
/*
enum FileWatcherCmd {
AddWatch(PathBuf),
Exit,
}
struct FileWatcherThread {
api_tx: Sender<FileWatcherCmd>,
}
impl FileWatcherThread {
fn new(handler: Box<FileWatcherHandler>) -> FileWatcherThread {
let (api_tx, api_rx) = channel();
thread::spawn(move || {
let (watch_tx, watch_rx) = channel();
enum Request {
Watcher(notify::Event),
Command(FileWatcherCmd),
}
let mut file_watcher: notify::RecommendedWatcher = notify::Watcher::new(watch_tx).unwrap();
loop {
let request = {
let receiver_from_api = &api_rx;
let receiver_from_watcher = &watch_rx;
select! {
msg = receiver_from_api.recv() => Request::Command(msg.unwrap()),
msg = receiver_from_watcher.recv() => Request::Watcher(msg.unwrap())
}
};
match request {
Request::Watcher(event) => {
handler.file_changed(event.path.unwrap());
}
Request::Command(cmd) => {
match cmd {
FileWatcherCmd::AddWatch(path) => {
file_watcher.watch(path).ok();
}
FileWatcherCmd::Exit => {
break;
}
}
}
}
}
});
FileWatcherThread {
api_tx,
}
}
fn exit(&self) {
self.api_tx.send(FileWatcherCmd::Exit).ok();
}
fn add_watch(&self, path: PathBuf) {
self.api_tx.send(FileWatcherCmd::AddWatch(path)).ok();
}
}
*/
pub struct Capabilities {
pub supports_multisampling: bool,
}
@ -774,7 +696,7 @@ pub struct Device {
// device state
bound_textures: [TextureId; 16],
bound_program: gl::GLuint,
bound_vao: VAOId,
bound_vao: gl::GLuint,
bound_pbo: PBOId,
bound_read_fbo: FBOId,
bound_draw_fbo: FBOId,
@ -791,15 +713,9 @@ pub struct Device {
// resources
resource_override_path: Option<PathBuf>,
textures: FastHashMap<TextureId, Texture>,
vaos: FastHashMap<VAOId, VAO>,
// misc.
shader_preamble: String,
//file_watcher: FileWatcherThread,
// Used on android only
#[allow(dead_code)]
next_vao_id: gl::GLuint,
max_texture_size: u32,
@ -812,11 +728,7 @@ impl Device {
pub fn new(gl: Rc<gl::Gl>,
resource_override_path: Option<PathBuf>,
_file_changed_handler: Box<FileWatcherHandler>) -> Device {
//let file_watcher = FileWatcherThread::new(file_changed_handler);
let shader_preamble = get_shader_source(SHADER_PREAMBLE, &resource_override_path);
//file_watcher.add_watch(resource_path);
let max_texture_size = gl.get_integer_v(gl::MAX_TEXTURE_SIZE) as u32;
Device {
@ -833,7 +745,7 @@ impl Device {
bound_textures: [ TextureId::invalid(); 16 ],
bound_program: 0,
bound_vao: VAOId(0),
bound_vao: 0,
bound_pbo: PBOId(0),
bound_read_fbo: FBOId(0),
bound_draw_fbo: FBOId(0),
@ -841,13 +753,9 @@ impl Device {
default_draw_fbo: 0,
textures: FastHashMap::default(),
vaos: FastHashMap::default(),
shader_preamble,
next_vao_id: 1,
//file_watcher: file_watcher,
max_texture_size,
frame_id: FrameId(0),
}
@ -924,8 +832,8 @@ impl Device {
self.gl.use_program(0);
// Vertex state
self.bound_vao = VAOId(0);
self.clear_vertex_array();
self.bound_vao = 0;
self.gl.bind_vertex_array(0);
// FBO state
self.bound_read_fbo = FBOId(self.default_read_fbo);
@ -1014,6 +922,7 @@ impl Device {
id,
width: 0,
height: 0,
layer_count: 0,
format: ImageFormat::Invalid,
filter: TextureFilter::Nearest,
mode: RenderTargetMode::None,
@ -1030,6 +939,11 @@ impl Device {
texture_ids
}
pub fn get_texture_layer_count(&self, texture_id: TextureId) -> i32 {
let texture = &self.textures[&texture_id];
texture.layer_count
}
pub fn get_texture_dimensions(&self, texture_id: TextureId) -> DeviceUintSize {
let texture = &self.textures[&texture_id];
DeviceUintSize::new(texture.width, texture.height)
@ -1052,24 +966,6 @@ impl Device {
self.gl.tex_parameter_i(target, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as gl::GLint);
}
fn upload_texture_image(&mut self,
target: gl::GLuint,
width: u32,
height: u32,
internal_format: u32,
format: u32,
type_: u32,
pixels: Option<&[u8]>) {
self.gl.tex_image_2d(target,
0,
internal_format as gl::GLint,
width as gl::GLint, height as gl::GLint,
0,
format,
type_,
pixels);
}
pub fn init_texture(&mut self,
texture_id: TextureId,
width: u32,
@ -1077,6 +973,7 @@ impl Device {
format: ImageFormat,
filter: TextureFilter,
mode: RenderTargetMode,
layer_count: i32,
pixels: Option<&[u8]>) {
debug_assert!(self.inside_frame);
@ -1088,6 +985,7 @@ impl Device {
texture.width = width;
texture.height = height;
texture.filter = filter;
texture.layer_count = layer_count;
texture.mode = mode;
}
@ -1095,22 +993,10 @@ impl Device {
let type_ = gl_type_for_texture_format(format);
match mode {
RenderTargetMode::SimpleRenderTarget => {
RenderTargetMode::RenderTarget => {
self.bind_texture(DEFAULT_TEXTURE, texture_id);
self.set_texture_parameters(texture_id.target, filter);
self.upload_texture_image(texture_id.target,
width,
height,
internal_format as u32,
gl_format,
type_,
None);
self.update_texture_storage(texture_id, None, resized);
}
RenderTargetMode::LayerRenderTarget(layer_count) => {
self.bind_texture(DEFAULT_TEXTURE, texture_id);
self.set_texture_parameters(texture_id.target, filter);
self.update_texture_storage(texture_id, Some(layer_count), resized);
self.update_texture_storage(texture_id, layer_count, resized);
}
RenderTargetMode::None => {
self.bind_texture(DEFAULT_TEXTURE, texture_id);
@ -1124,13 +1010,34 @@ impl Device {
} else {
pixels
};
self.upload_texture_image(texture_id.target,
width,
height,
internal_format as u32,
gl_format,
type_,
actual_pixels);
match texture_id.target {
gl::TEXTURE_2D_ARRAY => {
self.gl.tex_image_3d(gl::TEXTURE_2D_ARRAY,
0,
internal_format as gl::GLint,
width as gl::GLint,
height as gl::GLint,
layer_count,
0,
gl_format,
type_,
actual_pixels);
}
gl::TEXTURE_2D |
gl::TEXTURE_RECTANGLE |
gl::TEXTURE_EXTERNAL_OES => {
self.gl.tex_image_2d(texture_id.target,
0,
internal_format as gl::GLint,
width as gl::GLint, height as gl::GLint,
0,
gl_format,
type_,
actual_pixels);
}
_ => panic!("BUG: Unexpected texture target!"),
}
}
}
}
@ -1143,92 +1050,70 @@ impl Device {
/// FBOs as required.
pub fn update_texture_storage(&mut self,
texture_id: TextureId,
layer_count: Option<i32>,
layer_count: i32,
resized: bool) {
let texture = self.textures.get_mut(&texture_id).unwrap();
match layer_count {
Some(layer_count) => {
assert!(layer_count > 0);
assert_eq!(texture_id.target, gl::TEXTURE_2D_ARRAY);
assert!(layer_count > 0);
assert_eq!(texture_id.target, gl::TEXTURE_2D_ARRAY);
let current_layer_count = texture.fbo_ids.len() as i32;
// If the texture is already the required size skip.
if current_layer_count == layer_count && !resized {
return;
}
let current_layer_count = texture.fbo_ids.len() as i32;
// If the texture is already the required size skip.
if current_layer_count == layer_count && !resized {
return;
}
let (internal_format, gl_format) = gl_texture_formats_for_image_format(&*self.gl, texture.format);
let type_ = gl_type_for_texture_format(texture.format);
let (internal_format, gl_format) = gl_texture_formats_for_image_format(&*self.gl, texture.format);
let type_ = gl_type_for_texture_format(texture.format);
self.gl.tex_image_3d(texture_id.target,
0,
internal_format as gl::GLint,
texture.width as gl::GLint,
texture.height as gl::GLint,
layer_count,
0,
gl_format,
type_,
None);
self.gl.tex_image_3d(texture_id.target,
0,
internal_format as gl::GLint,
texture.width as gl::GLint,
texture.height as gl::GLint,
layer_count,
0,
gl_format,
type_,
None);
let needed_layer_count = layer_count - current_layer_count;
if needed_layer_count > 0 {
// Create more framebuffers to fill the gap
let new_fbos = self.gl.gen_framebuffers(needed_layer_count);
texture.fbo_ids.extend(new_fbos.into_iter().map(|id| FBOId(id)));
} else if needed_layer_count < 0 {
// Remove extra framebuffers
for old in texture.fbo_ids.drain(layer_count as usize ..) {
self.gl.delete_framebuffers(&[old.0]);
}
}
let depth_rb = if let Some(rbo) = texture.depth_rb {
rbo.0
} else {
let renderbuffer_ids = self.gl.gen_renderbuffers(1);
let depth_rb = renderbuffer_ids[0];
texture.depth_rb = Some(RBOId(depth_rb));
depth_rb
};
self.gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
self.gl.renderbuffer_storage(gl::RENDERBUFFER,
gl::DEPTH_COMPONENT24,
texture.width as gl::GLsizei,
texture.height as gl::GLsizei);
for (fbo_index, fbo_id) in texture.fbo_ids.iter().enumerate() {
self.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo_id.0);
self.gl.framebuffer_texture_layer(gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
texture_id.name,
0,
fbo_index as gl::GLint);
self.gl.framebuffer_renderbuffer(gl::FRAMEBUFFER,
gl::DEPTH_ATTACHMENT,
gl::RENDERBUFFER,
depth_rb);
}
let needed_layer_count = layer_count - current_layer_count;
if needed_layer_count > 0 {
// Create more framebuffers to fill the gap
let new_fbos = self.gl.gen_framebuffers(needed_layer_count);
texture.fbo_ids.extend(new_fbos.into_iter().map(|id| FBOId(id)));
} else if needed_layer_count < 0 {
// Remove extra framebuffers
for old in texture.fbo_ids.drain(layer_count as usize ..) {
self.gl.delete_framebuffers(&[old.0]);
}
None => {
if texture.fbo_ids.is_empty() {
assert!(texture_id.target != gl::TEXTURE_2D_ARRAY);
}
let new_fbo = self.gl.gen_framebuffers(1)[0];
self.gl.bind_framebuffer(gl::FRAMEBUFFER, new_fbo);
let depth_rb = if let Some(rbo) = texture.depth_rb {
rbo.0
} else {
let renderbuffer_ids = self.gl.gen_renderbuffers(1);
let depth_rb = renderbuffer_ids[0];
texture.depth_rb = Some(RBOId(depth_rb));
depth_rb
};
self.gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
self.gl.renderbuffer_storage(gl::RENDERBUFFER,
gl::DEPTH_COMPONENT24,
texture.width as gl::GLsizei,
texture.height as gl::GLsizei);
self.gl.framebuffer_texture_2d(gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
texture_id.target,
texture_id.name,
0);
texture.fbo_ids.push(FBOId(new_fbo));
} else {
assert_eq!(texture.fbo_ids.len(), 1);
}
}
for (fbo_index, fbo_id) in texture.fbo_ids.iter().enumerate() {
self.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo_id.0);
self.gl.framebuffer_texture_layer(gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
texture_id.name,
0,
fbo_index as gl::GLint);
self.gl.framebuffer_renderbuffer(gl::FRAMEBUFFER,
gl::DEPTH_ATTACHMENT,
gl::RENDERBUFFER,
depth_rb);
}
// TODO(gw): Hack! Modify the code above to use the normal binding interfaces the device exposes.
@ -1263,52 +1148,6 @@ impl Device {
gl::LINEAR);
}
pub fn resize_texture(&mut self,
texture_id: TextureId,
new_width: u32,
new_height: u32,
format: ImageFormat,
filter: TextureFilter,
mode: RenderTargetMode) {
debug_assert!(self.inside_frame);
let old_size = self.get_texture_dimensions(texture_id);
let temp_texture_id = self.create_texture_ids(1, TextureTarget::Default)[0];
self.init_texture(temp_texture_id, old_size.width, old_size.height, format, filter, mode, None);
self.update_texture_storage(temp_texture_id, None, true);
self.bind_read_target(Some((texture_id, 0)));
self.bind_texture(DEFAULT_TEXTURE, temp_texture_id);
self.gl.copy_tex_sub_image_2d(temp_texture_id.target,
0,
0,
0,
0,
0,
old_size.width as i32,
old_size.height as i32);
self.deinit_texture(texture_id);
self.init_texture(texture_id, new_width, new_height, format, filter, mode, None);
self.update_texture_storage(texture_id, None, true);
self.bind_read_target(Some((temp_texture_id, 0)));
self.bind_texture(DEFAULT_TEXTURE, texture_id);
self.gl.copy_tex_sub_image_2d(texture_id.target,
0,
0,
0,
0,
0,
old_size.width as i32,
old_size.height as i32);
self.bind_read_target(None);
self.deinit_texture(temp_texture_id);
}
pub fn deinit_texture(&mut self, texture_id: TextureId) {
debug_assert!(self.inside_frame);
@ -1318,15 +1157,32 @@ impl Device {
let (internal_format, gl_format) = gl_texture_formats_for_image_format(&*self.gl, texture.format);
let type_ = gl_type_for_texture_format(texture.format);
self.gl.tex_image_2d(texture_id.target,
0,
internal_format,
0,
0,
0,
gl_format,
type_,
None);
match texture_id.target {
gl::TEXTURE_2D_ARRAY => {
self.gl.tex_image_3d(gl::TEXTURE_2D_ARRAY,
0,
internal_format as gl::GLint,
0,
0,
0,
0,
gl_format,
type_,
None);
}
_ => {
self.gl.tex_image_2d(texture_id.target,
0,
internal_format,
0,
0,
0,
gl_format,
type_,
None);
}
}
if let Some(RBOId(depth_rb)) = texture.depth_rb.take() {
self.gl.delete_renderbuffers(&[depth_rb]);
@ -1340,6 +1196,7 @@ impl Device {
texture.format = ImageFormat::Invalid;
texture.width = 0;
texture.height = 0;
texture.layer_count = 0;
}
pub fn create_program(&mut self,
@ -1352,7 +1209,7 @@ impl Device {
descriptor)
}
pub fn delete_program(&mut self, program: &mut Program) {
pub fn delete_program(&mut self, mut program: Program) {
self.gl.delete_program(program.id);
program.id = 0;
}
@ -1507,43 +1364,6 @@ impl Device {
Ok(())
}
/*
pub fn refresh_shader(&mut self, path: PathBuf) {
let mut vs_preamble_path = self.resource_path.clone();
vs_preamble_path.push(VERTEX_SHADER_PREAMBLE);
let mut fs_preamble_path = self.resource_path.clone();
fs_preamble_path.push(FRAGMENT_SHADER_PREAMBLE);
let mut refresh_all = false;
if path == vs_preamble_path {
let mut f = File::open(&vs_preamble_path).unwrap();
self.vertex_shader_preamble = String::new();
f.read_to_string(&mut self.vertex_shader_preamble).unwrap();
refresh_all = true;
}
if path == fs_preamble_path {
let mut f = File::open(&fs_preamble_path).unwrap();
self.fragment_shader_preamble = String::new();
f.read_to_string(&mut self.fragment_shader_preamble).unwrap();
refresh_all = true;
}
let mut programs_to_update = Vec::new();
for (program_id, program) in &mut self.programs {
if refresh_all || program.vs_path == path || program.fs_path == path {
programs_to_update.push(*program_id)
}
}
for program_id in programs_to_update {
self.load_program(program_id, false);
}
}*/
pub fn get_uniform_location(&self, program: &Program, name: &str) -> UniformLocation {
UniformLocation(self.gl.get_uniform_location(program.id, name))
}
@ -1610,48 +1430,17 @@ impl Device {
y0: u32,
width: u32,
height: u32,
layer_index: i32,
stride: Option<u32>,
offset: usize) {
debug_assert!(self.inside_frame);
debug_assert_eq!(self.textures.get(&texture_id).unwrap().format, ImageFormat::RGBAF32);
self.bind_texture(DEFAULT_TEXTURE, texture_id);
self.gl.tex_sub_image_2d_pbo(texture_id.target,
0,
x0 as gl::GLint,
y0 as gl::GLint,
width as gl::GLint,
height as gl::GLint,
gl::RGBA,
gl::FLOAT,
offset);
}
pub fn update_texture(&mut self,
texture_id: TextureId,
x0: u32,
y0: u32,
width: u32,
height: u32,
stride: Option<u32>,
data: &[u8]) {
debug_assert!(self.inside_frame);
let mut expanded_data = Vec::new();
let (gl_format, bpp, data, data_type) = match self.textures.get(&texture_id).unwrap().format {
ImageFormat::A8 => {
if cfg!(any(target_arch="arm", target_arch="aarch64")) {
expanded_data.extend(data.iter().flat_map(|byte| repeat(*byte).take(4)));
(get_gl_format_bgra(self.gl()), 4, expanded_data.as_slice(), gl::UNSIGNED_BYTE)
} else {
(GL_FORMAT_A, 1, data, gl::UNSIGNED_BYTE)
}
}
ImageFormat::RGB8 => (gl::RGB, 3, data, gl::UNSIGNED_BYTE),
ImageFormat::BGRA8 => (get_gl_format_bgra(self.gl()), 4, data, gl::UNSIGNED_BYTE),
ImageFormat::RG8 => (gl::RG, 2, data, gl::UNSIGNED_BYTE),
ImageFormat::RGBAF32 => (gl::RGBA, 16, data, gl::FLOAT),
let (gl_format, bpp, data_type) = match self.textures.get(&texture_id).unwrap().format {
ImageFormat::A8 => (GL_FORMAT_A, 1, gl::UNSIGNED_BYTE),
ImageFormat::RGB8 => (gl::RGB, 3, gl::UNSIGNED_BYTE),
ImageFormat::BGRA8 => (get_gl_format_bgra(self.gl()), 4, gl::UNSIGNED_BYTE),
ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE),
ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT),
ImageFormat::Invalid => unreachable!(),
};
@ -1660,26 +1449,41 @@ impl Device {
None => width,
};
// Take the stride into account for all rows, except the last one.
let len = bpp * row_length * (height - 1)
+ width * bpp;
let data = &data[0..len as usize];
if let Some(..) = stride {
self.gl.pixel_store_i(gl::UNPACK_ROW_LENGTH, row_length as gl::GLint);
}
self.bind_texture(DEFAULT_TEXTURE, texture_id);
self.gl.tex_sub_image_2d(texture_id.target,
0,
x0 as gl::GLint,
y0 as gl::GLint,
width as gl::GLint,
height as gl::GLint,
gl_format,
data_type,
data);
match texture_id.target {
gl::TEXTURE_2D_ARRAY => {
self.gl.tex_sub_image_3d_pbo(texture_id.target,
0,
x0 as gl::GLint,
y0 as gl::GLint,
layer_index,
width as gl::GLint,
height as gl::GLint,
1,
gl_format,
data_type,
offset);
}
gl::TEXTURE_2D |
gl::TEXTURE_RECTANGLE |
gl::TEXTURE_EXTERNAL_OES => {
self.gl.tex_sub_image_2d_pbo(texture_id.target,
0,
x0 as gl::GLint,
y0 as gl::GLint,
width as gl::GLint,
height as gl::GLint,
gl_format,
data_type,
offset);
}
_ => panic!("BUG: Unexpected texture target!"),
}
// Reset row length to 0, otherwise the stride would apply to all texture uploads.
if let Some(..) = stride {
@ -1687,19 +1491,12 @@ impl Device {
}
}
fn clear_vertex_array(&mut self) {
debug_assert!(self.inside_frame);
self.gl.bind_vertex_array(0);
}
pub fn bind_vao(&mut self, vao_id: VAOId) {
pub fn bind_vao(&mut self, vao: &VAO) {
debug_assert!(self.inside_frame);
if self.bound_vao != vao_id {
self.bound_vao = vao_id;
let VAOId(id) = vao_id;
self.gl.bind_vertex_array(id);
if self.bound_vao != vao.id {
self.bound_vao = vao.id;
self.gl.bind_vertex_array(vao.id);
}
}
@ -1709,14 +1506,11 @@ impl Device {
instance_vbo_id: VBOId,
ibo_id: IBOId,
instance_stride: gl::GLint,
owns_vertices: bool,
owns_instances: bool,
owns_indices: bool)
-> VAOId {
owns_vertices_and_indices: bool)
-> VAO {
debug_assert!(self.inside_frame);
let vao_ids = self.gl.gen_vertex_arrays(1);
let vao_id = vao_ids[0];
let vao_id = self.gl.gen_vertex_arrays(1)[0];
self.gl.bind_vertex_array(vao_id);
@ -1724,30 +1518,22 @@ impl Device {
ibo_id.bind(self.gl()); // force it to be a part of VAO
let vao = VAO {
gl: Rc::clone(&self.gl),
id: vao_id,
ibo_id,
main_vbo_id,
instance_vbo_id,
instance_stride,
owns_indices,
owns_vertices,
owns_instances,
owns_vertices_and_indices,
};
self.gl.bind_vertex_array(0);
let vao_id = VAOId(vao_id);
debug_assert!(!self.vaos.contains_key(&vao_id));
self.vaos.insert(vao_id, vao);
vao_id
vao
}
pub fn create_vao(&mut self,
descriptor: &VertexDescriptor,
inst_stride: gl::GLint) -> VAOId {
inst_stride: gl::GLint) -> VAO {
debug_assert!(self.inside_frame);
let buffer_ids = self.gl.gen_buffers(3);
@ -1760,55 +1546,55 @@ impl Device {
intance_vbo_id,
ibo_id,
inst_stride,
true,
true,
true)
}
pub fn delete_vao(&mut self, mut vao: VAO) {
self.gl.delete_vertex_arrays(&[vao.id]);
vao.id = 0;
if vao.owns_vertices_and_indices {
self.gl.delete_buffers(&[vao.ibo_id.0]);
self.gl.delete_buffers(&[vao.main_vbo_id.0]);
}
self.gl.delete_buffers(&[vao.instance_vbo_id.0])
}
pub fn create_vao_with_new_instances(&mut self,
descriptor: &VertexDescriptor,
inst_stride: gl::GLint,
base_vao: VAOId) -> VAOId {
base_vao: &VAO) -> VAO {
debug_assert!(self.inside_frame);
let buffer_ids = self.gl.gen_buffers(1);
let intance_vbo_id = VBOId(buffer_ids[0]);
let (main_vbo_id, ibo_id) = {
let vao = self.vaos.get(&base_vao).unwrap();
(vao.main_vbo_id, vao.ibo_id)
};
self.create_vao_with_vbos(descriptor,
main_vbo_id,
base_vao.main_vbo_id,
intance_vbo_id,
ibo_id,
base_vao.ibo_id,
inst_stride,
false,
true,
false)
}
pub fn update_vao_main_vertices<V>(&mut self,
vao_id: VAOId,
vao: &VAO,
vertices: &[V],
usage_hint: VertexUsageHint) {
debug_assert!(self.inside_frame);
let vao = self.vaos.get(&vao_id).unwrap();
debug_assert_eq!(self.bound_vao, vao_id);
debug_assert_eq!(self.bound_vao, vao.id);
vao.main_vbo_id.bind(self.gl());
gl::buffer_data(self.gl(), gl::ARRAY_BUFFER, vertices, usage_hint.to_gl());
}
pub fn update_vao_instances<V>(&mut self,
vao_id: VAOId,
vao: &VAO,
instances: &[V],
usage_hint: VertexUsageHint) {
debug_assert!(self.inside_frame);
let vao = self.vaos.get(&vao_id).unwrap();
debug_assert_eq!(self.bound_vao, vao_id);
debug_assert_eq!(self.bound_vao, vao.id);
debug_assert_eq!(vao.instance_stride as usize, mem::size_of::<V>());
vao.instance_vbo_id.bind(self.gl());
@ -1816,13 +1602,11 @@ impl Device {
}
pub fn update_vao_indices<I>(&mut self,
vao_id: VAOId,
vao: &VAO,
indices: &[I],
usage_hint: VertexUsageHint) {
debug_assert!(self.inside_frame);
let vao = self.vaos.get(&vao_id).unwrap();
debug_assert_eq!(self.bound_vao, vao_id);
debug_assert_eq!(self.bound_vao, vao.id);
vao.ibo_id.bind(self.gl());
gl::buffer_data(self.gl(), gl::ELEMENT_ARRAY_BUFFER, indices, usage_hint.to_gl());
@ -1991,12 +1775,6 @@ impl Device {
}
}
impl Drop for Device {
fn drop(&mut self) {
//self.file_watcher.exit();
}
}
/// return (gl_internal_format, gl_format)
fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl::GLint, gl::GLuint) {
match format {

View File

@ -21,7 +21,7 @@ use scene::{Scene, SceneProperties};
use tiling::{CompositeOps, DisplayListMap, PrimitiveFlags};
use util::{ComplexClipRegionHelpers, subtract_rect};
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Eq, Ord)]
pub struct FrameId(pub u32);
static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6 };
@ -410,11 +410,9 @@ impl Frame {
let transform = context.scene.properties.resolve_layout_transform(transform);
let perspective =
stacking_context.perspective.unwrap_or_else(LayoutTransform::identity);
let origin = reference_frame_relative_offset + bounds.origin.to_vector();
let transform =
LayerToScrollTransform::create_translation(reference_frame_relative_offset.x,
reference_frame_relative_offset.y,
0.0)
.pre_translate(bounds.origin.to_vector().to_3d())
LayerToScrollTransform::create_translation(origin.x, origin.y, 0.0)
.pre_mul(&transform)
.pre_mul(&perspective);
@ -424,6 +422,7 @@ impl Frame {
pipeline_id,
&reference_frame_bounds,
&transform,
origin,
&mut self.clip_scroll_tree);
context.replacements.push((context_scroll_node_id, clip_id));
reference_frame_relative_offset = LayerVector2D::zero();
@ -485,16 +484,14 @@ impl Frame {
self.pipeline_epoch_map.insert(pipeline_id, pipeline.epoch);
let iframe_rect = LayerRect::new(LayerPoint::zero(), bounds.size);
let transform = LayerToScrollTransform::create_translation(
reference_frame_relative_offset.x + bounds.origin.x,
reference_frame_relative_offset.y + bounds.origin.y,
0.0);
let origin = reference_frame_relative_offset + bounds.origin.to_vector();
let transform = LayerToScrollTransform::create_translation(origin.x, origin.y, 0.0);
let iframe_reference_frame_id =
context.builder.push_reference_frame(Some(clip_id),
pipeline_id,
&iframe_rect,
&transform,
origin,
&mut self.clip_scroll_tree);
context.builder.add_scroll_frame(
@ -528,12 +525,6 @@ impl Frame {
let item_rect_with_offset = item.rect().translate(&reference_frame_relative_offset);
let clip_with_offset = item.local_clip_with_offset(&reference_frame_relative_offset);
match *item.item() {
SpecificDisplayItem::WebGL(ref info) => {
context.builder.add_webgl_rectangle(clip_and_scroll,
item_rect_with_offset,
&clip_with_offset,
info.context_id);
}
SpecificDisplayItem::Image(ref info) => {
if let Some(tiling) = context.tiled_image_map.get(&info.image_key) {
// The image resource is tiled. We have to generate an image primitive
@ -693,8 +684,9 @@ impl Frame {
clip_region.origin += reference_frame_relative_offset;
// Just use clip rectangle as the frame rect for this scroll frame.
// This is only interesting when calculating scroll extents for the
// ClipScrollNode::scroll(..) API
// This is useful when calculating scroll extents for the
// ClipScrollNode::scroll(..) API as well as for properly setting sticky
// positioning offsets.
let frame_rect = item.local_clip()
.clip_rect()
.translate(&reference_frame_relative_offset);
@ -708,6 +700,16 @@ impl Frame {
clip_region,
info.scroll_sensitivity);
}
SpecificDisplayItem::StickyFrame(ref info) => {
let frame_rect = item.rect().translate(&reference_frame_relative_offset);
let new_clip_id = context.convert_new_id_to_nested(&info.id);
self.clip_scroll_tree.add_sticky_frame(
new_clip_id,
clip_and_scroll.scroll_node_id, /* parent id */
frame_rect,
info.sticky_frame_info);
}
SpecificDisplayItem::PushNestedDisplayList => {
// Using the clip and scroll already processed for nesting here
// means that in the case of multiple nested display lists, we

View File

@ -5,10 +5,10 @@
use api::{BorderDetails, BorderDisplayItem, BoxShadowClipMode, ClipAndScrollInfo, ClipId, ColorF};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect, DeviceUintSize};
use api::{ExtendMode, FontKey, FontRenderMode, GlyphInstance, GlyphOptions, GradientStop};
use api::{ImageKey, ImageRendering, ItemRange, LayerPoint, LayerRect, LayerSize, SubpixelDirection};
use api::{ImageKey, ImageRendering, ItemRange, LayerPoint, LayerRect, LayerSize};
use api::{LayerToScrollTransform, LayerVector2D, LayoutVector2D, LineOrientation, LineStyle};
use api::{LocalClip, PipelineId, RepeatMode, ScrollSensitivity, TextShadow, TileOffset};
use api::{TransformStyle, WebGLContextId, WorldPixel, YuvColorSpace, YuvData};
use api::{LocalClip, PipelineId, RepeatMode, ScrollSensitivity, SubpixelDirection, TextShadow};
use api::{TileOffset, TransformStyle, WorldPixel, YuvColorSpace, YuvData};
use app_units::Au;
use frame::FrameId;
use gpu_cache::GpuCache;
@ -16,7 +16,7 @@ use internal_types::{FastHashMap, HardwareCompositeOp};
use mask_cache::{ClipMode, ClipRegion, ClipSource, MaskCacheInfo};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, LinePrimitive, PrimitiveKind};
use prim_store::{ImagePrimitiveKind, PrimitiveContainer, PrimitiveIndex};
use prim_store::{PrimitiveContainer, PrimitiveIndex};
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu, TextRunMode};
use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu, TextShadowPrimitiveCpu};
use prim_store::{BoxShadowPrimitiveCpu, TexelRect, YuvImagePrimitiveCpu};
@ -103,7 +103,6 @@ pub struct FrameBuilderConfig {
pub enable_scrollbars: bool,
pub default_font_render_mode: FontRenderMode,
pub debug: bool,
pub cache_expiry_frames: u32,
}
pub struct FrameBuilder {
@ -323,9 +322,14 @@ impl FrameBuilder {
pipeline_id: PipelineId,
rect: &LayerRect,
transform: &LayerToScrollTransform,
origin_in_parent_reference_frame: LayerVector2D,
clip_scroll_tree: &mut ClipScrollTree)
-> ClipId {
let new_id = clip_scroll_tree.add_reference_frame(rect, transform, pipeline_id, parent_id);
let new_id = clip_scroll_tree.add_reference_frame(rect,
transform,
origin_in_parent_reference_frame,
pipeline_id,
parent_id);
self.reference_frame_stack.push(new_id);
new_id
}
@ -353,10 +357,10 @@ impl FrameBuilder {
let root_id = clip_scroll_tree.root_reference_frame_id();
if let Some(root_node) = clip_scroll_tree.nodes.get_mut(&root_id) {
if let NodeType::ReferenceFrame(ref mut transform) = root_node.node_type {
*transform = LayerToScrollTransform::create_translation(viewport_offset.x,
viewport_offset.y,
0.0);
if let NodeType::ReferenceFrame(ref mut info) = root_node.node_type {
info.transform = LayerToScrollTransform::create_translation(viewport_offset.x,
viewport_offset.y,
0.0);
}
root_node.local_clip_rect = viewport_clip;
}
@ -375,7 +379,12 @@ impl FrameBuilder {
-> ClipId {
let viewport_rect = LayerRect::new(LayerPoint::zero(), *viewport_size);
let identity = &LayerToScrollTransform::identity();
self.push_reference_frame(None, pipeline_id, &viewport_rect, identity, clip_scroll_tree);
self.push_reference_frame(None,
pipeline_id,
&viewport_rect,
identity,
LayerVector2D::zero(),
clip_scroll_tree);
let topmost_scrolling_node_id = ClipId::root_scroll_node(pipeline_id);
clip_scroll_tree.topmost_scrolling_node_id = topmost_scrolling_node_id;
@ -1196,24 +1205,6 @@ impl FrameBuilder {
}
}
pub fn add_webgl_rectangle(&mut self,
clip_and_scroll: ClipAndScrollInfo,
rect: LayerRect,
local_clip: &LocalClip,
context_id: WebGLContextId) {
let prim_cpu = ImagePrimitiveCpu {
kind: ImagePrimitiveKind::WebGL(context_id),
gpu_blocks: [ [rect.size.width, rect.size.height, 0.0, 0.0].into(),
TexelRect::invalid().into() ],
};
self.add_primitive(clip_and_scroll,
&rect,
local_clip,
&[],
PrimitiveContainer::Image(prim_cpu));
}
pub fn add_image(&mut self,
clip_and_scroll: ClipAndScrollInfo,
rect: LayerRect,
@ -1227,10 +1218,10 @@ impl FrameBuilder {
let sub_rect_block = sub_rect.unwrap_or(TexelRect::invalid()).into();
let prim_cpu = ImagePrimitiveCpu {
kind: ImagePrimitiveKind::Image(image_key,
image_rendering,
tile,
*tile_spacing),
image_key,
image_rendering,
tile_offset: tile,
tile_spacing: *tile_spacing,
gpu_blocks: [ [ stretch_size.width,
stretch_size.height,
tile_spacing.width,
@ -1773,7 +1764,10 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
if let Some(mask) = clip_source.image_mask() {
// We don't add the image mask for resolution, because
// layer masks are resolved later.
self.resource_cache.request_image(mask.image, ImageRendering::Auto, None);
self.resource_cache.request_image(mask.image,
ImageRendering::Auto,
None,
self.gpu_cache);
}
}
}
@ -1879,9 +1873,9 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
current_id = node.parent;
let clip = match node.node_type {
NodeType::ReferenceFrame(transform) => {
NodeType::ReferenceFrame(ref info) => {
// if the transform is non-aligned, bake the next LCCR into the clip mask
next_node_needs_region_mask |= !transform.preserves_2d_axis_alignment();
next_node_needs_region_mask |= !info.transform.preserves_2d_axis_alignment();
continue
},
NodeType::Clip(ref clip) if clip.mask_cache_info.is_masking() => clip,

View File

@ -3,40 +3,31 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::marker::PhantomData;
use std::mem;
// TODO(gw): Add a weak free list handle. This is like a strong
// free list handle below, but will contain an epoch
// field. Weak handles will use a get_opt style API
// which returns an Option<T> instead of T.
// TODO(gw): Add an occupied list head, for fast
// iteration of the occupied list to implement
// retain() style functionality.
#[derive(Debug, Copy, Clone, PartialEq)]
struct Epoch(u32);
#[derive(Debug)]
pub struct FreeListHandle<T> {
index: u32,
_marker: PhantomData<T>,
}
enum SlotValue<T> {
Free,
Occupied(T),
}
impl<T> SlotValue<T> {
fn take(&mut self) -> T {
match mem::replace(self, SlotValue::Free) {
SlotValue::Free => unreachable!(),
SlotValue::Occupied(data) => data,
}
}
#[derive(Debug)]
pub struct WeakFreeListHandle<T> {
index: u32,
epoch: Epoch,
_marker: PhantomData<T>,
}
struct Slot<T> {
next: Option<u32>,
value: SlotValue<T>,
epoch: Epoch,
value: Option<T>,
}
pub struct FreeList<T> {
@ -44,6 +35,11 @@ pub struct FreeList<T> {
free_list_head: Option<u32>,
}
pub enum UpsertResult<T> {
Updated(T),
Inserted(FreeListHandle<T>),
}
impl<T> FreeList<T> {
pub fn new() -> FreeList<T> {
FreeList {
@ -52,17 +48,63 @@ impl<T> FreeList<T> {
}
}
#[allow(dead_code)]
pub fn get(&self, id: &FreeListHandle<T>) -> &T {
match self.slots[id.index as usize].value {
SlotValue::Free => unreachable!(),
SlotValue::Occupied(ref data) => data,
self.slots[id.index as usize]
.value
.as_ref()
.unwrap()
}
#[allow(dead_code)]
pub fn get_mut(&mut self, id: &FreeListHandle<T>) -> &mut T {
self.slots[id.index as usize]
.value
.as_mut()
.unwrap()
}
pub fn get_opt(&self, id: &WeakFreeListHandle<T>) -> Option<&T> {
let slot = &self.slots[id.index as usize];
if slot.epoch == id.epoch {
slot.value.as_ref()
} else {
None
}
}
pub fn get_mut(&mut self, id: &FreeListHandle<T>) -> &mut T {
match self.slots[id.index as usize].value {
SlotValue::Free => unreachable!(),
SlotValue::Occupied(ref mut data) => data,
pub fn get_opt_mut(&mut self, id: &WeakFreeListHandle<T>) -> Option<&mut T> {
let slot = &mut self.slots[id.index as usize];
if slot.epoch == id.epoch {
slot.value.as_mut()
} else {
None
}
}
pub fn create_weak_handle(&self, id: &FreeListHandle<T>) -> WeakFreeListHandle<T> {
let slot = &self.slots[id.index as usize];
WeakFreeListHandle {
index: id.index,
epoch: slot.epoch,
_marker: PhantomData,
}
}
// Perform a database style UPSERT operation. If the provided
// handle is a valid entry, update the value and return the
// previous data. If the provided handle is invalid, then
// insert the data into a new slot and return the new handle.
pub fn upsert(&mut self,
id: &WeakFreeListHandle<T>,
data: T) -> UpsertResult<T> {
if self.slots[id.index as usize].epoch == id.epoch {
let slot = &mut self.slots[id.index as usize];
let result = UpsertResult::Updated(slot.value.take().unwrap());
slot.value = Some(data);
result
} else {
UpsertResult::Inserted(self.insert(data))
}
}
@ -74,7 +116,7 @@ impl<T> FreeList<T> {
// Remove from free list.
self.free_list_head = slot.next;
slot.next = None;
slot.value = SlotValue::Occupied(item);
slot.value = Some(item);
FreeListHandle {
index: free_index,
@ -86,7 +128,8 @@ impl<T> FreeList<T> {
self.slots.push(Slot {
next: None,
value: SlotValue::Occupied(item),
epoch: Epoch(0),
value: Some(item),
});
FreeListHandle {
@ -100,7 +143,8 @@ impl<T> FreeList<T> {
pub fn free(&mut self, id: FreeListHandle<T>) -> T {
let slot = &mut self.slots[id.index as usize];
slot.next = self.free_list_head;
slot.epoch = Epoch(slot.epoch.0 + 1);
self.free_list_head = Some(id.index);
slot.value.take()
slot.value.take().unwrap()
}
}

View File

@ -2,47 +2,23 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{FontInstanceKey, GlyphKey};
use frame::FrameId;
use gpu_cache::GpuCache;
use api::{DevicePoint, DeviceUintSize, FontInstance, GlyphKey};
use internal_types::FastHashMap;
use resource_cache::{Resource, ResourceClassCache};
use texture_cache::{TextureCache, TextureCacheItemId};
use resource_cache::ResourceClassCache;
use std::sync::Arc;
use texture_cache::TextureCacheHandle;
pub struct CachedGlyphInfo {
pub texture_cache_id: Option<TextureCacheItemId>,
pub last_access: FrameId,
pub texture_cache_handle: TextureCacheHandle,
pub glyph_bytes: Arc<Vec<u8>>,
pub size: DeviceUintSize,
pub offset: DevicePoint,
}
impl Resource for CachedGlyphInfo {
fn free(self, texture_cache: &mut TextureCache) {
if let Some(id) = self.texture_cache_id {
texture_cache.free(id);
}
}
fn get_last_access_time(&self) -> FrameId {
self.last_access
}
fn set_last_access_time(&mut self, frame_id: FrameId) {
self.last_access = frame_id;
}
fn add_to_gpu_cache(&self,
texture_cache: &mut TextureCache,
gpu_cache: &mut GpuCache) {
if let Some(texture_cache_id) = self.texture_cache_id.as_ref() {
let item = texture_cache.get_mut(texture_cache_id);
if let Some(mut request) = gpu_cache.request(&mut item.uv_rect_handle) {
request.push(item.uv_rect);
request.push([item.user_data[0], item.user_data[1], 0.0, 0.0]);
}
}
}
}
pub type GlyphKeyCache = ResourceClassCache<GlyphKey, CachedGlyphInfo>;
pub type GlyphKeyCache = ResourceClassCache<GlyphKey, Option<CachedGlyphInfo>>;
pub struct GlyphCache {
pub glyph_key_caches: FastHashMap<FontInstanceKey, GlyphKeyCache>,
pub glyph_key_caches: FastHashMap<FontInstance, GlyphKeyCache>,
}
impl GlyphCache {
@ -53,53 +29,30 @@ impl GlyphCache {
}
pub fn get_glyph_key_cache_for_font_mut(&mut self,
font: FontInstanceKey) -> &mut GlyphKeyCache {
font: FontInstance) -> &mut GlyphKeyCache {
self.glyph_key_caches
.entry(font)
.or_insert(ResourceClassCache::new())
}
pub fn get_glyph_key_cache_for_font(&self,
font: &FontInstanceKey) -> &GlyphKeyCache {
font: &FontInstance) -> &GlyphKeyCache {
self.glyph_key_caches
.get(font)
.expect("BUG: Unable to find glyph key cache!")
}
pub fn update(&mut self,
texture_cache: &mut TextureCache,
gpu_cache: &mut GpuCache,
current_frame_id: FrameId,
expiry_frame_id: FrameId) {
let mut caches_to_remove = Vec::new();
for (font, glyph_key_cache) in &mut self.glyph_key_caches {
glyph_key_cache.update(texture_cache,
gpu_cache,
current_frame_id,
expiry_frame_id);
if glyph_key_cache.is_empty() {
caches_to_remove.push(font.clone());
}
}
for key in caches_to_remove {
self.glyph_key_caches.remove(&key).unwrap();
}
}
pub fn clear(&mut self, texture_cache: &mut TextureCache) {
pub fn clear(&mut self) {
for (_, glyph_key_cache) in &mut self.glyph_key_caches {
glyph_key_cache.clear(texture_cache)
glyph_key_cache.clear()
}
// We use this in on_memory_pressure where retaining memory allocations
// isn't desirable, so we completely remove the hash map instead of clearing it.
self.glyph_key_caches = FastHashMap::default();
}
pub fn clear_fonts<F>(&mut self, texture_cache: &mut TextureCache, key_fun: F)
where for<'r> F: Fn(&'r &FontInstanceKey) -> bool
pub fn clear_fonts<F>(&mut self, key_fun: F)
where for<'r> F: Fn(&'r &FontInstance) -> bool
{
let caches_to_destroy = self.glyph_key_caches.keys()
.filter(&key_fun)
@ -107,7 +60,7 @@ impl GlyphCache {
.collect::<Vec<_>>();
for key in caches_to_destroy {
let mut cache = self.glyph_key_caches.remove(&key).unwrap();
cache.clear(texture_cache);
cache.clear();
}
}
}

View File

@ -5,8 +5,8 @@
#[cfg(test)]
use app_units::Au;
use device::TextureFilter;
use frame::FrameId;
use glyph_cache::{CachedGlyphInfo, GlyphCache};
use gpu_cache::GpuCache;
use internal_types::FastHashSet;
use platform::font::{FontContext, RasterizedGlyph};
use profiler::TextureCacheProfileCounters;
@ -16,10 +16,10 @@ use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::collections::hash_map::Entry;
use std::mem;
use texture_cache::TextureCache;
use texture_cache::{TextureCache, TextureCacheHandle};
#[cfg(test)]
use api::{ColorF, LayoutPoint, FontRenderMode, IdNamespace, SubpixelDirection};
use api::{FontInstanceKey};
use api::{DevicePoint, DeviceUintSize, FontInstance};
use api::{FontKey, FontTemplate};
use api::{ImageData, ImageDescriptor, ImageFormat};
use api::{GlyphKey, GlyphDimensions};
@ -145,9 +145,10 @@ impl GlyphRasterizer {
pub fn request_glyphs(
&mut self,
glyph_cache: &mut GlyphCache,
current_frame_id: FrameId,
font: FontInstanceKey,
glyph_keys: &[GlyphKey]) {
font: FontInstance,
glyph_keys: &[GlyphKey],
texture_cache: &mut TextureCache,
gpu_cache: &mut GpuCache) {
assert!(self.font_contexts.lock_shared_context().has_font(&font.font_key));
let mut glyphs = Vec::new();
@ -155,8 +156,31 @@ impl GlyphRasterizer {
// select glyphs that have not been requested yet.
for key in glyph_keys {
match glyph_key_cache.entry(key.clone(), current_frame_id) {
Entry::Occupied(..) => {}
match glyph_key_cache.entry(key.clone()) {
Entry::Occupied(mut entry) => {
if let Some(ref mut glyph_info) = *entry.get_mut() {
if texture_cache.request(&mut glyph_info.texture_cache_handle, gpu_cache) {
// This case gets hit when we have already rasterized
// the glyph and stored it in CPU memory, the the glyph
// has been evicted from the texture cache. In which case
// we need to re-upload it to the GPU.
texture_cache.update(&mut glyph_info.texture_cache_handle,
ImageDescriptor {
width: glyph_info.size.width,
height: glyph_info.size.height,
stride: None,
format: ImageFormat::BGRA8,
is_opaque: false,
offset: 0,
},
TextureFilter::Linear,
ImageData::Raw(glyph_info.glyph_bytes.clone()),
[glyph_info.offset.x, glyph_info.offset.y],
None,
gpu_cache);
}
}
}
Entry::Vacant(..) => {
let request = GlyphRequest::new(&font, key);
if self.pending_glyphs.insert(request.clone()) {
@ -198,7 +222,7 @@ impl GlyphRasterizer {
}
pub fn get_glyph_dimensions(&mut self,
font: &FontInstanceKey,
font: &FontInstance,
glyph_key: &GlyphKey) -> Option<GlyphDimensions> {
self.font_contexts.lock_shared_context().get_glyph_dimensions(font, glyph_key)
}
@ -209,10 +233,10 @@ impl GlyphRasterizer {
pub fn resolve_glyphs(
&mut self,
current_frame_id: FrameId,
glyph_cache: &mut GlyphCache,
texture_cache: &mut TextureCache,
texture_cache_profile: &mut TextureCacheProfileCounters,
gpu_cache: &mut GpuCache,
_texture_cache_profile: &mut TextureCacheProfileCounters,
) {
let mut rasterized_glyphs = Vec::with_capacity(self.pending_glyphs.len());
@ -241,10 +265,14 @@ impl GlyphRasterizer {
// Update the caches.
for job in rasterized_glyphs {
let image_id = job.result.and_then(
let glyph_info = job.result.and_then(
|glyph| if glyph.width > 0 && glyph.height > 0 {
assert_eq!((glyph.left.fract(), glyph.top.fract()), (0.0, 0.0));
let image_id = texture_cache.insert(
let glyph_bytes = Arc::new(glyph.bytes);
let mut texture_cache_handle = TextureCacheHandle::new();
texture_cache.request(&mut texture_cache_handle, gpu_cache);
texture_cache.update(
&mut texture_cache_handle,
ImageDescriptor {
width: glyph.width,
height: glyph.height,
@ -254,11 +282,17 @@ impl GlyphRasterizer {
offset: 0,
},
TextureFilter::Linear,
ImageData::Raw(Arc::new(glyph.bytes)),
ImageData::Raw(glyph_bytes.clone()),
[glyph.left, glyph.top],
texture_cache_profile,
None,
gpu_cache,
);
Some(image_id)
Some(CachedGlyphInfo {
texture_cache_handle,
glyph_bytes,
size: DeviceUintSize::new(glyph.width, glyph.height),
offset: DevicePoint::new(glyph.left, glyph.top),
})
} else {
None
}
@ -266,10 +300,7 @@ impl GlyphRasterizer {
let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font_mut(job.request.font);
glyph_key_cache.insert(job.request.key, CachedGlyphInfo {
texture_cache_id: image_id,
last_access: current_frame_id,
});
glyph_key_cache.insert(job.request.key, glyph_info);
}
// Now that we are done with the critical path (rendering the glyphs),
@ -308,11 +339,11 @@ impl FontContext {
#[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
pub struct GlyphRequest {
pub key: GlyphKey,
pub font: FontInstanceKey,
pub font: FontInstance,
}
impl GlyphRequest {
pub fn new(font: &FontInstanceKey, key: &GlyphKey) -> Self {
pub fn new(font: &FontInstance, key: &GlyphKey) -> Self {
GlyphRequest {
key: key.clone(),
font: font.clone(),
@ -337,6 +368,8 @@ fn raterize_200_glyphs() {
let workers = Arc::new(ThreadPool::new(Configuration::new()).unwrap());
let mut glyph_rasterizer = GlyphRasterizer::new(workers);
let mut glyph_cache = GlyphCache::new();
let mut gpu_cache = GpuCache::new();
let mut texture_cache = TextureCache::new(2048);
let mut font_file = File::open("../wrench/reftests/text/VeraBd.ttf").expect("Couldn't open font file");
let mut font_data = vec![];
@ -345,9 +378,7 @@ fn raterize_200_glyphs() {
let font_key = FontKey::new(IdNamespace(0), 0);
glyph_rasterizer.add_font(font_key, FontTemplate::Raw(Arc::new(font_data), 0));
let frame_id = FrameId(1);
let font = FontInstanceKey {
let font = FontInstance {
font_key,
color: ColorF::new(0.0, 0.0, 0.0, 1.0).into(),
size: Au::from_px(32),
@ -364,18 +395,19 @@ fn raterize_200_glyphs() {
for i in 0..4 {
glyph_rasterizer.request_glyphs(
&mut glyph_cache,
frame_id,
font.clone(),
&glyph_keys[(50 * i)..(50 * (i + 1))],
&mut texture_cache,
&mut gpu_cache
);
}
glyph_rasterizer.delete_font(font_key);
glyph_rasterizer.resolve_glyphs(
frame_id,
&mut glyph_cache,
&mut TextureCache::new(4096),
&mut gpu_cache,
&mut TextureCacheProfileCounters::new(),
);
}

View File

@ -28,7 +28,8 @@ use device::FrameId;
use internal_types::UvRect;
use profiler::GpuCacheProfileCounters;
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
use std::{mem, u32};
use std::{mem, u16, u32};
use std::ops::Add;
use api::{ColorF, LayerRect};
pub const GPU_CACHE_INITIAL_HEIGHT: u32 = 512;
@ -140,6 +141,24 @@ impl GpuCacheAddress {
v: v as u16,
}
}
pub fn invalid() -> GpuCacheAddress {
GpuCacheAddress {
u: u16::MAX,
v: u16::MAX,
}
}
}
impl Add<usize> for GpuCacheAddress {
type Output = GpuCacheAddress;
fn add(self, other: usize) -> GpuCacheAddress {
GpuCacheAddress {
u: self.u + other as u16,
v: self.v,
}
}
}
// An entry in a free-list of blocks in the GPU cache.

View File

@ -15,7 +15,7 @@ use tiling;
use renderer::BlendMode;
use api::{ClipId, DevicePoint, DeviceUintRect, DocumentId, Epoch};
use api::{ExternalImageData, ExternalImageId};
use api::{ImageData, ImageFormat, PipelineId};
use api::{ImageFormat, PipelineId};
pub type FastHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
@ -43,10 +43,8 @@ pub enum SourceTexture {
Invalid,
TextureCache(CacheTextureId),
External(ExternalImageData),
#[cfg_attr(not(feature = "webgl"), allow(dead_code))]
/// This is actually a gl::GLuint, with the shared texture id between the
/// main context and the WebGL context.
WebGL(u32),
CacheA8,
CacheRGBA8,
}
pub const ORTHO_NEAR_PLANE: f32 = -1000000.0;
@ -91,6 +89,16 @@ impl BatchTextures {
colors: [SourceTexture::Invalid; 3],
}
}
pub fn render_target_cache() -> Self {
BatchTextures {
colors: [
SourceTexture::CacheRGBA8,
SourceTexture::Invalid,
SourceTexture::Invalid,
]
}
}
}
// In some places we need to temporarily bind a texture to any slot.
@ -99,42 +107,31 @@ pub const DEFAULT_TEXTURE: TextureSampler = TextureSampler::Color0;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RenderTargetMode {
None,
SimpleRenderTarget,
LayerRenderTarget(i32), // Number of texture layers
RenderTarget,
}
#[derive(Debug)]
pub enum TextureUpdateSource {
External { id: ExternalImageId, channel_index: u8 },
Bytes { data: Arc<Vec<u8>> },
}
#[derive(Debug)]
pub enum TextureUpdateOp {
Create {
width: u32,
height: u32,
format: ImageFormat,
filter: TextureFilter,
mode: RenderTargetMode,
data: Option<ImageData>,
},
Update {
page_pos_x: u32, // the texture page position which we want to upload
page_pos_y: u32,
width: u32,
height: u32,
data: Arc<Vec<u8>>,
stride: Option<u32>,
offset: u32,
},
UpdateForExternalBuffer {
rect: DeviceUintRect,
id: ExternalImageId,
channel_index: u8,
stride: Option<u32>,
offset: u32,
},
Grow {
width: u32,
height: u32,
format: ImageFormat,
filter: TextureFilter,
mode: RenderTargetMode,
layer_count: i32,
},
Update {
rect: DeviceUintRect,
stride: Option<u32>,
offset: u32,
layer_index: i32,
source: TextureUpdateSource,
},
Free,
}

View File

@ -80,16 +80,6 @@ mod texture_cache;
mod tiling;
mod util;
#[doc(hidden)] // for benchmarks
pub use texture_cache::TexturePage;
#[cfg(feature = "webgl")]
mod webgl_types;
#[cfg(not(feature = "webgl"))]
#[path = "webgl_stubs.rs"]
mod webgl_types;
mod shader_source {
include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
}
@ -140,8 +130,6 @@ extern crate num_traits;
//extern crate notify;
extern crate time;
pub extern crate webrender_api;
#[cfg(feature = "webgl")]
extern crate offscreen_gl_context;
extern crate byteorder;
extern crate rayon;
extern crate plane_split;

View File

@ -120,6 +120,10 @@ impl ClipAddressRange {
}
}
pub fn is_empty(&self) -> bool {
self.item_count == 0
}
pub fn get_count(&self) -> usize {
self.item_count
}

View File

@ -17,7 +17,7 @@ use internal_types::FastHashMap;
use std::collections::hash_map::Entry;
use api::{ColorU, FontKey, FontRenderMode, GlyphDimensions};
use api::{GlyphKey};
use api::{FontInstanceKey, NativeFontHandle};
use api::{FontInstance, NativeFontHandle};
use gamma_lut::{GammaLut, Color as ColorLut};
use std::ptr;
use std::sync::Arc;
@ -238,7 +238,7 @@ impl FontContext {
}
pub fn get_glyph_dimensions(&mut self,
font: &FontInstanceKey,
font: &FontInstance,
key: &GlyphKey) -> Option<GlyphDimensions> {
self.get_ct_font(font.font_key, font.size).and_then(|ref ct_font| {
let glyph = key.index as CGGlyph;
@ -298,7 +298,7 @@ impl FontContext {
}
pub fn rasterize_glyph(&mut self,
font: &FontInstanceKey,
font: &FontInstance,
key: &GlyphKey)
-> Option<RasterizedGlyph> {

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{FontInstanceKey, FontKey, FontRenderMode, GlyphDimensions};
use api::{FontInstance, FontKey, FontRenderMode, GlyphDimensions};
use api::{NativeFontHandle, SubpixelDirection};
use api::{GlyphKey};
use internal_types::FastHashMap;
@ -123,7 +123,7 @@ impl FontContext {
}
fn load_glyph(&self,
font: &FontInstanceKey,
font: &FontInstance,
glyph: &GlyphKey) -> Option<FT_GlyphSlot> {
debug_assert!(self.faces.contains_key(&font.font_key));
@ -166,7 +166,7 @@ impl FontContext {
// Get the bounding box for a glyph, accounting for sub-pixel positioning.
fn get_bounding_box(&self,
slot: FT_GlyphSlot,
font: &FontInstanceKey,
font: &FontInstance,
glyph: &GlyphKey) -> FT_BBox {
let mut cbox: FT_BBox = unsafe { mem::uninitialized() };
@ -213,7 +213,7 @@ impl FontContext {
fn get_glyph_dimensions_impl(&self,
slot: FT_GlyphSlot,
font: &FontInstanceKey,
font: &FontInstance,
glyph: &GlyphKey) -> Option<GlyphDimensions> {
let metrics = unsafe { &(*slot).metrics };
@ -249,7 +249,7 @@ impl FontContext {
}
pub fn get_glyph_dimensions(&mut self,
font: &FontInstanceKey,
font: &FontInstance,
key: &GlyphKey) -> Option<GlyphDimensions> {
let slot = self.load_glyph(font, key);
slot.and_then(|slot| {
@ -258,7 +258,7 @@ impl FontContext {
}
pub fn rasterize_glyph(&mut self,
font: &FontInstanceKey,
font: &FontInstance,
key: &GlyphKey)
-> Option<RasterizedGlyph> {

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{FontKey, FontRenderMode, GlyphDimensions};
use api::{FontInstanceKey, GlyphKey, GlyphOptions, SubpixelDirection};
use api::{FontInstance, GlyphKey, GlyphOptions, SubpixelDirection};
use gamma_lut::{GammaLut, Color as ColorLut};
use internal_types::FastHashMap;
@ -155,7 +155,7 @@ impl FontContext {
}
fn create_glyph_analysis(&self,
font: &FontInstanceKey,
font: &FontInstance,
key: &GlyphKey) ->
dwrote::GlyphRunAnalysis {
let face = self.fonts.get(&font.font_key).unwrap();
@ -202,7 +202,7 @@ impl FontContext {
// TODO: Pipe GlyphOptions into glyph_dimensions too
pub fn get_glyph_dimensions(&self,
font: &FontInstanceKey,
font: &FontInstance,
key: &GlyphKey)
-> Option<GlyphDimensions> {
// Probably have to default to something else here.
@ -283,7 +283,7 @@ impl FontContext {
}
pub fn rasterize_glyph(&mut self,
font: &FontInstanceKey,
font: &FontInstance,
key: &GlyphKey)
-> Option<RasterizedGlyph> {
let analysis = self.create_glyph_analysis(font, key);

View File

@ -5,8 +5,8 @@
use api::{BuiltDisplayList, ColorF, ComplexClipRegion, DeviceIntRect, DeviceIntSize, DevicePoint};
use api::{ExtendMode, FontKey, FontRenderMode, GlyphInstance, GlyphOptions, GradientStop};
use api::{ImageKey, ImageRendering, ItemRange, LayerPoint, LayerRect, LayerSize, TextShadow};
use api::{GlyphKey, LayerToWorldTransform, TileOffset, WebGLContextId, YuvColorSpace, YuvFormat};
use api::{device_length, FontInstanceKey, LayerVector2D, LineOrientation, LineStyle, SubpixelDirection};
use api::{GlyphKey, LayerToWorldTransform, TileOffset, YuvColorSpace, YuvFormat};
use api::{device_length, FontInstance, LayerVector2D, LineOrientation, LineStyle, SubpixelDirection};
use app_units::Au;
use border::BorderCornerInstance;
use euclid::{Size2D};
@ -199,15 +199,12 @@ impl ToGpuBlocks for LinePrimitive {
}
}
#[derive(Debug)]
pub enum ImagePrimitiveKind {
Image(ImageKey, ImageRendering, Option<TileOffset>, LayerSize),
WebGL(WebGLContextId),
}
#[derive(Debug)]
pub struct ImagePrimitiveCpu {
pub kind: ImagePrimitiveKind,
pub image_key: ImageKey,
pub image_rendering: ImageRendering,
pub tile_offset: Option<TileOffset>,
pub tile_spacing: LayerSize,
// TODO(gw): Build on demand
pub gpu_blocks: [GpuBlockData; 2],
}
@ -538,19 +535,20 @@ impl TextRunPrimitiveCpu {
resource_cache: &mut ResourceCache,
device_pixel_ratio: f32,
display_list: &BuiltDisplayList,
run_mode: TextRunMode) {
run_mode: TextRunMode,
gpu_cache: &mut GpuCache) {
let font_size_dp = self.logical_font_size.scale_by(device_pixel_ratio);
let render_mode = match run_mode {
TextRunMode::Normal => self.normal_render_mode,
TextRunMode::Shadow => self.shadow_render_mode,
};
let font = FontInstanceKey::new(self.font_key,
font_size_dp,
self.color,
render_mode,
self.glyph_options,
self.subpx_dir);
let font = FontInstance::new(self.font_key,
font_size_dp,
self.color,
render_mode,
self.glyph_options,
self.subpx_dir);
// Cache the glyph positions, if not in the cache already.
// TODO(gw): In the future, remove `glyph_instances`
@ -590,7 +588,7 @@ impl TextRunPrimitiveCpu {
}
}
resource_cache.request_glyphs(font, &self.glyph_keys);
resource_cache.request_glyphs(font, &self.glyph_keys, gpu_cache);
}
fn write_gpu_blocks(&self,
@ -1130,7 +1128,10 @@ impl PrimitiveStore {
for clip in &metadata.clips {
if let ClipSource::Region(ClipRegion{ image_mask: Some(ref mask), .. }, ..) = *clip {
resource_cache.request_image(mask.image, ImageRendering::Auto, None);
resource_cache.request_image(mask.image,
ImageRendering::Auto,
None,
gpu_cache);
}
}
}
@ -1177,25 +1178,25 @@ impl PrimitiveStore {
text.prepare_for_render(resource_cache,
device_pixel_ratio,
display_list,
text_run_mode);
text_run_mode,
gpu_cache);
}
PrimitiveKind::Image => {
let image_cpu = &mut self.cpu_images[cpu_prim_index.0];
match image_cpu.kind {
ImagePrimitiveKind::Image(image_key, image_rendering, tile_offset, tile_spacing) => {
resource_cache.request_image(image_key, image_rendering, tile_offset);
resource_cache.request_image(image_cpu.image_key,
image_cpu.image_rendering,
image_cpu.tile_offset,
gpu_cache);
// TODO(gw): This doesn't actually need to be calculated each frame.
// It's cheap enough that it's not worth introducing a cache for images
// right now, but if we introduce a cache for images for some other
// reason then we might as well cache this with it.
let image_properties = resource_cache.get_image_properties(image_key);
metadata.opacity.is_opaque = image_properties.descriptor.is_opaque &&
tile_spacing.width == 0.0 &&
tile_spacing.height == 0.0;
}
ImagePrimitiveKind::WebGL(..) => {}
// TODO(gw): This doesn't actually need to be calculated each frame.
// It's cheap enough that it's not worth introducing a cache for images
// right now, but if we introduce a cache for images for some other
// reason then we might as well cache this with it.
if let Some(image_properties) = resource_cache.get_image_properties(image_cpu.image_key) {
metadata.opacity.is_opaque = image_properties.descriptor.is_opaque &&
image_cpu.tile_spacing.width == 0.0 &&
image_cpu.tile_spacing.height == 0.0;
}
}
PrimitiveKind::YuvImage => {
@ -1204,7 +1205,10 @@ impl PrimitiveStore {
let channel_num = image_cpu.format.get_plane_num();
debug_assert!(channel_num <= 3);
for channel in 0..channel_num {
resource_cache.request_image(image_cpu.yuv_key[channel], image_cpu.image_rendering, None);
resource_cache.request_image(image_cpu.yuv_key[channel],
image_cpu.image_rendering,
None,
gpu_cache);
}
}
PrimitiveKind::AlignedGradient |

View File

@ -67,8 +67,7 @@ pub fn should_record_msg(msg: &ApiMsg) -> bool {
ApiMsg::UpdateResources(..) |
ApiMsg::AddDocument{..} |
ApiMsg::UpdateDocument(..) |
ApiMsg::DeleteDocument(..) |
ApiMsg::WebGLCommand(..) =>
ApiMsg::DeleteDocument(..) =>
true,
_ => false
}

View File

@ -5,7 +5,7 @@
use frame::Frame;
use frame_builder::FrameBuilderConfig;
use gpu_cache::GpuCache;
use internal_types::{FastHashMap, SourceTexture, ResultMsg, RendererFrame};
use internal_types::{FastHashMap, ResultMsg, RendererFrame};
use profiler::{BackendProfileCounters, ResourceProfileCounters};
use record::ApiRecordingReceiver;
use resource_cache::ResourceCache;
@ -17,19 +17,11 @@ use texture_cache::TextureCache;
use time::precise_time_ns;
use thread_profiler::register_thread_with_profiler;
use rayon::ThreadPool;
use webgl_types::{GLContextHandleWrapper, GLContextWrapper};
use api::channel::{MsgReceiver, PayloadReceiver, PayloadReceiverHelperMethods};
use api::channel::{PayloadSender, PayloadSenderHelperMethods};
use api::{ApiMsg, BlobImageRenderer, BuiltDisplayList, DeviceIntPoint};
use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentId, DocumentMsg};
use api::{IdNamespace, LayerPoint, RenderDispatcher, RenderNotifier};
use api::{VRCompositorCommand, VRCompositorHandler, WebGLCommand, WebGLContextId};
#[cfg(feature = "webgl")]
use offscreen_gl_context::GLContextDispatcher;
#[cfg(not(feature = "webgl"))]
use webgl_types::GLContextDispatcher;
use api::{IdNamespace, LayerPoint, RenderNotifier};
struct Document {
scene: Scene,
@ -102,59 +94,6 @@ impl Document {
}
}
struct WebGL {
last_id: WebGLContextId,
contexts: FastHashMap<WebGLContextId, GLContextWrapper>,
active_id: Option<WebGLContextId>,
}
impl WebGL {
fn new() -> Self {
WebGL {
last_id: WebGLContextId(0),
contexts: FastHashMap::default(),
active_id: None,
}
}
fn register(&mut self, context: GLContextWrapper) -> WebGLContextId {
// Creating a new GLContext may make the current bound context_id dirty.
// Clear it to ensure that make_current() is called in subsequent commands.
self.active_id = None;
self.last_id.0 += 1;
self.contexts.insert(self.last_id, context);
self.last_id
}
fn activate(&mut self, id: WebGLContextId) -> &mut GLContextWrapper {
let ctx = self.contexts.get_mut(&id).unwrap();
if Some(id) != self.active_id {
ctx.make_current();
self.active_id = Some(id);
}
ctx
}
fn flush(&mut self) {
if let Some(id) = self.active_id.take() {
self.contexts[&id].unbind();
}
// When running in OSMesa mode with texture sharing,
// a flush is required on any GL contexts to ensure
// that read-back from the shared texture returns
// valid data! This should be fine to have run on all
// implementations - a single flush for each webgl
// context at the start of a render frame should
// incur minimal cost.
for (_, context) in &self.contexts {
context.make_current();
context.apply_command(WebGLCommand::Flush);
context.unbind();
}
}
}
enum DocumentOp {
Nop,
Built,
@ -184,12 +123,7 @@ pub struct RenderBackend {
documents: FastHashMap<DocumentId, Document>,
notifier: Arc<Mutex<Option<Box<RenderNotifier>>>>,
webrender_context_handle: Option<GLContextHandleWrapper>,
recorder: Option<Box<ApiRecordingReceiver>>,
main_thread_dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>,
vr_compositor_handler: Arc<Mutex<Option<Box<VRCompositorHandler>>>>,
webgl: WebGL,
enable_render_on_scroll: bool,
}
@ -204,19 +138,15 @@ impl RenderBackend {
texture_cache: TextureCache,
workers: Arc<ThreadPool>,
notifier: Arc<Mutex<Option<Box<RenderNotifier>>>>,
webrender_context_handle: Option<GLContextHandleWrapper>,
frame_config: FrameBuilderConfig,
recorder: Option<Box<ApiRecordingReceiver>>,
main_thread_dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>,
blob_image_renderer: Option<Box<BlobImageRenderer>>,
vr_compositor_handler: Arc<Mutex<Option<Box<VRCompositorHandler>>>>,
enable_render_on_scroll: bool,
) -> RenderBackend {
let resource_cache = ResourceCache::new(texture_cache,
workers,
blob_image_renderer,
frame_config.cache_expiry_frames);
blob_image_renderer);
register_thread_with_profiler("Backend".to_string());
@ -233,12 +163,7 @@ impl RenderBackend {
documents: FastHashMap::default(),
next_namespace_id: IdNamespace(1),
notifier,
webrender_context_handle,
recorder,
main_thread_dispatcher,
vr_compositor_handler,
webgl: WebGL::new(),
enable_render_on_scroll,
}
@ -308,7 +233,6 @@ impl RenderBackend {
let display_list_received_time = precise_time_ns();
{
self.webgl.flush();
let _timer = profile_counters.total_time.timer();
doc.scene.set_display_list(
pipeline_id,
@ -344,7 +268,6 @@ impl RenderBackend {
doc.scene.set_root_pipeline_id(pipeline_id);
if doc.scene.display_lists.get(&pipeline_id).is_some() {
self.webgl.flush();
let _timer = profile_counters.total_time.timer();
doc.build_scene(&mut self.resource_cache, self.hidpi_factor);
DocumentOp::Built
@ -415,7 +338,6 @@ impl RenderBackend {
// animated properties to not require a full
// rebuild of the frame!
if let Some(property_bindings) = property_bindings {
self.webgl.flush();
doc.scene.properties.set_properties(property_bindings);
doc.build_scene(&mut self.resource_cache, self.hidpi_factor);
}
@ -511,63 +433,6 @@ impl RenderBackend {
ApiMsg::DeleteDocument(document_id) => {
self.documents.remove(&document_id);
}
ApiMsg::RequestWebGLContext(size, attributes, tx) => {
if let Some(ref wrapper) = self.webrender_context_handle {
let dispatcher: Option<Box<GLContextDispatcher>> = if cfg!(target_os = "windows") {
Some(Box::new(WebRenderGLDispatcher {
dispatcher: Arc::clone(&self.main_thread_dispatcher)
}))
} else {
None
};
let result = wrapper.new_context(size, attributes, dispatcher);
match result {
Ok(ctx) => {
let (real_size, texture_id, limits) = ctx.get_info();
let id = self.webgl.register(ctx);
self.resource_cache
.add_webgl_texture(id, SourceTexture::WebGL(texture_id),
real_size);
tx.send(Ok((id, limits))).unwrap();
},
Err(msg) => {
tx.send(Err(msg.to_owned())).unwrap();
}
}
} else {
tx.send(Err("Not implemented yet".to_owned())).unwrap();
}
}
ApiMsg::ResizeWebGLContext(context_id, size) => {
let ctx = self.webgl.activate(context_id);
match ctx.resize(&size) {
Ok(_) => {
// Update webgl texture size. Texture id may change too.
let (real_size, texture_id, _) = ctx.get_info();
self.resource_cache
.update_webgl_texture(context_id, SourceTexture::WebGL(texture_id),
real_size);
},
Err(msg) => {
error!("Error resizing WebGLContext: {}", msg);
}
}
}
ApiMsg::WebGLCommand(context_id, command) => {
// TODO: Buffer the commands and only apply them here if they need to
// be synchronous.
let ctx = self.webgl.activate(context_id);
ctx.apply_command(command);
},
ApiMsg::VRCompositorCommand(context_id, command) => {
self.webgl.activate(context_id);
self.handle_vr_compositor_command(context_id, command);
}
ApiMsg::ExternalEvent(evt) => {
let notifier = self.notifier.lock();
notifier.unwrap()
@ -640,32 +505,4 @@ impl RenderBackend {
let mut notifier = self.notifier.lock();
notifier.as_mut().unwrap().as_mut().unwrap().new_scroll_frame_ready(composite_needed);
}
fn handle_vr_compositor_command(&mut self, ctx_id: WebGLContextId, cmd: VRCompositorCommand) {
let texture = match cmd {
VRCompositorCommand::SubmitFrame(..) => {
match self.resource_cache.get_webgl_texture(&ctx_id).id {
SourceTexture::WebGL(texture_id) => {
let size = self.resource_cache.get_webgl_texture_size(&ctx_id);
Some((texture_id, size))
},
_=> None
}
},
_ => None
};
let mut handler = self.vr_compositor_handler.lock();
handler.as_mut().unwrap().as_mut().unwrap().handle(cmd, texture);
}
}
struct WebRenderGLDispatcher {
dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>
}
impl GLContextDispatcher for WebRenderGLDispatcher {
fn dispatch(&self, f: Box<Fn() + Send>) {
let mut dispatcher = self.dispatcher.lock();
dispatcher.as_mut().unwrap().as_mut().unwrap().dispatch(f);
}
}

View File

@ -12,14 +12,14 @@
use debug_colors;
use debug_render::DebugRenderer;
use device::{DepthFunction, Device, FrameId, Program, TextureId, VertexDescriptor, GpuMarker, GpuProfiler, PBOId};
use device::{GpuSample, TextureFilter, VAOId, VertexUsageHint, FileWatcherHandler, TextureTarget, ShaderError};
use device::{GpuSample, TextureFilter, VAO, VertexUsageHint, FileWatcherHandler, TextureTarget, ShaderError};
use device::{get_gl_format_bgra, VertexAttribute, VertexAttributeKind};
use euclid::{Transform3D, rect};
use frame_builder::FrameBuilderConfig;
use gleam::gl;
use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
use internal_types::{FastHashMap, CacheTextureId, RendererFrame, ResultMsg, TextureUpdateOp};
use internal_types::{TextureUpdateList, RenderTargetMode};
use internal_types::{TextureUpdateList, RenderTargetMode, TextureUpdateSource};
use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, SourceTexture};
use internal_types::{BatchTextures, TextureSampler};
use profiler::{Profiler, BackendProfileCounters};
@ -46,12 +46,10 @@ use tiling::{AlphaRenderTarget, CacheClipInstance, PrimitiveInstance, ColorRende
use time::precise_time_ns;
use thread_profiler::{register_thread_with_profiler, write_profile};
use util::TransformedRectKind;
use webgl_types::GLContextHandleWrapper;
use api::{ColorF, Epoch, PipelineId, RenderApiSender, RenderNotifier, RenderDispatcher};
use api::{ExternalImageId, ExternalImageType, ImageData, ImageFormat};
use api::{ColorF, Epoch, PipelineId, RenderApiSender, RenderNotifier};
use api::{ExternalImageId, ExternalImageType, ImageFormat};
use api::{DeviceIntRect, DeviceUintRect, DeviceIntPoint, DeviceIntSize, DeviceUintSize};
use api::{BlobImageRenderer, channel, FontRenderMode};
use api::VRCompositorHandler;
use api::{YuvColorSpace, YuvFormat};
use api::{YUV_COLOR_SPACES, YUV_FORMATS};
@ -125,12 +123,17 @@ const DESC_CLIP: VertexDescriptor = VertexDescriptor {
instance_attributes: &[
VertexAttribute { name: "aClipRenderTaskIndex", count: 1, kind: VertexAttributeKind::I32 },
VertexAttribute { name: "aClipLayerIndex", count: 1, kind: VertexAttributeKind::I32 },
VertexAttribute { name: "aClipDataIndex", count: 1, kind: VertexAttributeKind::I32 },
VertexAttribute { name: "aClipSegmentIndex", count: 1, kind: VertexAttributeKind::I32 },
VertexAttribute { name: "aClipResourceAddress", count: 1, kind: VertexAttributeKind::I32 },
VertexAttribute { name: "aClipSegment", count: 1, kind: VertexAttributeKind::I32 },
VertexAttribute { name: "aClipDataResourceAddress", count: 4, kind: VertexAttributeKind::U16 },
]
};
enum VertexArrayKind {
Primitive,
Blur,
Clip,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum VertexFormat {
PrimitiveInstances,
@ -155,18 +158,21 @@ pub enum ImageBufferKind {
Texture2D = 0,
TextureRect = 1,
TextureExternal = 2,
Texture2DArray = 3,
}
pub const IMAGE_BUFFER_KINDS: [ImageBufferKind; 3] = [
pub const IMAGE_BUFFER_KINDS: [ImageBufferKind; 4] = [
ImageBufferKind::Texture2D,
ImageBufferKind::TextureRect,
ImageBufferKind::TextureExternal
ImageBufferKind::TextureExternal,
ImageBufferKind::Texture2DArray,
];
impl ImageBufferKind {
pub fn get_feature_string(&self) -> &'static str {
match *self {
ImageBufferKind::Texture2D => "",
ImageBufferKind::Texture2D => "TEXTURE_2D",
ImageBufferKind::Texture2DArray => "",
ImageBufferKind::TextureRect => "TEXTURE_RECT",
ImageBufferKind::TextureExternal => "TEXTURE_EXTERNAL",
}
@ -177,6 +183,7 @@ impl ImageBufferKind {
gl::GlType::Gles => {
match *self {
ImageBufferKind::Texture2D => true,
ImageBufferKind::Texture2DArray => true,
ImageBufferKind::TextureRect => true,
ImageBufferKind::TextureExternal => true,
}
@ -184,6 +191,7 @@ impl ImageBufferKind {
gl::GlType::Gl => {
match *self {
ImageBufferKind::Texture2D => true,
ImageBufferKind::Texture2DArray => true,
ImageBufferKind::TextureRect => true,
ImageBufferKind::TextureExternal => false,
}
@ -239,6 +247,88 @@ impl CpuProfile {
}
}
struct SourceTextureResolver {
/// A vector for fast resolves of texture cache IDs to
/// native texture IDs. This maps to a free-list managed
/// by the backend thread / texture cache. We free the
/// texture memory associated with a TextureId when its
/// texture cache ID is freed by the texture cache, but
/// reuse the TextureId when the texture caches's free
/// list reuses the texture cache ID. This saves having to
/// use a hashmap, and allows a flat vector for performance.
cache_texture_id_map: Vec<TextureId>,
/// Map of external image IDs to native textures.
external_images: FastHashMap<(ExternalImageId, u8), TextureId>,
/// A special 1x1 dummy cache texture used for shaders that expect to work
/// with the cache but are actually running in the first pass
/// when no target is yet provided as a cache texture input.
dummy_cache_texture_id: TextureId,
/// The current cache textures.
cache_rgba8_texture: Option<TextureId>,
cache_a8_texture: Option<TextureId>,
}
impl SourceTextureResolver {
fn new(device: &mut Device) -> SourceTextureResolver {
let dummy_cache_texture_id = device.create_texture_ids(1, TextureTarget::Array)[0];
device.init_texture(dummy_cache_texture_id,
1,
1,
ImageFormat::BGRA8,
TextureFilter::Linear,
RenderTargetMode::RenderTarget,
1,
None);
SourceTextureResolver {
cache_texture_id_map: Vec::new(),
external_images: FastHashMap::default(),
dummy_cache_texture_id,
cache_a8_texture: None,
cache_rgba8_texture: None,
}
}
fn deinit(self, device: &mut Device) {
device.deinit_texture(self.dummy_cache_texture_id);
}
fn set_cache_textures(&mut self,
a8_texture: Option<TextureId>,
rgba8_texture: Option<TextureId>) {
self.cache_a8_texture = a8_texture;
self.cache_rgba8_texture = rgba8_texture;
}
// Get the real (OpenGL) texture ID for a given source texture.
// For a texture cache texture, the IDs are stored in a vector
// map for fast access.
fn resolve(&self, texture_id: &SourceTexture) -> TextureId {
match *texture_id {
SourceTexture::Invalid => {
TextureId::invalid()
}
SourceTexture::CacheA8 => {
self.cache_a8_texture.unwrap_or(self.dummy_cache_texture_id)
}
SourceTexture::CacheRGBA8 => {
self.cache_rgba8_texture.unwrap_or(self.dummy_cache_texture_id)
}
SourceTexture::External(external_image) => {
*self.external_images
.get(&(external_image.id, external_image.channel_index))
.expect("BUG: External image should be resolved by now!")
}
SourceTexture::TextureCache(index) => {
self.cache_texture_id_map[index.0]
}
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum BlendMode {
None,
@ -324,6 +414,7 @@ impl CacheTexture {
ImageFormat::RGBAF32,
TextureFilter::Nearest,
RenderTargetMode::None,
1,
None);
// Copy the current texture into the newly resized texture.
@ -361,6 +452,8 @@ impl CacheTexture {
row_index as u32,
MAX_VERTEX_TEXTURE_WIDTH as u32,
1,
0,
None,
0);
// Orphan the PBO. This is the recommended way to hint to the
@ -456,6 +549,7 @@ impl<L: GpuStoreLayout> GpuDataTexture<L> {
L::image_format(),
L::texture_filter(),
RenderTargetMode::None,
1,
Some(unsafe { mem::transmute(data.as_slice()) } ));
}
}
@ -549,8 +643,8 @@ impl LazilyCompiledShader {
Ok(self.program.as_ref().unwrap())
}
fn deinit(&mut self, device: &mut Device) {
if let &mut Some(ref mut program) = &mut self.program {
fn deinit(self, device: &mut Device) {
if let Some(program) = self.program {
device.delete_program(program);
}
}
@ -614,7 +708,7 @@ impl PrimitiveShader {
}
}
fn deinit(&mut self, device: &mut Device) {
fn deinit(self, device: &mut Device) {
self.simple.deinit(device);
self.transform.deinit(device);
}
@ -758,9 +852,9 @@ pub struct Renderer {
alpha_render_targets: Vec<TextureId>,
gpu_profile: GpuProfiler<GpuProfileTag>,
prim_vao_id: VAOId,
blur_vao_id: VAOId,
clip_vao_id: VAOId,
prim_vao: VAO,
blur_vao: VAO,
clip_vao: VAO,
gdt_index: usize,
gpu_data_textures: [GpuDataTextures; GPU_DATA_TEXTURE_POOL],
@ -768,24 +862,12 @@ pub struct Renderer {
gpu_cache_texture: CacheTexture,
pipeline_epoch_map: FastHashMap<PipelineId, Epoch>,
/// Used to dispatch functions to the main thread's event loop.
/// Required to allow GLContext sharing in some implementations like WGL.
main_thread_dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>,
/// A vector for fast resolves of texture cache IDs to
/// native texture IDs. This maps to a free-list managed
/// by the backend thread / texture cache. We free the
/// texture memory associated with a TextureId when its
/// texture cache ID is freed by the texture cache, but
/// reuse the TextureId when the texture caches's free
/// list reuses the texture cache ID. This saves having to
/// use a hashmap, and allows a flat vector for performance.
cache_texture_id_map: Vec<TextureId>,
// Manages and resolves source textures IDs to real texture IDs.
texture_resolver: SourceTextureResolver,
/// A special 1x1 dummy cache texture used for shaders that expect to work
/// with the cache but are actually running in the first pass
/// when no target is yet provided as a cache texture input.
dummy_cache_texture_id: TextureId,
// A PBO used to do asynchronous texture cache uploads.
texture_cache_upload_pbo: PBOId,
dither_matrix_texture_id: Option<TextureId>,
@ -793,13 +875,6 @@ pub struct Renderer {
/// application to provide external buffers for image data.
external_image_handler: Option<Box<ExternalImageHandler>>,
/// Map of external image IDs to native textures.
external_images: FastHashMap<(ExternalImageId, u8), TextureId>,
// Optional trait object that handles WebVR commands.
// Some WebVR commands such as SubmitFrame must be synced with the WebGL render thread.
vr_compositor_handler: Arc<Mutex<Option<Box<VRCompositorHandler>>>>,
/// List of profile results from previous frames. Can be retrieved
/// via get_frame_profiles().
cpu_profiles: VecDeque<CpuProfile>,
@ -1136,15 +1211,6 @@ impl Renderer {
let backend_profile_counters = BackendProfileCounters::new();
let dummy_cache_texture_id = device.create_texture_ids(1, TextureTarget::Array)[0];
device.init_texture(dummy_cache_texture_id,
1,
1,
ImageFormat::BGRA8,
TextureFilter::Linear,
RenderTargetMode::LayerRenderTarget(1),
None);
let dither_matrix_texture_id = if options.enable_dithering {
let dither_matrix: [u8; 64] = [
00, 48, 12, 60, 03, 51, 15, 63,
@ -1164,6 +1230,7 @@ impl Renderer {
ImageFormat::A8,
TextureFilter::Nearest,
RenderTargetMode::None,
1,
Some(&dither_matrix));
Some(id)
@ -1202,29 +1269,30 @@ impl Renderer {
},
];
let prim_vao_id = device.create_vao(&DESC_PRIM_INSTANCES, mem::size_of::<PrimitiveInstance>() as i32);
device.bind_vao(prim_vao_id);
device.update_vao_indices(prim_vao_id, &quad_indices, VertexUsageHint::Static);
device.update_vao_main_vertices(prim_vao_id, &quad_vertices, VertexUsageHint::Static);
let prim_vao = device.create_vao(&DESC_PRIM_INSTANCES,
mem::size_of::<PrimitiveInstance>() as i32);
device.bind_vao(&prim_vao);
device.update_vao_indices(&prim_vao,
&quad_indices,
VertexUsageHint::Static);
device.update_vao_main_vertices(&prim_vao,
&quad_vertices,
VertexUsageHint::Static);
let blur_vao_id = device.create_vao_with_new_instances(&DESC_BLUR, mem::size_of::<BlurCommand>() as i32, prim_vao_id);
let clip_vao_id = device.create_vao_with_new_instances(&DESC_CLIP, mem::size_of::<CacheClipInstance>() as i32, prim_vao_id);
let blur_vao = device.create_vao_with_new_instances(&DESC_BLUR,
mem::size_of::<BlurCommand>() as i32,
&prim_vao);
let clip_vao = device.create_vao_with_new_instances(&DESC_CLIP,
mem::size_of::<CacheClipInstance>() as i32,
&prim_vao);
let texture_cache_upload_pbo = device.create_pbo();
let texture_resolver = SourceTextureResolver::new(&mut device);
device.end_frame();
let main_thread_dispatcher = Arc::new(Mutex::new(None));
let backend_notifier = Arc::clone(&notifier);
let backend_main_thread_dispatcher = Arc::clone(&main_thread_dispatcher);
let vr_compositor = Arc::new(Mutex::new(None));
let backend_vr_compositor = Arc::clone(&vr_compositor);
// We need a reference to the webrender context from the render backend in order to share
// texture ids
let context_handle = match options.renderer_kind {
RendererKind::Native => GLContextHandleWrapper::current_native_handle(),
RendererKind::OSMesa => GLContextHandleWrapper::current_osmesa_handle(),
};
let default_font_render_mode = match (options.enable_aa, options.enable_subpixel_aa) {
(true, true) => FontRenderMode::Subpixel,
@ -1236,7 +1304,6 @@ impl Renderer {
enable_scrollbars: options.enable_scrollbars,
default_font_render_mode,
debug: options.debug,
cache_expiry_frames: options.cache_expiry_frames,
};
let device_pixel_ratio = options.device_pixel_ratio;
@ -1261,12 +1328,9 @@ impl Renderer {
texture_cache,
workers,
backend_notifier,
context_handle,
config,
recorder,
backend_main_thread_dispatcher,
blob_image_renderer,
backend_vr_compositor,
enable_render_on_scroll);
backend.run(backend_profile_counters);
})};
@ -1323,22 +1387,19 @@ impl Renderer {
color_render_targets: Vec::new(),
alpha_render_targets: Vec::new(),
gpu_profile,
prim_vao_id,
blur_vao_id,
clip_vao_id,
prim_vao,
blur_vao,
clip_vao,
gdt_index: 0,
gpu_data_textures,
pipeline_epoch_map: FastHashMap::default(),
main_thread_dispatcher,
cache_texture_id_map: Vec::new(),
dummy_cache_texture_id,
dither_matrix_texture_id,
external_image_handler: None,
external_images: FastHashMap::default(),
vr_compositor_handler: vr_compositor,
cpu_profiles: VecDeque::new(),
gpu_profiles: VecDeque::new(),
gpu_cache_texture,
texture_cache_upload_pbo,
texture_resolver,
};
let sender = RenderApiSender::new(api_tx, payload_tx);
@ -1370,23 +1431,6 @@ impl Renderer {
*notifier_arc = Some(notifier);
}
/// Sets the new main thread dispatcher.
///
/// Allows to dispatch functions to the main thread's event loop.
pub fn set_main_thread_dispatcher(&self, dispatcher: Box<RenderDispatcher>) {
let mut dispatcher_arc = self.main_thread_dispatcher.lock().unwrap();
*dispatcher_arc = Some(dispatcher);
}
/// Sets the VRCompositorHandler.
///
/// It's used to handle WebVR render commands.
/// Some WebVR commands such as Vsync and SubmitFrame must be called in the WebGL render thread.
pub fn set_vr_compositor_handler(&self, creator: Box<VRCompositorHandler>) {
let mut handler_arc = self.vr_compositor_handler.lock().unwrap();
*handler_arc = Some(creator);
}
/// Returns the Epoch of the current frame in a pipeline.
pub fn current_epoch(&self, pipeline_id: PipelineId) -> Option<Epoch> {
self.pipeline_epoch_map.get(&pipeline_id).cloned()
@ -1445,27 +1489,6 @@ impl Renderer {
}
}
// Get the real (OpenGL) texture ID for a given source texture.
// For a texture cache texture, the IDs are stored in a vector
// map for fast access. For WebGL textures, the native texture ID
// is stored inline. When we add support for external textures,
// we will add a callback here that is able to ask the caller
// for the image data.
fn resolve_source_texture(&mut self, texture_id: &SourceTexture) -> TextureId {
match *texture_id {
SourceTexture::Invalid => TextureId::invalid(),
SourceTexture::WebGL(id) => TextureId::new(id, TextureTarget::Default),
SourceTexture::External(external_image) => {
*self.external_images
.get(&(external_image.id, external_image.channel_index))
.expect("BUG: External image should be resolved by now!")
}
SourceTexture::TextureCache(index) => {
self.cache_texture_id_map[index.0]
}
}
}
/// Set a callback for handling external images.
pub fn set_external_image_handler(&mut self, handler: Box<ExternalImageHandler>) {
self.external_image_handler = Some(handler);
@ -1607,127 +1630,84 @@ impl Renderer {
fn update_texture_cache(&mut self) {
let _gm = GpuMarker::new(self.device.rc_gl(), "texture cache update");
let mut pending_texture_updates = mem::replace(&mut self.pending_texture_updates, vec![]);
for update_list in pending_texture_updates.drain(..) {
for update in update_list.updates {
match update.op {
TextureUpdateOp::Create { width, height, format, filter, mode, data } => {
TextureUpdateOp::Create { width, height, layer_count, format, filter, mode } => {
let CacheTextureId(cache_texture_index) = update.id;
if self.cache_texture_id_map.len() == cache_texture_index {
if self.texture_resolver.cache_texture_id_map.len() == cache_texture_index {
// Create a new native texture, as requested by the texture cache.
let texture_id = self.device
.create_texture_ids(1, TextureTarget::Default)[0];
self.cache_texture_id_map.push(texture_id);
.create_texture_ids(1, TextureTarget::Array)[0];
self.texture_resolver.cache_texture_id_map.push(texture_id);
}
let texture_id = self.cache_texture_id_map[cache_texture_index];
let texture_id = self.texture_resolver.cache_texture_id_map[cache_texture_index];
if let Some(image) = data {
match image {
ImageData::Raw(raw) => {
self.device.init_texture(texture_id,
width,
height,
format,
filter,
mode,
Some(raw.as_slice()));
}
ImageData::External(ext_image) => {
match ext_image.image_type {
ExternalImageType::ExternalBuffer => {
let handler = self.external_image_handler
.as_mut()
.expect("Found external image, but no handler set!");
// Ensure no PBO is bound when creating the texture storage,
// or GL will attempt to read data from there.
self.device.bind_pbo(None);
self.device.init_texture(texture_id,
width,
height,
format,
filter,
mode,
layer_count,
None);
}
TextureUpdateOp::Update { rect, source, stride, layer_index, offset } => {
let texture_id = self.texture_resolver.cache_texture_id_map[update.id.0];
match handler.lock(ext_image.id, ext_image.channel_index).source {
ExternalImageSource::RawData(raw) => {
self.device.init_texture(texture_id,
width,
height,
format,
filter,
mode,
Some(raw));
}
_ => panic!("No external buffer found"),
};
handler.unlock(ext_image.id, ext_image.channel_index);
}
ExternalImageType::Texture2DHandle |
ExternalImageType::TextureRectHandle |
ExternalImageType::TextureExternalHandle => {
panic!("External texture handle should not use TextureUpdateOp::Create.");
}
// Bind a PBO to do the texture upload.
// Updating the texture via PBO avoids CPU-side driver stalls.
self.device.bind_pbo(Some(self.texture_cache_upload_pbo));
match source {
TextureUpdateSource::Bytes { data } => {
self.device.update_pbo_data(&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 {
ExternalImageSource::RawData(data) => {
self.device.update_pbo_data(&data[offset as usize..]);
}
}
_ => {
panic!("No suitable image buffer for TextureUpdateOp::Create.");
}
_ => panic!("No external buffer found"),
};
handler.unlock(id, channel_index);
}
} else {
self.device.init_texture(texture_id,
width,
height,
format,
filter,
mode,
None);
}
}
TextureUpdateOp::Grow { width, height, format, filter, mode } => {
let texture_id = self.cache_texture_id_map[update.id.0];
self.device.resize_texture(texture_id,
width,
height,
format,
filter,
mode);
}
TextureUpdateOp::Update { page_pos_x, page_pos_y, width, height, data, stride, offset } => {
let texture_id = self.cache_texture_id_map[update.id.0];
self.device.update_texture(texture_id,
page_pos_x,
page_pos_y,
width, height, stride,
&data[offset as usize..]);
}
TextureUpdateOp::UpdateForExternalBuffer { rect, id, channel_index, stride, offset } => {
let handler = self.external_image_handler
.as_mut()
.expect("Found external image, but no handler set!");
let device = &mut self.device;
let cached_id = self.cache_texture_id_map[update.id.0];
match handler.lock(id, channel_index).source {
ExternalImageSource::RawData(data) => {
device.update_texture(cached_id,
rect.origin.x,
rect.origin.y,
rect.size.width,
rect.size.height,
stride,
&data[offset as usize..]);
}
_ => panic!("No external buffer found"),
};
handler.unlock(id, channel_index);
self.device.update_texture_from_pbo(texture_id,
rect.origin.x,
rect.origin.y,
rect.size.width,
rect.size.height,
layer_index,
stride,
0);
}
TextureUpdateOp::Free => {
let texture_id = self.cache_texture_id_map[update.id.0];
let texture_id = self.texture_resolver.cache_texture_id_map[update.id.0];
self.device.deinit_texture(texture_id);
}
}
}
}
// Ensure that other texture updates won't read from this PBO.
self.device.bind_pbo(None);
}
fn draw_instanced_batch<T>(&mut self,
data: &[T],
vao: VAOId,
vertex_array_kind: VertexArrayKind,
textures: &BatchTextures) {
self.device.bind_vao(vao);
for i in 0..textures.colors.len() {
let texture_id = self.resolve_source_texture(&textures.colors[i]);
let texture_id = self.texture_resolver.resolve(&textures.colors[i]);
self.device.bind_texture(TextureSampler::color(i), texture_id);
}
@ -1736,6 +1716,14 @@ impl Renderer {
self.device.bind_texture(TextureSampler::Dither, id);
}
let vao = match vertex_array_kind {
VertexArrayKind::Primitive => &self.prim_vao,
VertexArrayKind::Clip => &self.clip_vao,
VertexArrayKind::Blur => &self.blur_vao,
};
self.device.bind_vao(vao);
if self.enable_batcher {
self.device.update_vao_instances(vao, data, VertexUsageHint::Stream);
self.device.draw_indexed_triangles_instanced_u16(6, data.len() as i32);
@ -1755,7 +1743,6 @@ impl Renderer {
batch: &PrimitiveBatch,
projection: &Transform3D<f32>,
render_task_data: &[RenderTaskData],
cache_texture: TextureId,
render_target: Option<(TextureId, i32)>,
target_dimensions: DeviceUintSize) {
let transform_kind = batch.key.flags.transform_kind();
@ -1863,6 +1850,7 @@ impl Renderer {
// they may overlap and affect each other.
debug_assert!(batch.instances.len() == 1);
let instance = CompositePrimitiveInstance::from(&batch.instances[0]);
let cache_texture = self.texture_resolver.resolve(&SourceTexture::CacheRGBA8);
// TODO(gw): This code branch is all a bit hacky. We rely
// on pulling specific values from the render target data
@ -1917,9 +1905,8 @@ impl Renderer {
}
let _gm = self.gpu_profile.add_marker(marker);
let vao = self.prim_vao_id;
self.draw_instanced_batch(&batch.instances,
vao,
VertexArrayKind::Primitive,
&batch.key.textures);
}
@ -1927,7 +1914,6 @@ impl Renderer {
render_target: Option<(TextureId, i32)>,
target: &ColorRenderTarget,
target_size: DeviceUintSize,
color_cache_texture: TextureId,
clear_color: Option<[f32; 4]>,
render_task_data: &[RenderTaskData],
projection: &Transform3D<f32>) {
@ -1965,20 +1951,19 @@ impl Renderer {
// blur radii with fixed weights.
if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
let _gm = self.gpu_profile.add_marker(GPU_TAG_BLUR);
let vao = self.blur_vao_id;
self.device.set_blend(false);
self.cs_blur.bind(&mut self.device, projection);
if !target.vertical_blurs.is_empty() {
self.draw_instanced_batch(&target.vertical_blurs,
vao,
VertexArrayKind::Blur,
&BatchTextures::no_texture());
}
if !target.horizontal_blurs.is_empty() {
self.draw_instanced_batch(&target.horizontal_blurs,
vao,
VertexArrayKind::Blur,
&BatchTextures::no_texture());
}
}
@ -1987,10 +1972,9 @@ impl Renderer {
if !target.box_shadow_cache_prims.is_empty() {
self.device.set_blend(false);
let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_BOX_SHADOW);
let vao = self.prim_vao_id;
self.cs_box_shadow.bind(&mut self.device, projection);
self.draw_instanced_batch(&target.box_shadow_cache_prims,
vao,
VertexArrayKind::Primitive,
&BatchTextures::no_texture());
}
@ -2005,10 +1989,9 @@ impl Renderer {
self.device.set_blend_mode_alpha();
let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_TEXT_RUN);
let vao = self.prim_vao_id;
self.cs_text_run.bind(&mut self.device, projection);
self.draw_instanced_batch(&target.text_run_cache_prims,
vao,
VertexArrayKind::Primitive,
&target.text_run_textures);
}
if !target.line_cache_prims.is_empty() {
@ -2018,10 +2001,9 @@ impl Renderer {
self.device.set_blend_mode_alpha();
let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_LINE);
let vao = self.prim_vao_id;
self.cs_line.bind(&mut self.device, projection);
self.draw_instanced_batch(&target.line_cache_prims,
vao,
VertexArrayKind::Primitive,
&BatchTextures::no_texture());
}
@ -2045,7 +2027,6 @@ impl Renderer {
self.submit_batch(batch,
&projection,
render_task_data,
color_cache_texture,
render_target,
target_size);
}
@ -2077,7 +2058,6 @@ impl Renderer {
self.submit_batch(batch,
&projection,
render_task_data,
color_cache_texture,
render_target,
target_size);
}
@ -2112,7 +2092,6 @@ impl Renderer {
// Draw the clip items into the tiled alpha mask.
{
let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_CLIP);
let vao = self.clip_vao_id;
// If we have border corner clips, the first step is to clear out the
// area in the clip mask. This allows drawing multiple invididual clip
@ -2122,7 +2101,7 @@ impl Renderer {
self.device.set_blend(false);
self.cs_clip_border.bind(&mut self.device, projection);
self.draw_instanced_batch(&target.clip_batcher.border_clears,
vao,
VertexArrayKind::Clip,
&BatchTextures::no_texture());
}
@ -2137,7 +2116,7 @@ impl Renderer {
self.device.set_blend_mode_max();
self.cs_clip_border.bind(&mut self.device, projection);
self.draw_instanced_batch(&target.clip_batcher.borders,
vao,
VertexArrayKind::Clip,
&BatchTextures::no_texture());
}
@ -2150,7 +2129,7 @@ impl Renderer {
let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip rectangles");
self.cs_clip_rectangle.bind(&mut self.device, projection);
self.draw_instanced_batch(&target.clip_batcher.rectangles,
vao,
VertexArrayKind::Clip,
&BatchTextures::no_texture());
}
// draw image masks
@ -2165,7 +2144,7 @@ impl Renderer {
};
self.cs_clip_image.bind(&mut self.device, projection);
self.draw_instanced_batch(items,
vao,
VertexArrayKind::Clip,
&textures);
}
}
@ -2189,6 +2168,7 @@ impl Renderer {
let image = handler.lock(ext_image.id, ext_image.channel_index);
let texture_target = match ext_image.image_type {
ExternalImageType::Texture2DHandle => TextureTarget::Default,
ExternalImageType::Texture2DArrayHandle => TextureTarget::Array,
ExternalImageType::TextureRectHandle => TextureTarget::Rect,
ExternalImageType::TextureExternalHandle => TextureTarget::External,
ExternalImageType::ExternalBuffer => {
@ -2202,26 +2182,29 @@ impl Renderer {
_ => panic!("No native texture found."),
};
self.external_images.insert((ext_image.id, ext_image.channel_index), texture_id);
self.texture_resolver
.external_images
.insert((ext_image.id, ext_image.channel_index), texture_id);
let update = GpuCacheUpdate::Copy {
block_index: 0,
block_count: 1,
address: deferred_resolve.address,
};
let blocks = [ [image.u0, image.v0, image.u1, image.v1].into() ];
let blocks = [ [image.u0, image.v0, image.u1, image.v1].into(), [0.0; 4].into() ];
self.gpu_cache_texture.apply_patch(&update, &blocks);
}
}
}
fn unlock_external_images(&mut self) {
if !self.external_images.is_empty() {
if !self.texture_resolver.external_images.is_empty() {
let handler = self.external_image_handler
.as_mut()
.expect("Found external image, but no handler set!");
for (ext_data, _) in self.external_images.drain() {
for (ext_data, _) in self.texture_resolver.external_images.drain() {
handler.unlock(ext_data.0, ext_data.1);
}
}
@ -2264,7 +2247,8 @@ impl Renderer {
frame.cache_size.height as u32,
ImageFormat::BGRA8,
TextureFilter::Linear,
RenderTargetMode::LayerRenderTarget(target_count as i32),
RenderTargetMode::RenderTarget,
target_count as i32,
None);
}
if let Some(texture_id) = pass.alpha_texture_id {
@ -2274,7 +2258,8 @@ impl Renderer {
frame.cache_size.height as u32,
ImageFormat::A8,
TextureFilter::Nearest,
RenderTargetMode::LayerRenderTarget(target_count as i32),
RenderTargetMode::RenderTarget,
target_count as i32,
None);
}
}
@ -2285,6 +2270,7 @@ impl Renderer {
// number of driver stalls.
self.gpu_data_textures[self.gdt_index].init_frame(&mut self.device, frame);
self.gdt_index = (self.gdt_index + 1) % GPU_DATA_TEXTURE_POOL;
self.texture_resolver.set_cache_textures(None, None);
}
fn draw_tile_frame(&mut self,
@ -2307,9 +2293,6 @@ impl Renderer {
} else {
self.start_frame(frame);
let mut src_color_id = self.dummy_cache_texture_id;
let mut src_alpha_id = self.dummy_cache_texture_id;
for pass in &mut frame.passes {
let size;
let clear_color;
@ -2341,8 +2324,10 @@ impl Renderer {
ORTHO_FAR_PLANE);
}
self.device.bind_texture(TextureSampler::CacheA8, src_alpha_id);
self.device.bind_texture(TextureSampler::CacheRGBA8, src_color_id);
let cache_a8_texture = self.texture_resolver.resolve(&SourceTexture::CacheA8);
let cache_rgba8_texture = self.texture_resolver.resolve(&SourceTexture::CacheRGBA8);
self.device.bind_texture(TextureSampler::CacheA8, cache_a8_texture);
self.device.bind_texture(TextureSampler::CacheRGBA8, cache_rgba8_texture);
for (target_index, target) in pass.alpha_targets.targets.iter().enumerate() {
self.draw_alpha_target((pass.alpha_texture_id.unwrap(), target_index as i32),
@ -2358,15 +2343,13 @@ impl Renderer {
self.draw_color_target(render_target,
target,
*size,
src_color_id,
clear_color,
&frame.render_task_data,
&projection);
}
src_color_id = pass.color_texture_id.unwrap_or(self.dummy_cache_texture_id);
src_alpha_id = pass.alpha_texture_id.unwrap_or(self.dummy_cache_texture_id);
self.texture_resolver.set_cache_textures(pass.alpha_texture_id, pass.color_texture_id);
// Return the texture IDs to the pool for next frame.
if let Some(texture_id) = pass.color_texture_id.take() {
@ -2443,25 +2426,37 @@ impl Renderer {
let mut spacing = 16;
let mut size = 512;
let fb_width = framebuffer_size.width as i32;
let num_textures = self.cache_texture_id_map.len() as i32;
let num_layers: i32 = self.texture_resolver
.cache_texture_id_map
.iter()
.map(|id| {
self.device.get_texture_layer_count(*id)
})
.sum();
if num_textures * (size + spacing) > fb_width {
let factor = fb_width as f32 / (num_textures * (size + spacing)) as f32;
if num_layers * (size + spacing) > fb_width {
let factor = fb_width as f32 / (num_layers * (size + spacing)) as f32;
size = (size as f32 * factor) as i32;
spacing = (spacing as f32 * factor) as i32;
}
for (i, texture_id) in self.cache_texture_id_map.iter().enumerate() {
let x = fb_width - (spacing + size) * (i as i32 + 1);
let mut i = 0;
for texture_id in &self.texture_resolver.cache_texture_id_map {
let y = spacing + if self.debug_flags.contains(RENDER_TARGET_DBG) { 528 } else { 0 };
// If we have more targets than fit on one row in screen, just early exit.
if x > fb_width {
return;
}
let layer_count = self.device.get_texture_layer_count(*texture_id);
for layer_index in 0..layer_count {
let x = fb_width - (spacing + size) * (i as i32 + 1);
let dest_rect = rect(x, y, size, size);
self.device.blit_render_target(Some((*texture_id, 0)), None, dest_rect);
// If we have more targets than fit on one row in screen, just early exit.
if x > fb_width {
return;
}
let dest_rect = rect(x, y, size, size);
self.device.blit_render_target(Some((*texture_id, layer_index)), None, dest_rect);
i += 1;
}
}
}
@ -2494,7 +2489,10 @@ impl Renderer {
pub fn deinit(mut self) {
//Note: this is a fake frame, only needed because texture deletion is require to happen inside a frame
self.device.begin_frame(1.0);
self.device.deinit_texture(self.dummy_cache_texture_id);
self.texture_resolver.deinit(&mut self.device);
self.device.delete_vao(self.prim_vao);
self.device.delete_vao(self.clip_vao);
self.device.delete_vao(self.blur_vao);
self.debug.deinit(&mut self.device);
self.cs_box_shadow.deinit(&mut self.device);
self.cs_text_run.deinit(&mut self.device);
@ -2507,13 +2505,13 @@ impl Renderer {
self.ps_rectangle_clip.deinit(&mut self.device);
self.ps_text_run.deinit(&mut self.device);
self.ps_text_run_subpixel.deinit(&mut self.device);
for shader in &mut self.ps_image {
if let &mut Some(ref mut shader) = shader {
for shader in self.ps_image {
if let Some(shader) = shader {
shader.deinit(&mut self.device);
}
}
for shader in &mut self.ps_yuv_image {
if let &mut Some(ref mut shader) = shader {
for shader in self.ps_yuv_image {
if let Some(shader) = shader {
shader.deinit(&mut self.device);
}
}
@ -2587,7 +2585,6 @@ pub struct RendererOptions {
pub enable_clear_scissor: bool,
pub enable_batcher: bool,
pub max_texture_size: Option<u32>,
pub cache_expiry_frames: u32,
pub workers: Option<Arc<ThreadPool>>,
pub blob_image_renderer: Option<Box<BlobImageRenderer>>,
pub recorder: Option<Box<ApiRecordingReceiver>>,
@ -2614,7 +2611,6 @@ impl Default for RendererOptions {
enable_clear_scissor: true,
enable_batcher: true,
max_texture_size: None,
cache_expiry_frames: 600, // roughly, 10 seconds
workers: None,
blob_image_renderer: None,
recorder: None,

View File

@ -8,21 +8,20 @@ use glyph_cache::GlyphCache;
use gpu_cache::{GpuCache, GpuCacheHandle};
use internal_types::{FastHashMap, FastHashSet, SourceTexture, TextureUpdateList};
use profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
use std::cmp;
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
use std::fmt::Debug;
use std::hash::Hash;
use std::mem;
use std::sync::Arc;
use texture_cache::{TextureCache, TextureCacheItemId};
use texture_cache::{TextureCache, TextureCacheHandle};
use api::{BlobImageRenderer, BlobImageDescriptor, BlobImageError, BlobImageRequest};
use api::{BlobImageResources, BlobImageData, ResourceUpdates, ResourceUpdate, AddFont};
use api::{DevicePoint, DeviceIntSize, DeviceUintRect, DeviceUintSize};
use api::{Epoch, FontInstanceKey, FontKey, FontTemplate};
use api::{DevicePoint, DeviceUintRect, DeviceUintSize};
use api::{Epoch, FontInstance, FontKey, FontTemplate};
use api::{GlyphDimensions, GlyphKey, IdNamespace};
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering};
use api::{TileOffset, TileSize};
use api::{ExternalImageData, ExternalImageType, WebGLContextId};
use api::{ExternalImageData, ExternalImageType};
use rayon::ThreadPool;
use glyph_rasterizer::{GlyphRasterizer, GlyphRequest};
@ -102,85 +101,44 @@ impl ImageTemplates {
}
struct CachedImageInfo {
texture_cache_id: TextureCacheItemId,
texture_cache_handle: TextureCacheHandle,
epoch: Epoch,
last_access: FrameId,
}
pub struct ResourceClassCache<K,V> {
resources: FastHashMap<K, V>,
}
impl<K,V> ResourceClassCache<K,V> where K: Clone + Hash + Eq + Debug, V: Resource {
impl<K,V> ResourceClassCache<K,V> where K: Clone + Hash + Eq + Debug {
pub fn new() -> ResourceClassCache<K,V> {
ResourceClassCache {
resources: FastHashMap::default(),
}
}
fn get(&self, key: &K, frame: FrameId) -> &V {
let resource = self.resources
.get(key)
.expect("Didn't find a cached resource with that ID!");
// This assert catches cases in which we accidentally request a resource that we forgot to
// mark as needed this frame.
debug_assert_eq!(frame, resource.get_last_access_time());
resource
fn get(&self, key: &K) -> &V {
self.resources
.get(key)
.expect("Didn't find a cached resource with that ID!")
}
pub fn insert(&mut self, key: K, value: V) {
self.resources.insert(key, value);
}
pub fn entry(&mut self, key: K, frame: FrameId) -> Entry<K,V> {
let mut entry = self.resources.entry(key);
match entry {
Occupied(ref mut entry) => {
entry.get_mut().set_last_access_time(frame);
}
Vacant(..) => {}
}
entry
pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
self.resources.get_mut(key)
}
pub fn is_empty(&self) -> bool {
self.resources.is_empty()
pub fn entry(&mut self, key: K) -> Entry<K,V> {
self.resources.entry(key)
}
pub fn update(&mut self,
texture_cache: &mut TextureCache,
gpu_cache: &mut GpuCache,
current_frame_id: FrameId,
expiry_frame_id: FrameId) {
let mut resources_to_destroy = Vec::new();
for (key, resource) in &self.resources {
let last_access = resource.get_last_access_time();
if last_access < expiry_frame_id {
resources_to_destroy.push(key.clone());
} else if last_access == current_frame_id {
resource.add_to_gpu_cache(texture_cache, gpu_cache);
}
}
for key in resources_to_destroy {
let resource =
self.resources
.remove(&key)
.expect("Resource was in `last_access_times` but not in `resources`!");
resource.free(texture_cache);
}
pub fn clear(&mut self) {
self.resources.clear();
}
pub fn clear(&mut self, texture_cache: &mut TextureCache) {
for (_, resource) in self.resources.drain() {
resource.free(texture_cache);
}
}
fn clear_keys<F>(&mut self, texture_cache: &mut TextureCache, key_fun: F)
fn clear_keys<F>(&mut self, key_fun: F)
where for<'r> F: Fn(&'r &K) -> bool
{
let resources_to_destroy = self.resources.keys()
@ -188,8 +146,7 @@ impl<K,V> ResourceClassCache<K,V> where K: Clone + Hash + Eq + Debug, V: Resourc
.cloned()
.collect::<Vec<_>>();
for key in resources_to_destroy {
let resource = self.resources.remove(&key).unwrap();
resource.free(texture_cache);
self.resources.remove(&key).unwrap();
}
}
}
@ -211,11 +168,6 @@ impl Into<BlobImageRequest> for ImageRequest {
}
}
pub struct WebGLTexture {
pub id: SourceTexture,
pub size: DeviceIntSize,
}
struct Resources {
font_templates: FastHashMap<FontKey, FontTemplate>,
image_templates: ImageTemplates,
@ -234,9 +186,6 @@ pub struct ResourceCache {
cached_glyphs: GlyphCache,
cached_images: ResourceClassCache<ImageRequest, CachedImageInfo>,
// TODO(pcwalton): Figure out the lifecycle of these.
webgl_textures: FastHashMap<WebGLContextId, WebGLTexture>,
resources: Resources,
state: State,
current_frame_id: FrameId,
@ -253,19 +202,15 @@ pub struct ResourceCache {
pending_image_requests: FastHashSet<ImageRequest>,
blob_image_renderer: Option<Box<BlobImageRenderer>>,
cache_expiry_frames: u32,
}
impl ResourceCache {
pub fn new(texture_cache: TextureCache,
workers: Arc<ThreadPool>,
blob_image_renderer: Option<Box<BlobImageRenderer>>,
cache_expiry_frames: u32) -> ResourceCache {
blob_image_renderer: Option<Box<BlobImageRenderer>>) -> ResourceCache {
ResourceCache {
cached_glyphs: GlyphCache::new(),
cached_images: ResourceClassCache::new(),
webgl_textures: FastHashMap::default(),
resources: Resources {
font_templates: FastHashMap::default(),
image_templates: ImageTemplates::new(),
@ -277,7 +222,6 @@ impl ResourceCache {
pending_image_requests: FastHashSet::default(),
glyph_rasterizer: GlyphRasterizer::new(workers),
blob_image_renderer,
cache_expiry_frames,
}
}
@ -426,7 +370,7 @@ impl ResourceCache {
pub fn delete_image_template(&mut self, image_key: ImageKey) {
let value = self.resources.image_templates.remove(image_key);
self.cached_images.clear_keys(&mut self.texture_cache, |request| request.key == image_key);
self.cached_images.clear_keys(|request| request.key == image_key);
match value {
Some(image) => {
@ -440,25 +384,11 @@ impl ResourceCache {
}
}
pub fn add_webgl_texture(&mut self, id: WebGLContextId, texture_id: SourceTexture, size: DeviceIntSize) {
self.webgl_textures.insert(id, WebGLTexture {
id: texture_id,
size,
});
}
pub fn update_webgl_texture(&mut self, id: WebGLContextId, texture_id: SourceTexture, size: DeviceIntSize) {
let webgl_texture = self.webgl_textures.get_mut(&id).unwrap();
// Update new texture id and size
webgl_texture.id = texture_id;
webgl_texture.size = size;
}
pub fn request_image(&mut self,
key: ImageKey,
rendering: ImageRendering,
tile: Option<TileOffset>) {
tile: Option<TileOffset>,
gpu_cache: &mut GpuCache) {
debug_assert_eq!(self.state, State::AddResources);
let request = ImageRequest {
@ -467,74 +397,92 @@ impl ResourceCache {
tile,
};
let template = self.resources.image_templates.get(key).unwrap();
// Images that don't use the texture cache can early out.
if !template.data.uses_texture_cache() {
return;
}
// If this image exists in the texture cache, *and* the epoch
// in the cache matches that of the template, then it is
// valid to use as-is.
match self.cached_images.entry(request, self.current_frame_id) {
Occupied(entry) => {
let cached_image = entry.get();
if cached_image.epoch == template.epoch {
match self.resources.image_templates.get(key) {
Some(template) => {
// Images that don't use the texture cache can early out.
if !template.data.uses_texture_cache() {
return;
}
}
Vacant(..) => {}
}
// We can start a worker thread rasterizing right now, if:
// - The image is a blob.
// - The blob hasn't already been requested this frame.
if self.pending_image_requests.insert(request) {
if template.data.is_blob() {
if let Some(ref mut renderer) = self.blob_image_renderer {
let (offset, w, h) = match template.tiling {
Some(tile_size) => {
let tile_offset = request.tile.unwrap();
let (w, h) = compute_tile_size(&template.descriptor, tile_size, tile_offset);
let offset = DevicePoint::new(
tile_offset.x as f32 * tile_size as f32,
tile_offset.y as f32 * tile_size as f32,
);
// If this image exists in the texture cache, *and* the epoch
// in the cache matches that of the template, then it is
// valid to use as-is.
let (entry, needs_update) = match self.cached_images.entry(request) {
Occupied(entry) => {
let needs_update = entry.get().epoch != template.epoch;
(entry.into_mut(), needs_update)
}
Vacant(entry) => {
(entry.insert(CachedImageInfo {
epoch: template.epoch,
texture_cache_handle: TextureCacheHandle::new(),
}), true)
}
};
(offset, w, h)
}
None => {
(DevicePoint::zero(), template.descriptor.width, template.descriptor.height)
}
};
let needs_upload = self.texture_cache
.request(&mut entry.texture_cache_handle,
gpu_cache);
renderer.request(
&self.resources,
request.into(),
&BlobImageDescriptor {
width: w,
height: h,
offset,
format: template.descriptor.format,
},
template.dirty_rect,
);
if !needs_upload && !needs_update {
return;
}
// We can start a worker thread rasterizing right now, if:
// - The image is a blob.
// - The blob hasn't already been requested this frame.
if self.pending_image_requests.insert(request) {
if template.data.is_blob() {
if let Some(ref mut renderer) = self.blob_image_renderer {
let (offset, w, h) = match template.tiling {
Some(tile_size) => {
let tile_offset = request.tile.unwrap();
let (w, h) = compute_tile_size(&template.descriptor, tile_size, tile_offset);
let offset = DevicePoint::new(
tile_offset.x as f32 * tile_size as f32,
tile_offset.y as f32 * tile_size as f32,
);
(offset, w, h)
}
None => {
(DevicePoint::zero(), template.descriptor.width, template.descriptor.height)
}
};
renderer.request(
&self.resources,
request.into(),
&BlobImageDescriptor {
width: w,
height: h,
offset,
format: template.descriptor.format,
},
template.dirty_rect,
);
}
}
}
}
None => {
warn!("ERROR: Trying to render deleted / non-existent key {:?}", key);
}
}
}
pub fn request_glyphs(&mut self,
font: FontInstanceKey,
glyph_keys: &[GlyphKey]) {
font: FontInstance,
glyph_keys: &[GlyphKey],
gpu_cache: &mut GpuCache) {
debug_assert_eq!(self.state, State::AddResources);
self.glyph_rasterizer.request_glyphs(
&mut self.cached_glyphs,
self.current_frame_id,
font,
glyph_keys,
&mut self.texture_cache,
gpu_cache,
);
}
@ -543,7 +491,7 @@ impl ResourceCache {
}
pub fn get_glyphs<F>(&self,
font: FontInstanceKey,
font: FontInstance,
glyph_keys: &[GlyphKey],
mut f: F) -> SourceTexture where F: FnMut(usize, &GpuCacheHandle) {
debug_assert_eq!(self.state, State::QueryResources);
@ -552,10 +500,8 @@ impl ResourceCache {
let glyph_key_cache = self.cached_glyphs.get_glyph_key_cache_for_font(&font);
for (loop_index, key) in glyph_keys.iter().enumerate() {
let glyph = glyph_key_cache.get(key, self.current_frame_id);
let cache_item = glyph.texture_cache_id
.as_ref()
.map(|image_id| self.texture_cache.get(image_id));
let glyph = glyph_key_cache.get(key);
let cache_item = glyph.as_ref().map(|info| self.texture_cache.get(&info.texture_cache_handle));
if let Some(cache_item) = cache_item {
f(loop_index, &cache_item.uv_rect_handle);
debug_assert!(texture_id == None ||
@ -564,11 +510,11 @@ impl ResourceCache {
}
}
texture_id.map_or(SourceTexture::Invalid, SourceTexture::TextureCache)
texture_id.unwrap_or(SourceTexture::Invalid)
}
pub fn get_glyph_dimensions(&mut self,
font: &FontInstanceKey,
font: &FontInstance,
key: &GlyphKey) -> Option<GlyphDimensions> {
let key = GlyphRequest::new(font, key);
@ -595,38 +541,37 @@ impl ResourceCache {
rendering: image_rendering,
tile,
};
let image_info = &self.cached_images.get(&key, self.current_frame_id);
let item = self.texture_cache.get(&image_info.texture_cache_id);
CacheItem {
texture_id: SourceTexture::TextureCache(item.texture_id),
uv_rect_handle: item.uv_rect_handle,
}
let image_info = &self.cached_images.get(&key);
self.texture_cache.get(&image_info.texture_cache_handle)
}
pub fn get_image_properties(&self, image_key: ImageKey) -> ImageProperties {
let image_template = &self.resources.image_templates.get(image_key).unwrap();
pub fn get_image_properties(&self, image_key: ImageKey) -> Option<ImageProperties> {
let image_template = &self.resources.image_templates.get(image_key);
let external_image = match image_template.data {
ImageData::External(ext_image) => {
match ext_image.image_type {
ExternalImageType::Texture2DHandle |
ExternalImageType::TextureRectHandle |
ExternalImageType::TextureExternalHandle => {
Some(ext_image)
},
// external buffer uses resource_cache.
ExternalImageType::ExternalBuffer => None,
}
},
// raw and blob image are all using resource_cache.
ImageData::Raw(..) | ImageData::Blob(..) => None,
};
image_template.map(|image_template| {
let external_image = match image_template.data {
ImageData::External(ext_image) => {
match ext_image.image_type {
ExternalImageType::Texture2DHandle |
ExternalImageType::Texture2DArrayHandle |
ExternalImageType::TextureRectHandle |
ExternalImageType::TextureExternalHandle => {
Some(ext_image)
},
// external buffer uses resource_cache.
ExternalImageType::ExternalBuffer => None,
}
},
// raw and blob image are all using resource_cache.
ImageData::Raw(..) | ImageData::Blob(..) => None,
};
ImageProperties {
descriptor: image_template.descriptor,
external_image,
tiling: image_template.tiling,
}
ImageProperties {
descriptor: image_template.descriptor,
external_image,
tiling: image_template.tiling,
}
})
}
pub fn get_tiled_image_map(&self) -> TiledImageMap {
@ -639,17 +584,10 @@ impl ResourceCache {
).collect()
}
pub fn get_webgl_texture(&self, context_id: &WebGLContextId) -> &WebGLTexture {
&self.webgl_textures[context_id]
}
pub fn get_webgl_texture_size(&self, context_id: &WebGLContextId) -> DeviceIntSize {
self.webgl_textures[context_id].size
}
pub fn begin_frame(&mut self, frame_id: FrameId) {
debug_assert_eq!(self.state, State::Idle);
self.state = State::AddResources;
self.texture_cache.begin_frame(frame_id);
self.current_frame_id = frame_id;
}
@ -662,29 +600,20 @@ impl ResourceCache {
self.state = State::QueryResources;
self.glyph_rasterizer.resolve_glyphs(
self.current_frame_id,
&mut self.cached_glyphs,
&mut self.texture_cache,
gpu_cache,
texture_cache_profile,
);
// Apply any updates of new / updated images (incl. blobs) to the texture cache.
self.update_texture_cache(texture_cache_profile);
// Expire any resources that haven't been used for `cache_expiry_frames`.
let num_frames_back = self.cache_expiry_frames;
let expiry_frame = FrameId(cmp::max(num_frames_back, self.current_frame_id.0) - num_frames_back);
self.cached_images.update(&mut self.texture_cache,
gpu_cache,
self.current_frame_id,
expiry_frame);
self.cached_glyphs.update(&mut self.texture_cache,
gpu_cache,
self.current_frame_id,
expiry_frame);
self.update_texture_cache(gpu_cache, texture_cache_profile);
self.texture_cache.end_frame();
}
fn update_texture_cache(&mut self, texture_cache_profile: &mut TextureCacheProfileCounters) {
fn update_texture_cache(&mut self,
gpu_cache: &mut GpuCache,
_texture_cache_profile: &mut TextureCacheProfileCounters) {
for request in self.pending_image_requests.drain() {
let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
debug_assert!(image_template.data.uses_texture_cache());
@ -757,38 +686,15 @@ impl ResourceCache {
image_template.descriptor.clone()
};
match self.cached_images.entry(request, self.current_frame_id) {
Occupied(mut entry) => {
let entry = entry.get_mut();
// We should only get to this code path if the image
// definitely needs to be updated.
debug_assert!(entry.epoch != image_template.epoch);
self.texture_cache.update(&entry.texture_cache_id,
descriptor,
filter,
image_data,
image_template.dirty_rect);
// Update the cached epoch
debug_assert_eq!(self.current_frame_id, entry.last_access);
entry.epoch = image_template.epoch;
image_template.dirty_rect = None;
}
Vacant(entry) => {
let image_id = self.texture_cache.insert(descriptor,
filter,
image_data,
[0.0; 2],
texture_cache_profile);
entry.insert(CachedImageInfo {
texture_cache_id: image_id,
epoch: image_template.epoch,
last_access: self.current_frame_id,
});
}
};
let entry = self.cached_images.get_mut(&request).unwrap();
self.texture_cache.update(&mut entry.texture_cache_handle,
descriptor,
filter,
image_data,
[0.0; 2],
image_template.dirty_rect,
gpu_cache);
image_template.dirty_rect = None;
}
}
@ -806,8 +712,8 @@ impl ResourceCache {
// The advantage of clearing the cache completely is that it gets rid of any
// remaining fragmentation that could have persisted if we kept around the most
// recently used resources.
self.cached_images.clear(&mut self.texture_cache);
self.cached_glyphs.clear(&mut self.texture_cache);
self.cached_images.clear();
self.cached_glyphs.clear();
}
pub fn clear_namespace(&mut self, namespace: IdNamespace) {
@ -828,37 +734,8 @@ impl ResourceCache {
self.resources.font_templates.remove(key);
}
self.cached_images.clear_keys(&mut self.texture_cache, |request| request.key.0 == namespace);
self.cached_glyphs.clear_fonts(&mut self.texture_cache, |font| font.font_key.0 == namespace);
}
}
pub trait Resource {
fn free(self, texture_cache: &mut TextureCache);
fn get_last_access_time(&self) -> FrameId;
fn set_last_access_time(&mut self, frame_id: FrameId);
fn add_to_gpu_cache(&self,
texture_cache: &mut TextureCache,
gpu_cache: &mut GpuCache);
}
impl Resource for CachedImageInfo {
fn free(self, texture_cache: &mut TextureCache) {
texture_cache.free(self.texture_cache_id);
}
fn get_last_access_time(&self) -> FrameId {
self.last_access
}
fn set_last_access_time(&mut self, frame_id: FrameId) {
self.last_access = frame_id;
}
fn add_to_gpu_cache(&self,
texture_cache: &mut TextureCache,
gpu_cache: &mut GpuCache) {
let item = texture_cache.get_mut(&self.texture_cache_id);
if let Some(mut request) = gpu_cache.request(&mut item.uv_rect_handle) {
request.push(item.uv_rect);
}
self.cached_images.clear_keys(|request| request.key.0 == namespace);
self.cached_glyphs.clear_fonts(|font| font.font_key.0 == namespace);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,11 @@
use border::{BorderCornerInstance, BorderCornerSide};
use device::TextureId;
use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheUpdateList};
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuCacheUpdateList};
use internal_types::BatchTextures;
use internal_types::{FastHashMap, SourceTexture};
use mask_cache::MaskCacheInfo;
use prim_store::{CLIP_DATA_GPU_BLOCKS, DeferredResolve, ImagePrimitiveKind, PrimitiveCacheKey};
use prim_store::{CLIP_DATA_GPU_BLOCKS, DeferredResolve, PrimitiveCacheKey};
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
use profiler::FrameProfileCounters;
use render_task::{AlphaRenderItem, MaskGeometryKind, MaskSegment, RenderTask, RenderTaskData};
@ -21,7 +21,7 @@ use std::{f32, i32, mem, usize};
use texture_allocator::GuillotineAllocator;
use util::{TransformedRect, TransformedRectKind};
use api::{BuiltDisplayList, ClipAndScrollInfo, ClipId, ColorF, DeviceIntPoint, ImageKey};
use api::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintSize, FontInstanceKey};
use api::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintSize, FontInstance};
use api::{ExternalImageType, FilterOp, FontRenderMode, ImageRendering, LayerRect};
use api::{LayerToWorldTransform, MixBlendMode, PipelineId, PropertyBinding, TransformStyle};
use api::{TileOffset, WorldToLayerTransform, YuvColorSpace, YuvFormat, LayerVector2D};
@ -431,30 +431,22 @@ impl AlphaRenderItem {
PrimitiveKind::Image => {
let image_cpu = &ctx.prim_store.cpu_images[prim_metadata.cpu_prim_index.0];
let (color_texture_id, uv_address) = match image_cpu.kind {
ImagePrimitiveKind::Image(image_key, image_rendering, tile_offset, _) => {
resolve_image(image_key,
image_rendering,
tile_offset,
ctx.resource_cache,
gpu_cache,
deferred_resolves)
}
ImagePrimitiveKind::WebGL(context_id) => {
let webgl_texture = ctx.resource_cache.get_webgl_texture(&context_id);
let uv_rect = [ 0.0,
webgl_texture.size.height as f32,
webgl_texture.size.width as f32,
0.0];
let cache_handle = gpu_cache.push_per_frame_blocks(&[uv_rect.into()]);
(webgl_texture.id, cache_handle)
}
};
let (color_texture_id, uv_address) = resolve_image(image_cpu.image_key,
image_cpu.image_rendering,
image_cpu.tile_offset,
ctx.resource_cache,
gpu_cache,
deferred_resolves);
if color_texture_id == SourceTexture::Invalid {
return;
}
let batch_kind = match color_texture_id {
SourceTexture::External(ext_image) => {
match ext_image.image_type {
ExternalImageType::Texture2DHandle => AlphaBatchKind::Image(ImageBufferKind::Texture2D),
ExternalImageType::Texture2DArrayHandle => AlphaBatchKind::Image(ImageBufferKind::Texture2DArray),
ExternalImageType::TextureRectHandle => AlphaBatchKind::Image(ImageBufferKind::TextureRect),
ExternalImageType::TextureExternalHandle => AlphaBatchKind::Image(ImageBufferKind::TextureExternal),
ExternalImageType::ExternalBuffer => {
@ -465,7 +457,7 @@ impl AlphaRenderItem {
}
}
_ => {
AlphaBatchKind::Image(ImageBufferKind::Texture2D)
AlphaBatchKind::Image(ImageBufferKind::Texture2DArray)
}
};
@ -484,12 +476,12 @@ impl AlphaRenderItem {
// TODO(gw): avoid / recycle this allocation in the future.
let mut instances = Vec::new();
let font = FontInstanceKey::new(text_cpu.font_key,
font_size_dp,
text_cpu.color,
text_cpu.normal_render_mode,
text_cpu.glyph_options,
text_cpu.subpx_dir);
let font = FontInstance::new(text_cpu.font_key,
font_size_dp,
text_cpu.color,
text_cpu.normal_render_mode,
text_cpu.glyph_options,
text_cpu.subpx_dir);
let texture_id = ctx.resource_cache.get_glyphs(font,
&text_cpu.glyph_keys,
@ -513,7 +505,8 @@ impl AlphaRenderItem {
let cache_task_id = prim_metadata.render_task.as_ref().expect("no render task!").id;
let cache_task_index = render_tasks.get_task_index(&cache_task_id,
child_pass_index);
let key = AlphaBatchKey::new(AlphaBatchKind::CacheImage, flags, blend_mode, no_textures);
let textures = BatchTextures::render_target_cache();
let key = AlphaBatchKey::new(AlphaBatchKind::CacheImage, flags, blend_mode, textures);
let batch = batch_list.get_suitable_batch(&key, item_bounding_rect);
batch.add_instance(base_instance.build(0, cache_task_index.0 as i32, 0));
}
@ -552,6 +545,11 @@ impl AlphaRenderItem {
ctx.resource_cache,
gpu_cache,
deferred_resolves);
if texture == SourceTexture::Invalid {
return;
}
textures.colors[channel] = texture;
uv_rect_addresses[channel] = address.as_int(gpu_cache);
}
@ -561,6 +559,7 @@ impl AlphaRenderItem {
SourceTexture::External(ext_image) => {
match ext_image.image_type {
ExternalImageType::Texture2DHandle => ImageBufferKind::Texture2D,
ExternalImageType::Texture2DArrayHandle => ImageBufferKind::Texture2DArray,
ExternalImageType::TextureRectHandle => ImageBufferKind::TextureRect,
ExternalImageType::TextureExternalHandle => ImageBufferKind::TextureExternal,
ExternalImageType::ExternalBuffer => {
@ -571,7 +570,7 @@ impl AlphaRenderItem {
}
}
_ => {
ImageBufferKind::Texture2D
ImageBufferKind::Texture2DArray
}
}
};
@ -702,82 +701,88 @@ impl ClipBatcher {
for &(packed_layer_index, ref info) in clips.iter() {
let instance = CacheClipInstance {
task_id: task_index.0 as i32,
render_task_index: task_index.0 as i32,
layer_index: packed_layer_index.0 as i32,
address: 0,
segment: 0,
resource_address: 0,
clip_data_address: GpuCacheAddress::invalid(),
resource_address: GpuCacheAddress::invalid(),
};
for clip_index in 0 .. info.complex_clip_range.get_count() {
let gpu_address = info.complex_clip_range.location.as_int(gpu_cache) +
(CLIP_DATA_GPU_BLOCKS * clip_index) as i32;
match geometry_kind {
MaskGeometryKind::Default => {
self.rectangles.push(CacheClipInstance {
address: gpu_address,
segment: MaskSegment::All as i32,
..instance
});
}
MaskGeometryKind::CornersOnly => {
self.rectangles.extend_from_slice(&[
CacheClipInstance {
address: gpu_address,
segment: MaskSegment::TopLeftCorner as i32,
if !info.complex_clip_range.is_empty() {
let base_gpu_address = gpu_cache.get_address(&info.complex_clip_range.location);
for clip_index in 0 .. info.complex_clip_range.get_count() {
let gpu_address = base_gpu_address + CLIP_DATA_GPU_BLOCKS * clip_index;
match geometry_kind {
MaskGeometryKind::Default => {
self.rectangles.push(CacheClipInstance {
clip_data_address: gpu_address,
segment: MaskSegment::All as i32,
..instance
},
CacheClipInstance {
address: gpu_address,
segment: MaskSegment::TopRightCorner as i32,
..instance
},
CacheClipInstance {
address: gpu_address,
segment: MaskSegment::BottomLeftCorner as i32,
..instance
},
CacheClipInstance {
address: gpu_address,
segment: MaskSegment::BottomRightCorner as i32,
..instance
},
]);
});
}
MaskGeometryKind::CornersOnly => {
self.rectangles.extend_from_slice(&[
CacheClipInstance {
clip_data_address: gpu_address,
segment: MaskSegment::TopLeftCorner as i32,
..instance
},
CacheClipInstance {
clip_data_address: gpu_address,
segment: MaskSegment::TopRightCorner as i32,
..instance
},
CacheClipInstance {
clip_data_address: gpu_address,
segment: MaskSegment::BottomLeftCorner as i32,
..instance
},
CacheClipInstance {
clip_data_address: gpu_address,
segment: MaskSegment::BottomRightCorner as i32,
..instance
},
]);
}
}
}
}
for clip_index in 0 .. info.layer_clip_range.get_count() {
let gpu_address = info.layer_clip_range.location.as_int(gpu_cache) +
(CLIP_DATA_GPU_BLOCKS * clip_index) as i32;
self.rectangles.push(CacheClipInstance {
address: gpu_address,
segment: MaskSegment::All as i32,
..instance
});
if !info.layer_clip_range.is_empty() {
let base_gpu_address = gpu_cache.get_address(&info.layer_clip_range.location);
for clip_index in 0 .. info.layer_clip_range.get_count() {
let gpu_address = base_gpu_address + CLIP_DATA_GPU_BLOCKS * clip_index;
self.rectangles.push(CacheClipInstance {
clip_data_address: gpu_address,
segment: MaskSegment::All as i32,
..instance
});
}
}
if let Some((ref mask, gpu_location)) = info.image {
if let Some((ref mask, ref gpu_location)) = info.image {
let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None);
self.images.entry(cache_item.texture_id)
.or_insert(Vec::new())
.push(CacheClipInstance {
address: gpu_location.as_int(gpu_cache),
resource_address: cache_item.uv_rect_handle.as_int(gpu_cache),
clip_data_address: gpu_cache.get_address(gpu_location),
resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle),
..instance
})
}
for &(ref source, gpu_location) in &info.border_corners {
let gpu_address = gpu_location.as_int(gpu_cache);
for &(ref source, ref gpu_location) in &info.border_corners {
let gpu_address = gpu_cache.get_address(gpu_location);
self.border_clears.push(CacheClipInstance {
address: gpu_address,
clip_data_address: gpu_address,
segment: 0,
..instance
});
for clip_index in 0..source.actual_clip_count {
self.borders.push(CacheClipInstance {
address: gpu_address,
clip_data_address: gpu_address,
segment: 1 + clip_index as i32,
..instance
})
@ -1058,12 +1063,12 @@ impl RenderTarget for ColorRenderTarget {
let text = &ctx.prim_store.cpu_text_runs[sub_metadata.cpu_prim_index.0];
let font_size_dp = text.logical_font_size.scale_by(ctx.device_pixel_ratio);
let font = FontInstanceKey::new(text.font_key,
font_size_dp,
text.color,
text.shadow_render_mode,
text.glyph_options,
text.subpx_dir);
let font = FontInstance::new(text.font_key,
font_size_dp,
text.color,
text.shadow_render_mode,
text.glyph_options,
text.subpx_dir);
let texture_id = ctx.resource_cache.get_glyphs(font,
&text.glyph_keys,
@ -1375,12 +1380,13 @@ pub struct BlurCommand {
/// Could be an image or a rectangle, which defines the
/// way `address` is treated.
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct CacheClipInstance {
task_id: i32,
render_task_index: i32,
layer_index: i32,
address: i32,
segment: i32,
resource_address: i32,
clip_data_address: GpuCacheAddress,
resource_address: GpuCacheAddress,
}
// 32 bytes per instance should be enough for anyone!
@ -1721,30 +1727,33 @@ fn resolve_image(image_key: ImageKey,
resource_cache: &ResourceCache,
gpu_cache: &mut GpuCache,
deferred_resolves: &mut Vec<DeferredResolve>) -> (SourceTexture, GpuCacheHandle) {
let image_properties = resource_cache.get_image_properties(image_key);
match resource_cache.get_image_properties(image_key) {
Some(image_properties) => {
// Check if an external image that needs to be resolved
// by the render thread.
match image_properties.external_image {
Some(external_image) => {
// This is an external texture - we will add it to
// the deferred resolves list to be patched by
// the render thread...
let cache_handle = gpu_cache.push_deferred_per_frame_blocks(1);
deferred_resolves.push(DeferredResolve {
image_properties,
address: gpu_cache.get_address(&cache_handle),
});
// Check if an external image that needs to be resolved
// by the render thread.
match image_properties.external_image {
Some(external_image) => {
// This is an external texture - we will add it to
// the deferred resolves list to be patched by
// the render thread...
let cache_handle = gpu_cache.push_deferred_per_frame_blocks(1);
deferred_resolves.push(DeferredResolve {
image_properties,
address: gpu_cache.get_address(&cache_handle),
});
(SourceTexture::External(external_image), cache_handle)
}
None => {
let cache_item = resource_cache.get_cached_image(image_key,
image_rendering,
tile_offset);
(SourceTexture::External(external_image), cache_handle)
}
None => {
let cache_item = resource_cache.get_cached_image(image_key,
image_rendering,
tile_offset);
(cache_item.texture_id, cache_item.uv_rect_handle)
(cache_item.texture_id, cache_item.uv_rect_handle)
}
}
}
None => (SourceTexture::Invalid, GpuCacheHandle::new()),
}
}

View File

@ -1,59 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Stubs for the types contained in webgl_types.rs
//!
//! The API surface provided here should be roughly the same to the one provided
//! in webgl_types, modulo completely compiled-out stuff.
use api::DeviceIntSize;
use api::{GLContextAttributes, GLLimits};
use api::WebGLCommand;
pub struct GLContextHandleWrapper;
impl GLContextHandleWrapper {
pub fn new_context(&self,
_: DeviceIntSize,
_: GLContextAttributes,
_: Option<Box<GLContextDispatcher>>) -> Result<GLContextWrapper, &'static str> {
unreachable!()
}
pub fn current_native_handle() -> Option<GLContextHandleWrapper> {
None
}
pub fn current_osmesa_handle() -> Option<GLContextHandleWrapper> {
None
}
}
pub struct GLContextWrapper;
impl GLContextWrapper {
pub fn make_current(&self) {
unreachable!()
}
pub fn unbind(&self) {
unreachable!()
}
pub fn apply_command(&self, _: WebGLCommand) {
unreachable!()
}
pub fn get_info(&self) -> (DeviceIntSize, u32, GLLimits) {
unreachable!()
}
pub fn resize(&mut self, _: &DeviceIntSize) -> Result<(), &'static str> {
unreachable!()
}
}
pub trait GLContextDispatcher {
fn dispatch(&self, Box<Fn() + Send>);
}

View File

@ -1,130 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! A set of WebGL-related types, in their own module so it's easy to
//! compile it off.
use gleam::gl;
use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle};
use offscreen_gl_context::{GLContext, NativeGLContextMethods, GLContextDispatcher};
use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle};
use offscreen_gl_context::{ColorAttachmentType, GLContextAttributes, GLLimits};
use api::{WebGLCommand, DeviceIntSize};
pub enum GLContextHandleWrapper {
Native(NativeGLContextHandle),
OSMesa(OSMesaContextHandle),
}
impl GLContextHandleWrapper {
pub fn current_native_handle() -> Option<GLContextHandleWrapper> {
NativeGLContext::current_handle().map(GLContextHandleWrapper::Native)
}
pub fn current_osmesa_handle() -> Option<GLContextHandleWrapper> {
OSMesaContext::current_handle().map(GLContextHandleWrapper::OSMesa)
}
pub fn new_context(&self,
size: DeviceIntSize,
attributes: GLContextAttributes,
dispatcher: Option<Box<GLContextDispatcher>>) -> Result<GLContextWrapper, &'static str> {
match *self {
GLContextHandleWrapper::Native(ref handle) => {
let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size.to_untyped(),
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(handle),
dispatcher);
ctx.map(GLContextWrapper::Native)
}
GLContextHandleWrapper::OSMesa(ref handle) => {
let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(),
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(handle),
dispatcher);
ctx.map(GLContextWrapper::OSMesa)
}
}
}
}
pub enum GLContextWrapper {
Native(GLContext<NativeGLContext>),
OSMesa(GLContext<OSMesaContext>),
}
impl GLContextWrapper {
pub fn make_current(&self) {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.make_current().unwrap();
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.make_current().unwrap();
}
}
}
pub fn unbind(&self) {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.unbind().unwrap();
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.unbind().unwrap();
}
}
}
pub fn apply_command(&self, cmd: WebGLCommand) {
match *self {
GLContextWrapper::Native(ref ctx) => {
cmd.apply(ctx);
}
GLContextWrapper::OSMesa(ref ctx) => {
cmd.apply(ctx);
}
}
}
pub fn get_info(&self) -> (DeviceIntSize, u32, GLLimits) {
match *self {
GLContextWrapper::Native(ref ctx) => {
let (real_size, texture_id) = {
let draw_buffer = ctx.borrow_draw_buffer().unwrap();
(draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
};
let limits = ctx.borrow_limits().clone();
(DeviceIntSize::from_untyped(&real_size), texture_id, limits)
}
GLContextWrapper::OSMesa(ref ctx) => {
let (real_size, texture_id) = {
let draw_buffer = ctx.borrow_draw_buffer().unwrap();
(draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
};
let limits = ctx.borrow_limits().clone();
(DeviceIntSize::from_untyped(&real_size), texture_id, limits)
}
}
}
pub fn resize(&mut self, size: &DeviceIntSize) -> Result<(), &'static str> {
match *self {
GLContextWrapper::Native(ref mut ctx) => {
ctx.resize(size.to_untyped())
}
GLContextWrapper::OSMesa(ref mut ctx) => {
ctx.resize(size.to_untyped())
}
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "webrender_api"
version = "0.48.0"
version = "0.49.0"
authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
license = "MPL-2.0"
repository = "https://github.com/servo/webrender"
@ -8,7 +8,6 @@ repository = "https://github.com/servo/webrender"
[features]
nightly = ["euclid/unstable", "serde/unstable"]
ipc = ["ipc-channel"]
webgl = ["offscreen_gl_context"]
[dependencies]
app_units = "0.5"
@ -16,10 +15,8 @@ bincode = "0.8"
byteorder = "1.0"
euclid = "0.15"
fxhash = "0.2.1"
gleam = "0.4.5"
heapsize = ">= 0.3.6, < 0.5"
ipc-channel = {version = "0.8", optional = true}
offscreen_gl_context = {version = "0.11", features = ["serde"], optional = true}
serde = { version = "1.0", features = ["rc", "derive"] }
time = "0.1"

View File

@ -3,17 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use channel::{self, MsgSender, Payload, PayloadSenderHelperMethods, PayloadSender};
#[cfg(feature = "webgl")]
use offscreen_gl_context::{GLContextAttributes, GLLimits};
use std::cell::Cell;
use std::fmt;
use std::marker::PhantomData;
use {BuiltDisplayList, BuiltDisplayListDescriptor, ClipId, ColorF, DeviceIntPoint, DeviceIntSize};
use {BuiltDisplayList, BuiltDisplayListDescriptor, ClipId, ColorF, DeviceIntPoint};
use {DeviceUintRect, DeviceUintSize, FontKey, GlyphDimensions, GlyphKey};
use {ImageData, ImageDescriptor, ImageKey, LayoutPoint, LayoutVector2D, LayoutSize, LayoutTransform};
use {FontInstanceKey, NativeFontHandle, WorldPoint};
#[cfg(feature = "webgl")]
use {WebGLCommand, WebGLContextId};
use {FontInstance, NativeFontHandle, WorldPoint};
pub type TileSize = u16;
@ -148,7 +144,7 @@ pub enum ApiMsg {
/// Add/remove/update images and fonts.
UpdateResources(ResourceUpdates),
/// Gets the glyph dimensions
GetGlyphDimensions(FontInstanceKey, Vec<GlyphKey>, MsgSender<Vec<Option<GlyphDimensions>>>),
GetGlyphDimensions(FontInstance, Vec<GlyphKey>, MsgSender<Vec<Option<GlyphDimensions>>>),
/// Gets the glyph indices from a string
GetGlyphIndices(FontKey, String, MsgSender<Vec<Option<u32>>>),
/// Adds a new document namespace.
@ -159,11 +155,6 @@ pub enum ApiMsg {
UpdateDocument(DocumentId, DocumentMsg),
/// Deletes an existing document.
DeleteDocument(DocumentId),
RequestWebGLContext(DeviceIntSize, GLContextAttributes, MsgSender<Result<(WebGLContextId, GLLimits), String>>),
ResizeWebGLContext(WebGLContextId, DeviceIntSize),
WebGLCommand(WebGLContextId, WebGLCommand),
// WebVR commands that must be called in the WebGL render thread.
VRCompositorCommand(WebGLContextId, VRCompositorCommand),
/// An opaque handle that must be passed to the render notifier. It is used by Gecko
/// to forward gecko-specific messages to the render thread preserving the ordering
/// within the other messages.
@ -185,10 +176,6 @@ impl fmt::Debug for ApiMsg {
ApiMsg::AddDocument(..) => "ApiMsg::AddDocument",
ApiMsg::UpdateDocument(..) => "ApiMsg::UpdateDocument",
ApiMsg::DeleteDocument(..) => "ApiMsg::DeleteDocument",
ApiMsg::RequestWebGLContext(..) => "ApiMsg::RequestWebGLContext",
ApiMsg::ResizeWebGLContext(..) => "ApiMsg::ResizeWebGLContext",
ApiMsg::WebGLCommand(..) => "ApiMsg::WebGLCommand",
ApiMsg::VRCompositorCommand(..) => "ApiMsg::VRCompositorCommand",
ApiMsg::ExternalEvent(..) => "ApiMsg::ExternalEvent",
ApiMsg::ClearNamespace(..) => "ApiMsg::ClearNamespace",
ApiMsg::MemoryPressure => "ApiMsg::MemoryPressure",
@ -201,24 +188,6 @@ impl fmt::Debug for ApiMsg {
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Epoch(pub u32);
#[cfg(not(feature = "webgl"))]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct WebGLContextId(pub usize);
#[cfg(not(feature = "webgl"))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GLContextAttributes([u8; 0]);
#[cfg(not(feature = "webgl"))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GLLimits([u8; 0]);
#[cfg(not(feature = "webgl"))]
#[derive(Clone, Deserialize, Serialize)]
pub enum WebGLCommand {
Flush,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
pub struct IdNamespace(pub u32);
@ -343,7 +312,7 @@ impl RenderApi {
/// 'empty' textures (height or width = 0)
/// This means that glyph dimensions e.g. for spaces (' ') will mostly be None.
pub fn get_glyph_dimensions(&self,
font: FontInstanceKey,
font: FontInstance,
glyph_keys: Vec<GlyphKey>)
-> Vec<Option<GlyphDimensions>> {
let (tx, rx) = channel::msg_channel().unwrap();
@ -371,32 +340,12 @@ impl RenderApi {
/// Adds an image identified by the `ImageKey`.
pub fn update_resources(&self, resources: ResourceUpdates) {
if resources.updates.is_empty() {
return;
}
self.api_sender.send(ApiMsg::UpdateResources(resources)).unwrap();
}
pub fn request_webgl_context(&self, size: &DeviceIntSize, attributes: GLContextAttributes)
-> Result<(WebGLContextId, GLLimits), String> {
let (tx, rx) = channel::msg_channel().unwrap();
let msg = ApiMsg::RequestWebGLContext(*size, attributes, tx);
self.api_sender.send(msg).unwrap();
rx.recv().unwrap()
}
pub fn resize_webgl_context(&self, context_id: WebGLContextId, size: &DeviceIntSize) {
let msg = ApiMsg::ResizeWebGLContext(context_id, *size);
self.api_sender.send(msg).unwrap();
}
pub fn send_webgl_command(&self, context_id: WebGLContextId, command: WebGLCommand) {
let msg = ApiMsg::WebGLCommand(context_id, command);
self.api_sender.send(msg).unwrap();
}
pub fn send_vr_compositor_command(&self, context_id: WebGLContextId, command: VRCompositorCommand) {
let msg = ApiMsg::VRCompositorCommand(context_id, command);
self.api_sender.send(msg).unwrap();
}
pub fn send_external_event(&self, evt: ExternalEvent) {
let msg = ApiMsg::ExternalEvent(evt);
self.api_sender.send(msg).unwrap();
@ -705,31 +654,9 @@ pub struct DynamicProperties {
pub floats: Vec<PropertyValue<f32>>,
}
pub type VRCompositorId = u64;
// WebVR commands that must be called in the WebGL render thread.
#[derive(Clone, Deserialize, Serialize)]
pub enum VRCompositorCommand {
Create(VRCompositorId),
SyncPoses(VRCompositorId, f64, f64, MsgSender<Result<Vec<u8>,()>>),
SubmitFrame(VRCompositorId, [f32; 4], [f32; 4]),
Release(VRCompositorId)
}
// Trait object that handles WebVR commands.
// Receives the texture id and size associated to the WebGLContext.
pub trait VRCompositorHandler: Send {
fn handle(&mut self, command: VRCompositorCommand, texture: Option<(u32, DeviceIntSize)>);
}
pub trait RenderNotifier: Send {
fn new_frame_ready(&mut self);
fn new_scroll_frame_ready(&mut self, composite_needed: bool);
fn external_event(&mut self, _evt: ExternalEvent) { unimplemented!() }
fn shut_down(&mut self) {}
}
/// Trait to allow dispatching functions to a specific thread or event loop.
pub trait RenderDispatcher: Send {
fn dispatch(&self, Box<Fn() + Send>);
}

View File

@ -3,9 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use app_units::Au;
use euclid::SideOffsets2D;
use euclid::{SideOffsets2D, TypedSideOffsets2D};
use {ColorF, FontKey, ImageKey, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
use {GlyphOptions, LayoutVector2D, PipelineId, PropertyBinding, WebGLContextId};
use {GlyphOptions, LayoutVector2D, PipelineId, PropertyBinding};
// NOTE: some of these structs have an "IMPLICIT" comment.
// This indicates that the BuiltDisplayList will have serialized
@ -50,12 +50,12 @@ pub struct DisplayItem {
pub enum SpecificDisplayItem {
Clip(ClipDisplayItem),
ScrollFrame(ScrollFrameDisplayItem),
StickyFrame(StickyFrameDisplayItem),
Rectangle(RectangleDisplayItem),
Line(LineDisplayItem),
Text(TextDisplayItem),
Image(ImageDisplayItem),
YuvImage(YuvImageDisplayItem),
WebGL(WebGLDisplayItem),
Border(BorderDisplayItem),
BoxShadow(BoxShadowDisplayItem),
Gradient(GradientDisplayItem),
@ -77,6 +77,20 @@ pub struct ClipDisplayItem {
pub image_mask: Option<ImageMask>,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct StickyFrameDisplayItem {
pub id: ClipId,
pub sticky_frame_info: StickyFrameInfo,
}
pub type StickyFrameInfo = TypedSideOffsets2D<Option<StickySideConstraint>, LayoutPoint>;
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct StickySideConstraint {
pub margin: f32,
pub max_offset: f32,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum ScrollSensitivity {
ScriptAndInputEvents,
@ -131,11 +145,6 @@ pub struct TextDisplayItem {
pub glyph_options: Option<GlyphOptions>,
} // IMPLICIT: glyphs: Vec<GlyphInstance>
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct WebGLDisplayItem {
pub context_id: WebGLContextId,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct NormalBorder {
pub left: BorderSide,
@ -663,11 +672,12 @@ macro_rules! define_empty_heap_size_of {
}
}
define_empty_heap_size_of!(ClipId);
define_empty_heap_size_of!(RepeatMode);
define_empty_heap_size_of!(ImageKey);
define_empty_heap_size_of!(MixBlendMode);
define_empty_heap_size_of!(TransformStyle);
define_empty_heap_size_of!(LocalClip);
define_empty_heap_size_of!(ScrollSensitivity);
define_empty_heap_size_of!(ClipAndScrollInfo);
define_empty_heap_size_of!(ClipId);
define_empty_heap_size_of!(ImageKey);
define_empty_heap_size_of!(LocalClip);
define_empty_heap_size_of!(MixBlendMode);
define_empty_heap_size_of!(RepeatMode);
define_empty_heap_size_of!(ScrollSensitivity);
define_empty_heap_size_of!(StickySideConstraint);
define_empty_heap_size_of!(TransformStyle);

View File

@ -9,15 +9,15 @@ use serde::ser::{SerializeSeq, SerializeMap};
use time::precise_time_ns;
use {BorderDetails, BorderDisplayItem, BorderWidths, BoxShadowClipMode, BoxShadowDisplayItem};
use {ClipAndScrollInfo, ClipDisplayItem, ClipId, ColorF, ComplexClipRegion, DisplayItem};
use {ExtendMode, FilterOp, FontKey, GlyphIndex, GlyphInstance, GlyphOptions, Gradient};
use {GradientDisplayItem, GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask};
use {ImageRendering, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
use {LineDisplayItem, LineOrientation, LineStyle, LocalClip, MixBlendMode, PipelineId};
use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity};
use {SpecificDisplayItem, StackingContext, TextDisplayItem, TextShadow, TransformStyle};
use {WebGLContextId, WebGLDisplayItem, YuvColorSpace, YuvData, YuvImageDisplayItem};
use {FastHashMap, FastHashSet};
use {ExtendMode, FastHashMap, FastHashSet, FilterOp, FontKey, GlyphIndex, GlyphInstance};
use {GlyphOptions, Gradient, GradientDisplayItem, GradientStop, IframeDisplayItem};
use {ImageDisplayItem, ImageKey, ImageMask, ImageRendering, LayoutPoint, LayoutRect, LayoutSize};
use {LayoutTransform, LayoutVector2D, LineDisplayItem, LineOrientation, LineStyle, LocalClip};
use {MixBlendMode, PipelineId, PropertyBinding, PushStackingContextDisplayItem, RadialGradient};
use {RadialGradientDisplayItem, RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy};
use {ScrollSensitivity, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem};
use {StickyFrameInfo, TextDisplayItem, TextShadow, TransformStyle};
use {YuvColorSpace, YuvData, YuvImageDisplayItem};
use std::marker::PhantomData;
#[repr(C)]
@ -597,16 +597,6 @@ impl DisplayListBuilder {
self.push_item(item, rect, local_clip);
}
pub fn push_webgl_canvas(&mut self,
rect: LayoutRect,
local_clip: Option<LocalClip>,
context_id: WebGLContextId) {
let item = SpecificDisplayItem::WebGL(WebGLDisplayItem {
context_id,
});
self.push_item(item, rect, local_clip);
}
pub fn push_text(&mut self,
rect: LayoutRect,
local_clip: Option<LocalClip>,
@ -968,6 +958,21 @@ impl DisplayListBuilder {
id
}
pub fn define_sticky_frame(&mut self,
id: Option<ClipId>,
frame_rect: LayoutRect,
sticky_frame_info: StickyFrameInfo)
-> ClipId {
let id = self.generate_clip_id(id);
let item = SpecificDisplayItem::StickyFrame(StickyFrameDisplayItem {
id,
sticky_frame_info,
});
self.push_item(item, frame_rect, None);
id
}
pub fn push_clip_id(&mut self, id: ClipId) {
self.clip_stack.push(ClipAndScrollInfo::simple(id));
}

View File

@ -145,7 +145,7 @@ pub struct GlyphOptions {
}
#[derive(Clone, Hash, PartialEq, Eq, Debug, Deserialize, Serialize, Ord, PartialOrd)]
pub struct FontInstanceKey {
pub struct FontInstance {
pub font_key: FontKey,
// The font size is in *device* pixels, not logical pixels.
// It is stored as an Au since we need sub-pixel sizes, but
@ -159,13 +159,13 @@ pub struct FontInstanceKey {
pub subpx_dir: SubpixelDirection,
}
impl FontInstanceKey {
impl FontInstance {
pub fn new(font_key: FontKey,
size: Au,
mut color: ColorF,
render_mode: FontRenderMode,
glyph_options: Option<GlyphOptions>,
subpx_dir: SubpixelDirection) -> FontInstanceKey {
subpx_dir: SubpixelDirection) -> FontInstance {
// In alpha/mono mode, the color of the font is irrelevant.
// Forcing it to black in those cases saves rasterizing glyphs
// of different colors when not needed.
@ -173,7 +173,7 @@ impl FontInstanceKey {
color = ColorF::new(0.0, 0.0, 0.0, 1.0);
}
FontInstanceKey {
FontInstance {
font_key,
size,
color: color.into(),

View File

@ -33,6 +33,7 @@ pub struct ExternalImageId(pub u64);
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum ExternalImageType {
Texture2DHandle, // gl TEXTURE_2D handle
Texture2DArrayHandle, // gl TEXTURE_2D_ARRAY handle
TextureRectHandle, // gl TEXTURE_RECT handle
TextureExternalHandle, // gl TEXTURE_EXTERNAL handle
ExternalBuffer,
@ -131,6 +132,7 @@ impl ImageData {
&ImageData::External(ext_data) => {
match ext_data.image_type {
ExternalImageType::Texture2DHandle => false,
ExternalImageType::Texture2DArrayHandle => false,
ExternalImageType::TextureRectHandle => false,
ExternalImageType::TextureExternalHandle => false,
ExternalImageType::ExternalBuffer => true,

View File

@ -12,13 +12,10 @@ extern crate byteorder;
extern crate core;
extern crate euclid;
extern crate fxhash;
extern crate gleam;
#[macro_use]
extern crate heapsize;
#[cfg(feature = "ipc")]
extern crate ipc_channel;
#[cfg(feature = "webgl")]
extern crate offscreen_gl_context;
#[macro_use]
extern crate serde;
extern crate time;
@ -40,8 +37,6 @@ mod display_item;
mod display_list;
mod font;
mod image;
#[cfg(feature = "webgl")]
mod webgl;
pub use api::*;
pub use color::*;
@ -50,8 +45,6 @@ pub use display_list::*;
pub use font::*;
pub use image::*;
pub use units::*;
#[cfg(feature = "webgl")]
pub use webgl::*;
use std::hash::BuildHasherDefault;
use std::collections::{HashMap, HashSet};

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ authors = ["The Mozilla Project Developers"]
license = "MPL-2.0"
[dependencies]
webrender_api = {path = "../webrender_api", version = "0.48.0"}
webrender_api = {path = "../webrender_api", version = "0.49.0"}
rayon = "0.8"
thread_profiler = "0.1.1"
euclid = "0.15"
@ -14,5 +14,5 @@ gleam = "0.4"
[dependencies.webrender]
path = "../webrender"
version = "0.48.0"
version = "0.49.0"
default-features = false