зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1389497 - Update webrender to commit 1007a65c6dd1fdfb8b39d57d7faff3cae7b32e0c. r=jrmuizel
MozReview-Commit-ID: LLg2tnX9LYu --HG-- extra : rebase_source : 9fbbd518af8a3e2727edfe92ebf6171f272e9d65
This commit is contained in:
Родитель
29fb7aad8e
Коммит
83c2515b8a
|
@ -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(¬ifier);
|
let backend_notifier = Arc::clone(¬ifier);
|
||||||
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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче