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
Родитель 29fb7aad8e
Коммит 83c2515b8a
60 изменённых файлов: 2618 добавлений и 4044 удалений

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

@ -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 the need to run the cargo update command in js/src as well. Hopefully this will
be resolved soon. be resolved soon.
Latest Commit: 101c69db1a989fe89c308dabd53cf50aedfe4a96 Latest Commit: 1007a65c6dd1fdfb8b39d57d7faff3cae7b32e0c

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

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

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

@ -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();
});
}

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

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

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

@ -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);
}

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

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

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

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

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

@ -11,7 +11,7 @@ void main(void) {
clamp(vClipMaskUv.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)); clamp(vClipMaskUv.xy, vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 source_uv = clamp(clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy, vec2 source_uv = clamp(clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy,
vClipMaskUvInnerRect.xy, vClipMaskUvInnerRect.zw); 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); oFragColor = vec4(min(alpha, clip_alpha), 1.0, 1.0, 1.0);
} }

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

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

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

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

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

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

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

@ -3,5 +3,5 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
varying vec2 vUv; varying vec3 vUv;
flat varying vec4 vColor; flat varying vec4 vColor;

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

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

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

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

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

@ -3,25 +3,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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_LEFT 0
#define PST_TOP 1 #define PST_TOP 1
#define PST_TOP_RIGHT 2 #define PST_TOP_RIGHT 2
@ -129,6 +110,13 @@ ivec2 get_resource_cache_uv(int address) {
uniform HIGHP_SAMPLER_FLOAT sampler2D sResourceCache; 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) { vec4[2] fetch_from_resource_cache_2(int address) {
ivec2 uv = get_resource_cache_uv(address); ivec2 uv = get_resource_cache_uv(address);
return vec4[2]( 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) { vec4 fetch_from_resource_cache_1(int address) {
ivec2 uv = get_resource_cache_uv(address); ivec2 uv = get_resource_cache_uv(address);
return texelFetch(sResourceCache, uv, 0); return texelFetch(sResourceCache, uv, 0);
@ -771,21 +763,28 @@ TransformVertexInfo write_transform_vertex(RectWithSize instance_rect,
struct GlyphResource { struct GlyphResource {
vec4 uv_rect; vec4 uv_rect;
float layer;
vec2 offset; vec2 offset;
}; };
GlyphResource fetch_glyph_resource(int address) { GlyphResource fetch_glyph_resource(int address) {
vec4 data[2] = fetch_from_resource_cache_2(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 { struct ImageResource {
vec4 uv_rect; vec4 uv_rect;
float layer;
}; };
ImageResource fetch_image_resource(int address) { ImageResource fetch_image_resource(int address) {
vec4 data = fetch_from_resource_cache_1(address); vec4 data[2] = fetch_from_resource_cache_2(address);
return ImageResource(data); 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 { struct Rectangle {

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

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

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

@ -28,5 +28,5 @@ void main(void) {
alpha = alpha * float(all(bvec2(step(position_in_tile, vStretchSize)))); 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));
} }

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

@ -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 vTextureSize; // Size of the image in the texture atlas.
flat varying vec2 vTileSpacing; // Amount of space between tiled instances of this image. flat varying vec2 vTileSpacing; // Amount of space between tiled instances of this image.
flat varying vec4 vStRect; // Rectangle of valid texture rect. flat varying vec4 vStRect; // Rectangle of valid texture rect.
flat varying float vLayer;
#ifdef WR_FEATURE_TRANSFORM #ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos; varying vec3 vLocalPos;

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

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

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

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
void main(void) { 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 #ifdef WR_FEATURE_SUBPIXEL_AA
//note: the blend mode is not compatible with clipping //note: the blend mode is not compatible with clipping
oFragColor = texture(sColor0, tc); oFragColor = texture(sColor0, tc);

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

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

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

@ -48,6 +48,6 @@ void main(void) {
vec2 st1 = res.uv_rect.zw / texture_size; vec2 st1 = res.uv_rect.zw / texture_size;
vColor = text.color; 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; vUvBorder = (res.uv_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
} }

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

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

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

@ -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 vStretchSize;
flat varying vec2 vHalfTexelY; // Normalized length of the half of a Y texel. 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 vec2 vHalfTexelUv; // Normalized length of the half of u and v texels.
flat varying vec3 vLayers;
#ifdef WR_FEATURE_TRANSFORM #ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos; varying vec3 vLocalPos;

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

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

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

@ -14,8 +14,8 @@
// The textureLod() doesn't support sampler2DRect for WR_FEATURE_TEXTURE_RECT, too. // The textureLod() doesn't support sampler2DRect for WR_FEATURE_TEXTURE_RECT, too.
// //
// Use texture() instead. // Use texture() instead.
#if defined(WR_FEATURE_TEXTURE_EXTERNAL) || defined(WR_FEATURE_TEXTURE_RECT) #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) #define TEX_SAMPLE(sampler, tex_coord) texture(sampler, tex_coord.xy)
#else #else
// In normal case, we use textureLod(). We haven't used the lod yet. So, we always pass 0.0 now. // 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) #define TEX_SAMPLE(sampler, tex_coord) textureLod(sampler, tex_coord, 0.0)
@ -52,7 +52,30 @@
//====================================================================================== //======================================================================================
// Shared shader uniforms // 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 sColor0;
uniform sampler2DRect sColor1; uniform sampler2DRect sColor1;
uniform sampler2DRect sColor2; uniform sampler2DRect sColor2;
@ -61,9 +84,9 @@ uniform samplerExternalOES sColor0;
uniform samplerExternalOES sColor1; uniform samplerExternalOES sColor1;
uniform samplerExternalOES sColor2; uniform samplerExternalOES sColor2;
#else #else
uniform sampler2D sColor0; uniform sampler2DArray sColor0;
uniform sampler2D sColor1; uniform sampler2DArray sColor1;
uniform sampler2D sColor2; uniform sampler2DArray sColor2;
#endif #endif
#ifdef WR_FEATURE_DITHERING #ifdef WR_FEATURE_DITHERING

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

@ -4,7 +4,9 @@
use api::{ClipId, DeviceIntRect, LayerPixel, LayerPoint, LayerRect, LayerSize}; use api::{ClipId, DeviceIntRect, LayerPixel, LayerPoint, LayerRect, LayerSize};
use api::{LayerToScrollTransform, LayerToWorldTransform, LayerVector2D, PipelineId}; 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 geometry::ray_intersects_rect;
use mask_cache::{ClipRegion, ClipSource, MaskCacheInfo}; use mask_cache::{ClipRegion, ClipSource, MaskCacheInfo};
use spring::{DAMPING, STIFFNESS, Spring}; use spring::{DAMPING, STIFFNESS, Spring};
@ -61,15 +63,21 @@ impl ClipInfo {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum NodeType { pub enum NodeType {
/// Transform for this layer, relative to parent reference frame. A reference /// A reference frame establishes a new coordinate space in the tree.
/// frame establishes a new coordinate space in the tree. ReferenceFrame(ReferenceFrameInfo),
ReferenceFrame(LayerToScrollTransform),
/// Other nodes just do clipping, but no transformation. /// Other nodes just do clipping, but no transformation.
Clip(ClipInfo), 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), 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. /// Contains information common among all types of ClipScrollTree nodes.
@ -159,9 +167,15 @@ impl ClipScrollNode {
pub fn new_reference_frame(parent_id: Option<ClipId>, pub fn new_reference_frame(parent_id: Option<ClipId>,
local_viewport_rect: &LayerRect, local_viewport_rect: &LayerRect,
content_size: LayerSize, content_size: LayerSize,
local_transform: &LayerToScrollTransform, transform: &LayerToScrollTransform,
origin_in_parent_reference_frame: LayerVector2D,
pipeline_id: PipelineId) pipeline_id: PipelineId)
-> ClipScrollNode { -> ClipScrollNode {
let info = ReferenceFrameInfo {
transform: *transform,
origin_in_parent_reference_frame,
};
ClipScrollNode { ClipScrollNode {
content_size, content_size,
local_viewport_rect: *local_viewport_rect, local_viewport_rect: *local_viewport_rect,
@ -173,26 +187,45 @@ impl ClipScrollNode {
parent: parent_id, parent: parent_id,
children: Vec::new(), children: Vec::new(),
pipeline_id, 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) { pub fn add_child(&mut self, child: ClipId) {
self.children.push(child); self.children.push(child);
} }
pub fn apply_old_scrolling_state(&mut self, new_scrolling: &ScrollingState) { pub fn apply_old_scrolling_state(&mut self, new_scrolling: &ScrollingState) {
match self.node_type { 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) => { NodeType::ScrollFrame(ref mut scrolling) => {
let scroll_sensitivity = scrolling.scroll_sensitivity; let scroll_sensitivity = scrolling.scroll_sensitivity;
*scrolling = *new_scrolling; *scrolling = *new_scrolling;
scrolling.scroll_sensitivity = scroll_sensitivity; 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 scrollable_width = self.scrollable_width();
let scrolling = match self.node_type { let scrolling = match self.node_type {
NodeType::ReferenceFrame(_) | NodeType::Clip(_) => { NodeType::ScrollFrame(ref mut scrolling) => scrolling,
_ => {
warn!("Tried to scroll a non-scroll node."); warn!("Tried to scroll a non-scroll node.");
return false; return false;
} }
NodeType::ScrollFrame(ref mut scrolling) => scrolling,
}; };
let new_offset = match clamp { let new_offset = match clamp {
@ -231,41 +264,53 @@ impl ClipScrollNode {
true true
} }
pub fn update_transform(&mut self, pub fn update_transform(&mut self, state: &TransformUpdateState) {
parent_reference_frame_transform: &LayerToWorldTransform, let scrolled_parent_combined_clip = state.parent_combined_viewport_rect
parent_combined_viewport_rect: &LayerRect, .translate(&-state.parent_scroll_offset);
parent_scroll_offset: LayerVector2D,
parent_accumulated_scroll_offset: LayerVector2D) {
let scrolled_parent_combined_clip = parent_combined_viewport_rect let (local_transform, accumulated_scroll_offset) = match self.node_type {
.translate(&-parent_scroll_offset); NodeType::ReferenceFrame(ref info) => {
self.combined_local_viewport_rect =
let (local_transform, combined_clip, reference_frame_scroll_offset) = match self.node_type { info.transform.with_destination::<LayerPixel>()
NodeType::ReferenceFrame(transform) => { .inverse_rect_footprint(&scrolled_parent_combined_clip);
let combined_clip = transform.with_destination::<LayerPixel>() self.reference_frame_relative_scroll_offset = LayerVector2D::zero();
.inverse_rect_footprint(&scrolled_parent_combined_clip); (info.transform, state.parent_accumulated_scroll_offset)
(transform, combined_clip, LayerVector2D::zero())
} }
NodeType::Clip(_) | NodeType::ScrollFrame(_) => { NodeType::Clip(_) | NodeType::ScrollFrame(_) => {
// Move the parent's viewport into the local space (of the node origin) // 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. // and intersect with the local clip rectangle to get the local viewport.
let combined_clip = scrolled_parent_combined_clip.intersection(&self.local_clip_rect) self.combined_local_viewport_rect =
.unwrap_or(LayerRect::zero()); scrolled_parent_combined_clip.intersection(&self.local_clip_rect)
(LayerToScrollTransform::identity(), combined_clip, parent_accumulated_scroll_offset) .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 // The transformation for this viewport in world coordinates is the transformation for
// our parent reference frame, plus any accumulated scrolling offsets from nodes // our parent reference frame, plus any accumulated scrolling offsets from nodes
// between our reference frame and this node. For reference frames, we also include // between our reference frame and this node. For reference frames, we also include
// whatever local transformation this reference frame provides. This can be combined // whatever local transformation this reference frame provides. This can be combined
// with the local_viewport_rect to get its position in world space. // with the local_viewport_rect to get its position in world space.
self.world_viewport_transform = self.world_viewport_transform =
parent_reference_frame_transform state.parent_reference_frame_transform
.pre_translate(parent_accumulated_scroll_offset.to_3d()) .pre_translate(accumulated_scroll_offset.to_3d())
.pre_mul(&local_transform.with_destination::<LayerPixel>()); .pre_mul(&local_transform.with_destination::<LayerPixel>());
// The transformation for any content inside of us is the viewport transformation, plus // 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()); 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 { pub fn scrollable_height(&self) -> f32 {
self.content_size.height - self.local_viewport_rect.size.height self.content_size.height - self.local_viewport_rect.size.height
} }
@ -288,8 +371,8 @@ impl ClipScrollNode {
let scrollable_height = self.scrollable_height(); let scrollable_height = self.scrollable_height();
let scrolling = match self.node_type { let scrolling = match self.node_type {
NodeType::ReferenceFrame(_) | NodeType::Clip(_) => return false,
NodeType::ScrollFrame(ref mut scrolling) => scrolling, NodeType::ScrollFrame(ref mut scrolling) => scrolling,
_ => return false,
}; };
if scrolling.started_bouncing_back && phase == ScrollEventPhase::Move(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,
}

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

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

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

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

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

@ -5,7 +5,6 @@
use euclid::Transform3D; use euclid::Transform3D;
use gleam::gl; use gleam::gl;
use internal_types::{RenderTargetMode, TextureSampler, DEFAULT_TEXTURE, FastHashMap}; use internal_types::{RenderTargetMode, TextureSampler, DEFAULT_TEXTURE, FastHashMap};
//use notify::{self, Watcher};
use super::shader_source; use super::shader_source;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
@ -15,7 +14,6 @@ use std::ops::Add;
use std::path::PathBuf; use std::path::PathBuf;
use std::ptr; use std::ptr;
use std::rc::Rc; use std::rc::Rc;
//use std::sync::mpsc::{channel, Sender};
use std::thread; use std::thread;
use api::{ColorF, ImageFormat}; use api::{ColorF, ImageFormat};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintSize}; use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintSize};
@ -89,6 +87,7 @@ pub enum VertexAttributeKind {
F32, F32,
U8Norm, U8Norm,
I32, I32,
U16,
} }
#[derive(Debug)] #[derive(Debug)]
@ -159,6 +158,7 @@ impl VertexAttributeKind {
VertexAttributeKind::F32 => 4, VertexAttributeKind::F32 => 4,
VertexAttributeKind::U8Norm => 1, VertexAttributeKind::U8Norm => 1,
VertexAttributeKind::I32 => 4, VertexAttributeKind::I32 => 4,
VertexAttributeKind::U16 => 2,
} }
} }
} }
@ -201,6 +201,13 @@ impl VertexAttribute {
stride, stride,
offset); 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 { struct Texture {
gl: Rc<gl::Gl>, gl: Rc<gl::Gl>,
id: gl::GLuint, id: gl::GLuint,
layer_count: i32,
format: ImageFormat, format: ImageFormat,
width: u32, width: u32,
height: u32, height: u32,
@ -361,36 +369,22 @@ impl Program {
impl Drop for Program { impl Drop for Program {
fn drop(&mut self) { fn drop(&mut self) {
debug_assert!(thread::panicking() || self.id == 0); debug_assert!(thread::panicking() || self.id == 0, "renderer::deinit not called");
} }
} }
struct VAO { pub struct VAO {
gl: Rc<gl::Gl>,
id: gl::GLuint, id: gl::GLuint,
ibo_id: IBOId, ibo_id: IBOId,
main_vbo_id: VBOId, main_vbo_id: VBOId,
instance_vbo_id: VBOId, instance_vbo_id: VBOId,
instance_stride: gl::GLint, instance_stride: gl::GLint,
owns_indices: bool, owns_vertices_and_indices: bool,
owns_vertices: bool,
owns_instances: bool,
} }
impl Drop for VAO { impl Drop for VAO {
fn drop(&mut self) { fn drop(&mut self) {
self.gl.delete_vertex_arrays(&[self.id]); debug_assert!(thread::panicking() || self.id == 0, "renderer::deinit not called");
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])
}
} }
} }
@ -400,9 +394,6 @@ pub struct TextureId {
target: gl::GLuint, target: gl::GLuint,
} }
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub struct VAOId(gl::GLuint);
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub struct FBOId(gl::GLuint); 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 struct Capabilities {
pub supports_multisampling: bool, pub supports_multisampling: bool,
} }
@ -774,7 +696,7 @@ pub struct Device {
// device state // device state
bound_textures: [TextureId; 16], bound_textures: [TextureId; 16],
bound_program: gl::GLuint, bound_program: gl::GLuint,
bound_vao: VAOId, bound_vao: gl::GLuint,
bound_pbo: PBOId, bound_pbo: PBOId,
bound_read_fbo: FBOId, bound_read_fbo: FBOId,
bound_draw_fbo: FBOId, bound_draw_fbo: FBOId,
@ -791,15 +713,9 @@ pub struct Device {
// resources // resources
resource_override_path: Option<PathBuf>, resource_override_path: Option<PathBuf>,
textures: FastHashMap<TextureId, Texture>, textures: FastHashMap<TextureId, Texture>,
vaos: FastHashMap<VAOId, VAO>,
// misc. // misc.
shader_preamble: String, shader_preamble: String,
//file_watcher: FileWatcherThread,
// Used on android only
#[allow(dead_code)]
next_vao_id: gl::GLuint,
max_texture_size: u32, max_texture_size: u32,
@ -812,11 +728,7 @@ impl Device {
pub fn new(gl: Rc<gl::Gl>, pub fn new(gl: Rc<gl::Gl>,
resource_override_path: Option<PathBuf>, resource_override_path: Option<PathBuf>,
_file_changed_handler: Box<FileWatcherHandler>) -> Device { _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); 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; let max_texture_size = gl.get_integer_v(gl::MAX_TEXTURE_SIZE) as u32;
Device { Device {
@ -833,7 +745,7 @@ impl Device {
bound_textures: [ TextureId::invalid(); 16 ], bound_textures: [ TextureId::invalid(); 16 ],
bound_program: 0, bound_program: 0,
bound_vao: VAOId(0), bound_vao: 0,
bound_pbo: PBOId(0), bound_pbo: PBOId(0),
bound_read_fbo: FBOId(0), bound_read_fbo: FBOId(0),
bound_draw_fbo: FBOId(0), bound_draw_fbo: FBOId(0),
@ -841,13 +753,9 @@ impl Device {
default_draw_fbo: 0, default_draw_fbo: 0,
textures: FastHashMap::default(), textures: FastHashMap::default(),
vaos: FastHashMap::default(),
shader_preamble, shader_preamble,
next_vao_id: 1,
//file_watcher: file_watcher,
max_texture_size, max_texture_size,
frame_id: FrameId(0), frame_id: FrameId(0),
} }
@ -924,8 +832,8 @@ impl Device {
self.gl.use_program(0); self.gl.use_program(0);
// Vertex state // Vertex state
self.bound_vao = VAOId(0); self.bound_vao = 0;
self.clear_vertex_array(); self.gl.bind_vertex_array(0);
// FBO state // FBO state
self.bound_read_fbo = FBOId(self.default_read_fbo); self.bound_read_fbo = FBOId(self.default_read_fbo);
@ -1014,6 +922,7 @@ impl Device {
id, id,
width: 0, width: 0,
height: 0, height: 0,
layer_count: 0,
format: ImageFormat::Invalid, format: ImageFormat::Invalid,
filter: TextureFilter::Nearest, filter: TextureFilter::Nearest,
mode: RenderTargetMode::None, mode: RenderTargetMode::None,
@ -1030,6 +939,11 @@ impl Device {
texture_ids 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 { pub fn get_texture_dimensions(&self, texture_id: TextureId) -> DeviceUintSize {
let texture = &self.textures[&texture_id]; let texture = &self.textures[&texture_id];
DeviceUintSize::new(texture.width, texture.height) 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); 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, pub fn init_texture(&mut self,
texture_id: TextureId, texture_id: TextureId,
width: u32, width: u32,
@ -1077,6 +973,7 @@ impl Device {
format: ImageFormat, format: ImageFormat,
filter: TextureFilter, filter: TextureFilter,
mode: RenderTargetMode, mode: RenderTargetMode,
layer_count: i32,
pixels: Option<&[u8]>) { pixels: Option<&[u8]>) {
debug_assert!(self.inside_frame); debug_assert!(self.inside_frame);
@ -1088,6 +985,7 @@ impl Device {
texture.width = width; texture.width = width;
texture.height = height; texture.height = height;
texture.filter = filter; texture.filter = filter;
texture.layer_count = layer_count;
texture.mode = mode; texture.mode = mode;
} }
@ -1095,22 +993,10 @@ impl Device {
let type_ = gl_type_for_texture_format(format); let type_ = gl_type_for_texture_format(format);
match mode { match mode {
RenderTargetMode::SimpleRenderTarget => { RenderTargetMode::RenderTarget => {
self.bind_texture(DEFAULT_TEXTURE, texture_id); self.bind_texture(DEFAULT_TEXTURE, texture_id);
self.set_texture_parameters(texture_id.target, filter); self.set_texture_parameters(texture_id.target, filter);
self.upload_texture_image(texture_id.target, self.update_texture_storage(texture_id, layer_count, resized);
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);
} }
RenderTargetMode::None => { RenderTargetMode::None => {
self.bind_texture(DEFAULT_TEXTURE, texture_id); self.bind_texture(DEFAULT_TEXTURE, texture_id);
@ -1124,13 +1010,34 @@ impl Device {
} else { } else {
pixels pixels
}; };
self.upload_texture_image(texture_id.target,
width, match texture_id.target {
height, gl::TEXTURE_2D_ARRAY => {
internal_format as u32, self.gl.tex_image_3d(gl::TEXTURE_2D_ARRAY,
gl_format, 0,
type_, internal_format as gl::GLint,
actual_pixels); 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. /// FBOs as required.
pub fn update_texture_storage(&mut self, pub fn update_texture_storage(&mut self,
texture_id: TextureId, texture_id: TextureId,
layer_count: Option<i32>, layer_count: i32,
resized: bool) { resized: bool) {
let texture = self.textures.get_mut(&texture_id).unwrap(); let texture = self.textures.get_mut(&texture_id).unwrap();
match layer_count { assert!(layer_count > 0);
Some(layer_count) => { 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; let current_layer_count = texture.fbo_ids.len() as i32;
// If the texture is already the required size skip. // If the texture is already the required size skip.
if current_layer_count == layer_count && !resized { if current_layer_count == layer_count && !resized {
return; return;
} }
let (internal_format, gl_format) = gl_texture_formats_for_image_format(&*self.gl, 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); let type_ = gl_type_for_texture_format(texture.format);
self.gl.tex_image_3d(texture_id.target, self.gl.tex_image_3d(texture_id.target,
0, 0,
internal_format as gl::GLint, internal_format as gl::GLint,
texture.width as gl::GLint, texture.width as gl::GLint,
texture.height as gl::GLint, texture.height as gl::GLint,
layer_count, layer_count,
0, 0,
gl_format, gl_format,
type_, type_,
None); None);
let needed_layer_count = layer_count - current_layer_count; let needed_layer_count = layer_count - current_layer_count;
if needed_layer_count > 0 { if needed_layer_count > 0 {
// Create more framebuffers to fill the gap // Create more framebuffers to fill the gap
let new_fbos = self.gl.gen_framebuffers(needed_layer_count); let new_fbos = self.gl.gen_framebuffers(needed_layer_count);
texture.fbo_ids.extend(new_fbos.into_iter().map(|id| FBOId(id))); texture.fbo_ids.extend(new_fbos.into_iter().map(|id| FBOId(id)));
} else if needed_layer_count < 0 { } else if needed_layer_count < 0 {
// Remove extra framebuffers // Remove extra framebuffers
for old in texture.fbo_ids.drain(layer_count as usize ..) { for old in texture.fbo_ids.drain(layer_count as usize ..) {
self.gl.delete_framebuffers(&[old.0]); 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);
}
} }
None => { }
if texture.fbo_ids.is_empty() {
assert!(texture_id.target != gl::TEXTURE_2D_ARRAY);
let new_fbo = self.gl.gen_framebuffers(1)[0]; let depth_rb = if let Some(rbo) = texture.depth_rb {
self.gl.bind_framebuffer(gl::FRAMEBUFFER, new_fbo); 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, for (fbo_index, fbo_id) in texture.fbo_ids.iter().enumerate() {
gl::COLOR_ATTACHMENT0, self.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo_id.0);
texture_id.target, self.gl.framebuffer_texture_layer(gl::FRAMEBUFFER,
texture_id.name, gl::COLOR_ATTACHMENT0,
0); texture_id.name,
0,
texture.fbo_ids.push(FBOId(new_fbo)); fbo_index as gl::GLint);
} else { self.gl.framebuffer_renderbuffer(gl::FRAMEBUFFER,
assert_eq!(texture.fbo_ids.len(), 1); gl::DEPTH_ATTACHMENT,
} gl::RENDERBUFFER,
} depth_rb);
} }
// TODO(gw): Hack! Modify the code above to use the normal binding interfaces the device exposes. // TODO(gw): Hack! Modify the code above to use the normal binding interfaces the device exposes.
@ -1263,52 +1148,6 @@ impl Device {
gl::LINEAR); 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) { pub fn deinit_texture(&mut self, texture_id: TextureId) {
debug_assert!(self.inside_frame); 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 (internal_format, gl_format) = gl_texture_formats_for_image_format(&*self.gl, texture.format);
let type_ = gl_type_for_texture_format(texture.format); let type_ = gl_type_for_texture_format(texture.format);
self.gl.tex_image_2d(texture_id.target, match texture_id.target {
0, gl::TEXTURE_2D_ARRAY => {
internal_format, self.gl.tex_image_3d(gl::TEXTURE_2D_ARRAY,
0, 0,
0, internal_format as gl::GLint,
0, 0,
gl_format, 0,
type_, 0,
None); 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() { if let Some(RBOId(depth_rb)) = texture.depth_rb.take() {
self.gl.delete_renderbuffers(&[depth_rb]); self.gl.delete_renderbuffers(&[depth_rb]);
@ -1340,6 +1196,7 @@ impl Device {
texture.format = ImageFormat::Invalid; texture.format = ImageFormat::Invalid;
texture.width = 0; texture.width = 0;
texture.height = 0; texture.height = 0;
texture.layer_count = 0;
} }
pub fn create_program(&mut self, pub fn create_program(&mut self,
@ -1352,7 +1209,7 @@ impl Device {
descriptor) 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); self.gl.delete_program(program.id);
program.id = 0; program.id = 0;
} }
@ -1507,43 +1364,6 @@ impl Device {
Ok(()) 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 { pub fn get_uniform_location(&self, program: &Program, name: &str) -> UniformLocation {
UniformLocation(self.gl.get_uniform_location(program.id, name)) UniformLocation(self.gl.get_uniform_location(program.id, name))
} }
@ -1610,48 +1430,17 @@ impl Device {
y0: u32, y0: u32,
width: u32, width: u32,
height: u32, height: u32,
layer_index: i32,
stride: Option<u32>,
offset: usize) { offset: usize) {
debug_assert!(self.inside_frame); debug_assert!(self.inside_frame);
debug_assert_eq!(self.textures.get(&texture_id).unwrap().format, ImageFormat::RGBAF32);
self.bind_texture(DEFAULT_TEXTURE, texture_id); let (gl_format, bpp, data_type) = match self.textures.get(&texture_id).unwrap().format {
ImageFormat::A8 => (GL_FORMAT_A, 1, gl::UNSIGNED_BYTE),
self.gl.tex_sub_image_2d_pbo(texture_id.target, ImageFormat::RGB8 => (gl::RGB, 3, gl::UNSIGNED_BYTE),
0, ImageFormat::BGRA8 => (get_gl_format_bgra(self.gl()), 4, gl::UNSIGNED_BYTE),
x0 as gl::GLint, ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE),
y0 as gl::GLint, ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT),
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),
ImageFormat::Invalid => unreachable!(), ImageFormat::Invalid => unreachable!(),
}; };
@ -1660,26 +1449,41 @@ impl Device {
None => width, 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 { if let Some(..) = stride {
self.gl.pixel_store_i(gl::UNPACK_ROW_LENGTH, row_length as gl::GLint); self.gl.pixel_store_i(gl::UNPACK_ROW_LENGTH, row_length as gl::GLint);
} }
self.bind_texture(DEFAULT_TEXTURE, texture_id); self.bind_texture(DEFAULT_TEXTURE, texture_id);
self.gl.tex_sub_image_2d(texture_id.target, match texture_id.target {
0, gl::TEXTURE_2D_ARRAY => {
x0 as gl::GLint, self.gl.tex_sub_image_3d_pbo(texture_id.target,
y0 as gl::GLint, 0,
width as gl::GLint, x0 as gl::GLint,
height as gl::GLint, y0 as gl::GLint,
gl_format, layer_index,
data_type, width as gl::GLint,
data); 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. // Reset row length to 0, otherwise the stride would apply to all texture uploads.
if let Some(..) = stride { if let Some(..) = stride {
@ -1687,19 +1491,12 @@ impl Device {
} }
} }
fn clear_vertex_array(&mut self) { pub fn bind_vao(&mut self, vao: &VAO) {
debug_assert!(self.inside_frame);
self.gl.bind_vertex_array(0);
}
pub fn bind_vao(&mut self, vao_id: VAOId) {
debug_assert!(self.inside_frame); debug_assert!(self.inside_frame);
if self.bound_vao != vao_id { if self.bound_vao != vao.id {
self.bound_vao = vao_id; self.bound_vao = vao.id;
self.gl.bind_vertex_array(vao.id);
let VAOId(id) = vao_id;
self.gl.bind_vertex_array(id);
} }
} }
@ -1709,14 +1506,11 @@ impl Device {
instance_vbo_id: VBOId, instance_vbo_id: VBOId,
ibo_id: IBOId, ibo_id: IBOId,
instance_stride: gl::GLint, instance_stride: gl::GLint,
owns_vertices: bool, owns_vertices_and_indices: bool)
owns_instances: bool, -> VAO {
owns_indices: bool)
-> VAOId {
debug_assert!(self.inside_frame); debug_assert!(self.inside_frame);
let vao_ids = self.gl.gen_vertex_arrays(1); let vao_id = self.gl.gen_vertex_arrays(1)[0];
let vao_id = vao_ids[0];
self.gl.bind_vertex_array(vao_id); 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 ibo_id.bind(self.gl()); // force it to be a part of VAO
let vao = VAO { let vao = VAO {
gl: Rc::clone(&self.gl),
id: vao_id, id: vao_id,
ibo_id, ibo_id,
main_vbo_id, main_vbo_id,
instance_vbo_id, instance_vbo_id,
instance_stride, instance_stride,
owns_indices, owns_vertices_and_indices,
owns_vertices,
owns_instances,
}; };
self.gl.bind_vertex_array(0); self.gl.bind_vertex_array(0);
let vao_id = VAOId(vao_id); vao
debug_assert!(!self.vaos.contains_key(&vao_id));
self.vaos.insert(vao_id, vao);
vao_id
} }
pub fn create_vao(&mut self, pub fn create_vao(&mut self,
descriptor: &VertexDescriptor, descriptor: &VertexDescriptor,
inst_stride: gl::GLint) -> VAOId { inst_stride: gl::GLint) -> VAO {
debug_assert!(self.inside_frame); debug_assert!(self.inside_frame);
let buffer_ids = self.gl.gen_buffers(3); let buffer_ids = self.gl.gen_buffers(3);
@ -1760,55 +1546,55 @@ impl Device {
intance_vbo_id, intance_vbo_id,
ibo_id, ibo_id,
inst_stride, inst_stride,
true,
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, pub fn create_vao_with_new_instances(&mut self,
descriptor: &VertexDescriptor, descriptor: &VertexDescriptor,
inst_stride: gl::GLint, inst_stride: gl::GLint,
base_vao: VAOId) -> VAOId { base_vao: &VAO) -> VAO {
debug_assert!(self.inside_frame); debug_assert!(self.inside_frame);
let buffer_ids = self.gl.gen_buffers(1); let buffer_ids = self.gl.gen_buffers(1);
let intance_vbo_id = VBOId(buffer_ids[0]); 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, self.create_vao_with_vbos(descriptor,
main_vbo_id, base_vao.main_vbo_id,
intance_vbo_id, intance_vbo_id,
ibo_id, base_vao.ibo_id,
inst_stride, inst_stride,
false,
true,
false) false)
} }
pub fn update_vao_main_vertices<V>(&mut self, pub fn update_vao_main_vertices<V>(&mut self,
vao_id: VAOId, vao: &VAO,
vertices: &[V], vertices: &[V],
usage_hint: VertexUsageHint) { usage_hint: VertexUsageHint) {
debug_assert!(self.inside_frame); debug_assert!(self.inside_frame);
debug_assert_eq!(self.bound_vao, vao.id);
let vao = self.vaos.get(&vao_id).unwrap();
debug_assert_eq!(self.bound_vao, vao_id);
vao.main_vbo_id.bind(self.gl()); vao.main_vbo_id.bind(self.gl());
gl::buffer_data(self.gl(), gl::ARRAY_BUFFER, vertices, usage_hint.to_gl()); gl::buffer_data(self.gl(), gl::ARRAY_BUFFER, vertices, usage_hint.to_gl());
} }
pub fn update_vao_instances<V>(&mut self, pub fn update_vao_instances<V>(&mut self,
vao_id: VAOId, vao: &VAO,
instances: &[V], instances: &[V],
usage_hint: VertexUsageHint) { usage_hint: VertexUsageHint) {
debug_assert!(self.inside_frame); debug_assert!(self.inside_frame);
debug_assert_eq!(self.bound_vao, vao.id);
let vao = self.vaos.get(&vao_id).unwrap();
debug_assert_eq!(self.bound_vao, vao_id);
debug_assert_eq!(vao.instance_stride as usize, mem::size_of::<V>()); debug_assert_eq!(vao.instance_stride as usize, mem::size_of::<V>());
vao.instance_vbo_id.bind(self.gl()); vao.instance_vbo_id.bind(self.gl());
@ -1816,13 +1602,11 @@ impl Device {
} }
pub fn update_vao_indices<I>(&mut self, pub fn update_vao_indices<I>(&mut self,
vao_id: VAOId, vao: &VAO,
indices: &[I], indices: &[I],
usage_hint: VertexUsageHint) { usage_hint: VertexUsageHint) {
debug_assert!(self.inside_frame); debug_assert!(self.inside_frame);
debug_assert_eq!(self.bound_vao, vao.id);
let vao = self.vaos.get(&vao_id).unwrap();
debug_assert_eq!(self.bound_vao, vao_id);
vao.ibo_id.bind(self.gl()); vao.ibo_id.bind(self.gl());
gl::buffer_data(self.gl(), gl::ELEMENT_ARRAY_BUFFER, indices, usage_hint.to_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) /// return (gl_internal_format, gl_format)
fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl::GLint, gl::GLuint) { fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl::GLint, gl::GLuint) {
match format { match format {

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

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

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

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

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

@ -3,40 +3,31 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::marker::PhantomData; 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 // TODO(gw): Add an occupied list head, for fast
// iteration of the occupied list to implement // iteration of the occupied list to implement
// retain() style functionality. // retain() style functionality.
#[derive(Debug, Copy, Clone, PartialEq)]
struct Epoch(u32);
#[derive(Debug)] #[derive(Debug)]
pub struct FreeListHandle<T> { pub struct FreeListHandle<T> {
index: u32, index: u32,
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
enum SlotValue<T> { #[derive(Debug)]
Free, pub struct WeakFreeListHandle<T> {
Occupied(T), index: u32,
} epoch: Epoch,
_marker: PhantomData<T>,
impl<T> SlotValue<T> {
fn take(&mut self) -> T {
match mem::replace(self, SlotValue::Free) {
SlotValue::Free => unreachable!(),
SlotValue::Occupied(data) => data,
}
}
} }
struct Slot<T> { struct Slot<T> {
next: Option<u32>, next: Option<u32>,
value: SlotValue<T>, epoch: Epoch,
value: Option<T>,
} }
pub struct FreeList<T> { pub struct FreeList<T> {
@ -44,6 +35,11 @@ pub struct FreeList<T> {
free_list_head: Option<u32>, free_list_head: Option<u32>,
} }
pub enum UpsertResult<T> {
Updated(T),
Inserted(FreeListHandle<T>),
}
impl<T> FreeList<T> { impl<T> FreeList<T> {
pub fn new() -> FreeList<T> { pub fn new() -> FreeList<T> {
FreeList { FreeList {
@ -52,17 +48,63 @@ impl<T> FreeList<T> {
} }
} }
#[allow(dead_code)]
pub fn get(&self, id: &FreeListHandle<T>) -> &T { pub fn get(&self, id: &FreeListHandle<T>) -> &T {
match self.slots[id.index as usize].value { self.slots[id.index as usize]
SlotValue::Free => unreachable!(), .value
SlotValue::Occupied(ref data) => data, .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 { pub fn get_opt_mut(&mut self, id: &WeakFreeListHandle<T>) -> Option<&mut T> {
match self.slots[id.index as usize].value { let slot = &mut self.slots[id.index as usize];
SlotValue::Free => unreachable!(), if slot.epoch == id.epoch {
SlotValue::Occupied(ref mut data) => data, 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. // Remove from free list.
self.free_list_head = slot.next; self.free_list_head = slot.next;
slot.next = None; slot.next = None;
slot.value = SlotValue::Occupied(item); slot.value = Some(item);
FreeListHandle { FreeListHandle {
index: free_index, index: free_index,
@ -86,7 +128,8 @@ impl<T> FreeList<T> {
self.slots.push(Slot { self.slots.push(Slot {
next: None, next: None,
value: SlotValue::Occupied(item), epoch: Epoch(0),
value: Some(item),
}); });
FreeListHandle { FreeListHandle {
@ -100,7 +143,8 @@ impl<T> FreeList<T> {
pub fn free(&mut self, id: FreeListHandle<T>) -> T { pub fn free(&mut self, id: FreeListHandle<T>) -> T {
let slot = &mut self.slots[id.index as usize]; let slot = &mut self.slots[id.index as usize];
slot.next = self.free_list_head; slot.next = self.free_list_head;
slot.epoch = Epoch(slot.epoch.0 + 1);
self.free_list_head = Some(id.index); self.free_list_head = Some(id.index);
slot.value.take() slot.value.take().unwrap()
} }
} }

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

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

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

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

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

@ -28,7 +28,8 @@ use device::FrameId;
use internal_types::UvRect; use internal_types::UvRect;
use profiler::GpuCacheProfileCounters; use profiler::GpuCacheProfileCounters;
use renderer::MAX_VERTEX_TEXTURE_WIDTH; use renderer::MAX_VERTEX_TEXTURE_WIDTH;
use std::{mem, u32}; use std::{mem, u16, u32};
use std::ops::Add;
use api::{ColorF, LayerRect}; use api::{ColorF, LayerRect};
pub const GPU_CACHE_INITIAL_HEIGHT: u32 = 512; pub const GPU_CACHE_INITIAL_HEIGHT: u32 = 512;
@ -140,6 +141,24 @@ impl GpuCacheAddress {
v: v as u16, 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. // An entry in a free-list of blocks in the GPU cache.

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

@ -15,7 +15,7 @@ use tiling;
use renderer::BlendMode; use renderer::BlendMode;
use api::{ClipId, DevicePoint, DeviceUintRect, DocumentId, Epoch}; use api::{ClipId, DevicePoint, DeviceUintRect, DocumentId, Epoch};
use api::{ExternalImageData, ExternalImageId}; 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 FastHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>; pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
@ -43,10 +43,8 @@ pub enum SourceTexture {
Invalid, Invalid,
TextureCache(CacheTextureId), TextureCache(CacheTextureId),
External(ExternalImageData), External(ExternalImageData),
#[cfg_attr(not(feature = "webgl"), allow(dead_code))] CacheA8,
/// This is actually a gl::GLuint, with the shared texture id between the CacheRGBA8,
/// main context and the WebGL context.
WebGL(u32),
} }
pub const ORTHO_NEAR_PLANE: f32 = -1000000.0; pub const ORTHO_NEAR_PLANE: f32 = -1000000.0;
@ -91,6 +89,16 @@ impl BatchTextures {
colors: [SourceTexture::Invalid; 3], 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. // 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)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum RenderTargetMode { pub enum RenderTargetMode {
None, None,
SimpleRenderTarget, RenderTarget,
LayerRenderTarget(i32), // Number of texture layers }
#[derive(Debug)]
pub enum TextureUpdateSource {
External { id: ExternalImageId, channel_index: u8 },
Bytes { data: Arc<Vec<u8>> },
} }
#[derive(Debug)] #[derive(Debug)]
pub enum TextureUpdateOp { pub enum TextureUpdateOp {
Create { 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, width: u32,
height: u32, height: u32,
format: ImageFormat, format: ImageFormat,
filter: TextureFilter, filter: TextureFilter,
mode: RenderTargetMode, mode: RenderTargetMode,
layer_count: i32,
},
Update {
rect: DeviceUintRect,
stride: Option<u32>,
offset: u32,
layer_index: i32,
source: TextureUpdateSource,
}, },
Free, Free,
} }

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

@ -80,16 +80,6 @@ mod texture_cache;
mod tiling; mod tiling;
mod util; 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 { mod shader_source {
include!(concat!(env!("OUT_DIR"), "/shaders.rs")); include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
} }
@ -140,8 +130,6 @@ extern crate num_traits;
//extern crate notify; //extern crate notify;
extern crate time; extern crate time;
pub extern crate webrender_api; pub extern crate webrender_api;
#[cfg(feature = "webgl")]
extern crate offscreen_gl_context;
extern crate byteorder; extern crate byteorder;
extern crate rayon; extern crate rayon;
extern crate plane_split; extern crate plane_split;

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -5,7 +5,7 @@
use frame::Frame; use frame::Frame;
use frame_builder::FrameBuilderConfig; use frame_builder::FrameBuilderConfig;
use gpu_cache::GpuCache; use gpu_cache::GpuCache;
use internal_types::{FastHashMap, SourceTexture, ResultMsg, RendererFrame}; use internal_types::{FastHashMap, ResultMsg, RendererFrame};
use profiler::{BackendProfileCounters, ResourceProfileCounters}; use profiler::{BackendProfileCounters, ResourceProfileCounters};
use record::ApiRecordingReceiver; use record::ApiRecordingReceiver;
use resource_cache::ResourceCache; use resource_cache::ResourceCache;
@ -17,19 +17,11 @@ use texture_cache::TextureCache;
use time::precise_time_ns; use time::precise_time_ns;
use thread_profiler::register_thread_with_profiler; use thread_profiler::register_thread_with_profiler;
use rayon::ThreadPool; use rayon::ThreadPool;
use webgl_types::{GLContextHandleWrapper, GLContextWrapper};
use api::channel::{MsgReceiver, PayloadReceiver, PayloadReceiverHelperMethods}; use api::channel::{MsgReceiver, PayloadReceiver, PayloadReceiverHelperMethods};
use api::channel::{PayloadSender, PayloadSenderHelperMethods}; use api::channel::{PayloadSender, PayloadSenderHelperMethods};
use api::{ApiMsg, BlobImageRenderer, BuiltDisplayList, DeviceIntPoint}; use api::{ApiMsg, BlobImageRenderer, BuiltDisplayList, DeviceIntPoint};
use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentId, DocumentMsg}; use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentId, DocumentMsg};
use api::{IdNamespace, LayerPoint, RenderDispatcher, RenderNotifier}; use api::{IdNamespace, LayerPoint, RenderNotifier};
use api::{VRCompositorCommand, VRCompositorHandler, WebGLCommand, WebGLContextId};
#[cfg(feature = "webgl")]
use offscreen_gl_context::GLContextDispatcher;
#[cfg(not(feature = "webgl"))]
use webgl_types::GLContextDispatcher;
struct Document { struct Document {
scene: Scene, 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 { enum DocumentOp {
Nop, Nop,
Built, Built,
@ -184,12 +123,7 @@ pub struct RenderBackend {
documents: FastHashMap<DocumentId, Document>, documents: FastHashMap<DocumentId, Document>,
notifier: Arc<Mutex<Option<Box<RenderNotifier>>>>, notifier: Arc<Mutex<Option<Box<RenderNotifier>>>>,
webrender_context_handle: Option<GLContextHandleWrapper>,
recorder: Option<Box<ApiRecordingReceiver>>, 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, enable_render_on_scroll: bool,
} }
@ -204,19 +138,15 @@ impl RenderBackend {
texture_cache: TextureCache, texture_cache: TextureCache,
workers: Arc<ThreadPool>, workers: Arc<ThreadPool>,
notifier: Arc<Mutex<Option<Box<RenderNotifier>>>>, notifier: Arc<Mutex<Option<Box<RenderNotifier>>>>,
webrender_context_handle: Option<GLContextHandleWrapper>,
frame_config: FrameBuilderConfig, frame_config: FrameBuilderConfig,
recorder: Option<Box<ApiRecordingReceiver>>, recorder: Option<Box<ApiRecordingReceiver>>,
main_thread_dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>,
blob_image_renderer: Option<Box<BlobImageRenderer>>, blob_image_renderer: Option<Box<BlobImageRenderer>>,
vr_compositor_handler: Arc<Mutex<Option<Box<VRCompositorHandler>>>>,
enable_render_on_scroll: bool, enable_render_on_scroll: bool,
) -> RenderBackend { ) -> RenderBackend {
let resource_cache = ResourceCache::new(texture_cache, let resource_cache = ResourceCache::new(texture_cache,
workers, workers,
blob_image_renderer, blob_image_renderer);
frame_config.cache_expiry_frames);
register_thread_with_profiler("Backend".to_string()); register_thread_with_profiler("Backend".to_string());
@ -233,12 +163,7 @@ impl RenderBackend {
documents: FastHashMap::default(), documents: FastHashMap::default(),
next_namespace_id: IdNamespace(1), next_namespace_id: IdNamespace(1),
notifier, notifier,
webrender_context_handle,
recorder, recorder,
main_thread_dispatcher,
vr_compositor_handler,
webgl: WebGL::new(),
enable_render_on_scroll, enable_render_on_scroll,
} }
@ -308,7 +233,6 @@ impl RenderBackend {
let display_list_received_time = precise_time_ns(); let display_list_received_time = precise_time_ns();
{ {
self.webgl.flush();
let _timer = profile_counters.total_time.timer(); let _timer = profile_counters.total_time.timer();
doc.scene.set_display_list( doc.scene.set_display_list(
pipeline_id, pipeline_id,
@ -344,7 +268,6 @@ impl RenderBackend {
doc.scene.set_root_pipeline_id(pipeline_id); doc.scene.set_root_pipeline_id(pipeline_id);
if doc.scene.display_lists.get(&pipeline_id).is_some() { if doc.scene.display_lists.get(&pipeline_id).is_some() {
self.webgl.flush();
let _timer = profile_counters.total_time.timer(); let _timer = profile_counters.total_time.timer();
doc.build_scene(&mut self.resource_cache, self.hidpi_factor); doc.build_scene(&mut self.resource_cache, self.hidpi_factor);
DocumentOp::Built DocumentOp::Built
@ -415,7 +338,6 @@ impl RenderBackend {
// animated properties to not require a full // animated properties to not require a full
// rebuild of the frame! // rebuild of the frame!
if let Some(property_bindings) = property_bindings { if let Some(property_bindings) = property_bindings {
self.webgl.flush();
doc.scene.properties.set_properties(property_bindings); doc.scene.properties.set_properties(property_bindings);
doc.build_scene(&mut self.resource_cache, self.hidpi_factor); doc.build_scene(&mut self.resource_cache, self.hidpi_factor);
} }
@ -511,63 +433,6 @@ impl RenderBackend {
ApiMsg::DeleteDocument(document_id) => { ApiMsg::DeleteDocument(document_id) => {
self.documents.remove(&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) => { ApiMsg::ExternalEvent(evt) => {
let notifier = self.notifier.lock(); let notifier = self.notifier.lock();
notifier.unwrap() notifier.unwrap()
@ -640,32 +505,4 @@ impl RenderBackend {
let mut notifier = self.notifier.lock(); let mut notifier = self.notifier.lock();
notifier.as_mut().unwrap().as_mut().unwrap().new_scroll_frame_ready(composite_needed); 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);
}
} }

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

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

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

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

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

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

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

@ -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>);
}

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

@ -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())
}
}
}
}

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

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

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

@ -3,17 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use channel::{self, MsgSender, Payload, PayloadSenderHelperMethods, PayloadSender}; use channel::{self, MsgSender, Payload, PayloadSenderHelperMethods, PayloadSender};
#[cfg(feature = "webgl")]
use offscreen_gl_context::{GLContextAttributes, GLLimits};
use std::cell::Cell; use std::cell::Cell;
use std::fmt; use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use {BuiltDisplayList, BuiltDisplayListDescriptor, ClipId, ColorF, DeviceIntPoint, DeviceIntSize}; use {BuiltDisplayList, BuiltDisplayListDescriptor, ClipId, ColorF, DeviceIntPoint};
use {DeviceUintRect, DeviceUintSize, FontKey, GlyphDimensions, GlyphKey}; use {DeviceUintRect, DeviceUintSize, FontKey, GlyphDimensions, GlyphKey};
use {ImageData, ImageDescriptor, ImageKey, LayoutPoint, LayoutVector2D, LayoutSize, LayoutTransform}; use {ImageData, ImageDescriptor, ImageKey, LayoutPoint, LayoutVector2D, LayoutSize, LayoutTransform};
use {FontInstanceKey, NativeFontHandle, WorldPoint}; use {FontInstance, NativeFontHandle, WorldPoint};
#[cfg(feature = "webgl")]
use {WebGLCommand, WebGLContextId};
pub type TileSize = u16; pub type TileSize = u16;
@ -148,7 +144,7 @@ pub enum ApiMsg {
/// Add/remove/update images and fonts. /// Add/remove/update images and fonts.
UpdateResources(ResourceUpdates), UpdateResources(ResourceUpdates),
/// Gets the glyph dimensions /// 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 /// Gets the glyph indices from a string
GetGlyphIndices(FontKey, String, MsgSender<Vec<Option<u32>>>), GetGlyphIndices(FontKey, String, MsgSender<Vec<Option<u32>>>),
/// Adds a new document namespace. /// Adds a new document namespace.
@ -159,11 +155,6 @@ pub enum ApiMsg {
UpdateDocument(DocumentId, DocumentMsg), UpdateDocument(DocumentId, DocumentMsg),
/// Deletes an existing document. /// Deletes an existing document.
DeleteDocument(DocumentId), 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 /// 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 /// to forward gecko-specific messages to the render thread preserving the ordering
/// within the other messages. /// within the other messages.
@ -185,10 +176,6 @@ impl fmt::Debug for ApiMsg {
ApiMsg::AddDocument(..) => "ApiMsg::AddDocument", ApiMsg::AddDocument(..) => "ApiMsg::AddDocument",
ApiMsg::UpdateDocument(..) => "ApiMsg::UpdateDocument", ApiMsg::UpdateDocument(..) => "ApiMsg::UpdateDocument",
ApiMsg::DeleteDocument(..) => "ApiMsg::DeleteDocument", 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::ExternalEvent(..) => "ApiMsg::ExternalEvent",
ApiMsg::ClearNamespace(..) => "ApiMsg::ClearNamespace", ApiMsg::ClearNamespace(..) => "ApiMsg::ClearNamespace",
ApiMsg::MemoryPressure => "ApiMsg::MemoryPressure", ApiMsg::MemoryPressure => "ApiMsg::MemoryPressure",
@ -201,24 +188,6 @@ impl fmt::Debug for ApiMsg {
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Epoch(pub u32); 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)] #[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
pub struct IdNamespace(pub u32); pub struct IdNamespace(pub u32);
@ -343,7 +312,7 @@ impl RenderApi {
/// 'empty' textures (height or width = 0) /// 'empty' textures (height or width = 0)
/// This means that glyph dimensions e.g. for spaces (' ') will mostly be None. /// This means that glyph dimensions e.g. for spaces (' ') will mostly be None.
pub fn get_glyph_dimensions(&self, pub fn get_glyph_dimensions(&self,
font: FontInstanceKey, font: FontInstance,
glyph_keys: Vec<GlyphKey>) glyph_keys: Vec<GlyphKey>)
-> Vec<Option<GlyphDimensions>> { -> Vec<Option<GlyphDimensions>> {
let (tx, rx) = channel::msg_channel().unwrap(); let (tx, rx) = channel::msg_channel().unwrap();
@ -371,32 +340,12 @@ impl RenderApi {
/// Adds an image identified by the `ImageKey`. /// Adds an image identified by the `ImageKey`.
pub fn update_resources(&self, resources: ResourceUpdates) { pub fn update_resources(&self, resources: ResourceUpdates) {
if resources.updates.is_empty() {
return;
}
self.api_sender.send(ApiMsg::UpdateResources(resources)).unwrap(); 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) { pub fn send_external_event(&self, evt: ExternalEvent) {
let msg = ApiMsg::ExternalEvent(evt); let msg = ApiMsg::ExternalEvent(evt);
self.api_sender.send(msg).unwrap(); self.api_sender.send(msg).unwrap();
@ -705,31 +654,9 @@ pub struct DynamicProperties {
pub floats: Vec<PropertyValue<f32>>, 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 { pub trait RenderNotifier: Send {
fn new_frame_ready(&mut self); fn new_frame_ready(&mut self);
fn new_scroll_frame_ready(&mut self, composite_needed: bool); fn new_scroll_frame_ready(&mut self, composite_needed: bool);
fn external_event(&mut self, _evt: ExternalEvent) { unimplemented!() } fn external_event(&mut self, _evt: ExternalEvent) { unimplemented!() }
fn shut_down(&mut self) {} 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>);
}

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

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

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

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

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

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

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

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

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

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

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

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