Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand the optimization that eliminates stencil buffer usage in favor of the scissor box to handle 3D transforms. #282

Merged
merged 1 commit into from Jun 1, 2016
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -6,7 +6,7 @@ use batch::{RasterBatch, VertexBufferId};
use debug_render::DebugRenderer;
use device::{Device, ProgramId, TextureId, UniformLocation, VertexFormat, GpuProfile};
use device::{TextureFilter, VAOId, VBOId, VertexUsageHint, FileWatcherHandler};
use euclid::{Matrix4D, Point2D, Rect, Size2D};
use euclid::{Matrix4D, Point2D, Point4D, Rect, Size2D};
use fnv::FnvHasher;
use gleam::gl;
use internal_types::{RendererFrame, ResultMsg, TextureUpdateOp, BatchUpdateOp, BatchUpdateList};
@@ -33,7 +33,7 @@ use time::precise_time_ns;
use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier};
use webrender_traits::{ImageFormat, MixBlendMode, RenderApiSender};
use offscreen_gl_context::{NativeGLContext, NativeGLContextMethods};
use util::MatrixHelpers;
use util::{MatrixHelpers, RectHelpers};

pub const BLUR_INFLATION_FACTOR: u32 = 3;
pub const MAX_RASTER_OP_SIZE: u32 = 2048;
@@ -1114,9 +1114,7 @@ impl Renderer {
}
}

fn draw_layer(&mut self,
layer: &DrawLayer,
render_context: &RenderContext) {
fn draw_layer(&mut self, layer: &DrawLayer, render_context: &RenderContext) {
// Draw child layers first, to ensure that dependent render targets
// have been built before they are read as a texture.
for child in &layer.child_layers {
@@ -1209,22 +1207,59 @@ impl Renderer {

// If we can represent the mask by just adjusting the scissor rect,
// don't draw it.
if mask.transform.can_losslessly_transform_a_2d_rect() {
let transformed_mask_rect = mask.transform
.transform_rect(&mask.rect);
if mask.transform
.can_losslessly_transform_and_perspective_project_a_2d_rect() {
// Convert the mask rect to 4D points.
let top_left = to_point4d(&mask.rect.origin);
let top_right = to_point4d(&mask.rect.top_right());
let bottom_right = to_point4d(&mask.rect.bottom_right());
let bottom_left = to_point4d(&mask.rect.bottom_left());

// Transform in normalized device coordinates.
let transform = projection.mul(&mask.transform);
let top_left =
transform.transform_point_and_perspective_project(&top_left);
let top_right =
transform.transform_point_and_perspective_project(&top_right);
let bottom_right =
transform.transform_point_and_perspective_project(
&bottom_right);
let bottom_left =
transform.transform_point_and_perspective_project(
&bottom_left);
let transformed_mask_rect = Rect::from_points(&top_left,
&top_right,
&bottom_right,
&bottom_left);
/*println!("... transformed mask rect in NDC: {:?}",
transformed_mask_rect);*/

// Convert to window coordinates.
let transformed_mask_origin = Point2D::new(
(transformed_mask_rect.origin.x *
self.device_pixel_ratio).round() as gl::GLint,
(transformed_mask_rect.origin.y *
self.device_pixel_ratio).round() as gl::GLint);
(transformed_mask_rect.origin.x + 1.0) / 2.0 *
layer_viewport.size.width as f32 +
layer_viewport.origin.x as f32,
(1.0 - transformed_mask_rect.size.height -
transformed_mask_rect.origin.y) / 2.0 *
layer_viewport.size.height as f32 +
layer_viewport.origin.y as f32);
let transformed_mask_size = Size2D::new(
(transformed_mask_rect.size.width *
self.device_pixel_ratio).round() as gl::GLint,
(transformed_mask_rect.size.height *
self.device_pixel_ratio).round() as gl::GLint);
let transformed_mask_rect =
Rect::new(transformed_mask_origin,
transformed_mask_size);
transformed_mask_rect.size.width / 2.0 *
layer_viewport.size.width as f32,
transformed_mask_rect.size.height / 2.0 *
layer_viewport.size.height as f32);
let transformed_mask_rect = Rect::new(transformed_mask_origin,
transformed_mask_size);

// Round and convert to integers.
let transformed_mask_origin =
Point2D::new(transformed_mask_rect.origin.x.round() as i32,
transformed_mask_rect.origin.y.round() as i32);
let transformed_mask_size =
Size2D::new(transformed_mask_rect.size.width.round() as i32,
transformed_mask_rect.size.height.round() as i32);
let transformed_mask_rect = Rect::new(transformed_mask_origin,
transformed_mask_size);

scissor_rect = transformed_mask_rect.intersection(&scissor_rect)
.unwrap_or(Rect::zero());
@@ -1667,6 +1702,10 @@ impl Renderer {
};
function(rect.origin.x, y, rect.size.width, rect.size.height)
}

fn to_point4d(point: &Point2D<f32>) -> Point4D<f32> {
Point4D::new(point.x, point.y, 0.0, 1.0)
}
}

fn draw_frame(&mut self, framebuffer_size: Size2D<u32>) {
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use euclid::{Matrix4D, Point2D, Rect, Size2D};
use euclid::{Matrix4D, Point2D, Point4D, Rect, Size2D};
use internal_types::{RectColors};
use num_traits::Zero;
use time::precise_time_ns;
@@ -37,25 +37,52 @@ impl Drop for ProfileScope {

// TODO: Implement these in euclid!
pub trait MatrixHelpers {
fn transform_point_and_perspective_project(&self, point: &Point4D<f32>) -> Point2D<f32>;
fn transform_rect(&self, rect: &Rect<f32>) -> Rect<f32>;

/// Returns true if this matrix transforms an axis-aligned 2D rectangle to another axis-aligned
/// 2D rectangle.
///
/// This is used as part of `flatten()` above, as essentially a hack for browser.html.
fn can_losslessly_transform_a_2d_rect(&self) -> bool;

/// Returns true if this matrix will transforms an axis-aligned 2D rectangle to another axis-
/// aligned 2D rectangle after perspective divide.
fn can_losslessly_transform_and_perspective_project_a_2d_rect(&self) -> bool;
}

impl MatrixHelpers for Matrix4D<f32> {
#[inline]
fn transform_point_and_perspective_project(&self, point: &Point4D<f32>) -> Point2D<f32> {
let point = self.transform_point4d(point);
Point2D::new(point.x / point.w, point.y / point.w)
}

fn transform_rect(&self, rect: &Rect<f32>) -> Rect<f32> {
let top_left = self.transform_point(&rect.origin);
let top_right = self.transform_point(&rect.top_right());
let bottom_left = self.transform_point(&rect.bottom_left());
let bottom_right = self.transform_point(&rect.bottom_right());
let (mut min_x, mut min_y) = (top_left.x.clone(), top_left.y.clone());
Rect::from_points(&top_left, &top_right, &bottom_right, &bottom_left)
}

fn can_losslessly_transform_a_2d_rect(&self) -> bool {
self.m12 == 0.0 && self.m14 == 0.0 && self.m21 == 0.0 && self.m24 == 0.0 && self.m44 == 1.0
}

fn can_losslessly_transform_and_perspective_project_a_2d_rect(&self) -> bool {
self.m12 == 0.0 && self.m21 == 0.0
}
}

pub trait RectHelpers {
fn from_points(a: &Point2D<f32>, b: &Point2D<f32>, c: &Point2D<f32>, d: &Point2D<f32>) -> Self;
fn contains_rect(&self, other: &Rect<f32>) -> bool;
}

impl RectHelpers for Rect<f32> {
fn from_points(a: &Point2D<f32>, b: &Point2D<f32>, c: &Point2D<f32>, d: &Point2D<f32>)
-> Rect<f32> {
let (mut min_x, mut min_y) = (a.x.clone(), a.y.clone());
let (mut max_x, mut max_y) = (min_x.clone(), min_y.clone());
for point in &[ top_right, bottom_left, bottom_right ] {
for point in &[b, c, d] {
if point.x < min_x {
min_x = point.x.clone()
}
@@ -73,16 +100,6 @@ impl MatrixHelpers for Matrix4D<f32> {
Size2D::new(max_x - min_x, max_y - min_y))
}

fn can_losslessly_transform_a_2d_rect(&self) -> bool {
self.m12 == 0.0 && self.m14 == 0.0 && self.m21 == 0.0 && self.m24 == 0.0 && self.m44 == 1.0
}
}

pub trait RectHelpers {
fn contains_rect(&self, other: &Rect<f32>) -> bool;
}

impl RectHelpers for Rect<f32> {
fn contains_rect(&self, other: &Rect<f32>) -> bool {
self.origin.x <= other.origin.x &&
self.origin.y <= other.origin.y &&
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.