Bug 600760: Optimize mask with rectangular clip. r=jrmuizel
authorBas Schouten <bas.schouten@live.nl>
Mon, 11 Apr 2011 16:42:05 -0700
changeset 67868 e29f195869ade787c4363f3ea8ef6e2535a0f3f9
parent 67867 27718fc39386abe2925ab0f522a6f5cf95bcb160
child 67869 9d462cbed60feecbb6d3c22f662415c65223d5e0
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs600760
milestone2.2a1pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 600760: Optimize mask with rectangular clip. r=jrmuizel
gfx/cairo/cairo/src/cairo-d2d-surface.cpp
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -3155,54 +3155,80 @@ static cairo_int_status_t
 		cairo_operator_t	 op,
 		const cairo_pattern_t	*source,
 		const cairo_pattern_t	*mask,
 		cairo_clip_t		*clip)
 {
     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
     cairo_rectangle_int_t extents;
 
+    cairo_clip_t *actual_clip = clip;
+
     cairo_int_status_t status;
 
     status = (cairo_int_status_t)_cairo_surface_mask_extents (&d2dsurf->base,
 		    op, source,
 		    mask,
 		    clip, &extents);
     if (unlikely (status))
 	    return status;
 
-
-    D2D1_RECT_F rect = D2D1::RectF(0,
-				   0,
-				   (FLOAT)d2dsurf->rt->GetPixelSize().width,
-				   (FLOAT)d2dsurf->rt->GetPixelSize().height);
-
-    rect.left = (FLOAT)extents.x;
-    rect.right = (FLOAT)(extents.x + extents.width);
-    rect.top = (FLOAT)extents.y;
-    rect.bottom = (FLOAT)(extents.y + extents.height);
-
     bool isSolidAlphaMask = false;
     float solidAlphaValue = 1.0f;
 
     if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
 	cairo_solid_pattern_t *solidPattern =
 	    (cairo_solid_pattern_t*)mask;
 	if (solidPattern->content = CAIRO_CONTENT_ALPHA) {
 	    isSolidAlphaMask = true;
 	    solidAlphaValue = solidPattern->color.alpha;
 	}
     }
 
+    cairo_box_t box;
+    _cairo_box_from_rectangle(&box, &extents);
+
+    if (clip) {
+	// We do some work here to try and avoid pushing and popping clips for rectangular areas,
+	// if we do this fill rects will occur without rectangular clips being pushed and popped.
+	// This is faster for non-axis aligned clips in general and allows more efficient batching
+	// of the pop-clip calls.
+	int num_boxes = 1;
+	cairo_box_t box_stack;
+	cairo_box_t *boxes;
+	boxes = &box_stack;
+
+	// This function assumes atleast a single box resides at 'boxes' and the
+	// amount of boxes that reside there are passed in under num_boxes.
+	status = _cairo_clip_get_boxes(clip, &boxes, &num_boxes);
+
+	if (!status && num_boxes == 1) {
+	    box.p1.x = MAX(box.p1.x, boxes->p1.x);
+	    box.p2.x = MIN(box.p2.x, boxes->p2.x);
+	    box.p1.y = MAX(box.p1.y, boxes->p1.y);
+	    box.p2.y = MIN(box.p2.y, boxes->p2.y);
+
+	    if (clip->path != d2dsurf->clip.path) {
+		// Only reset the clip if we don't have the right clip set. Otherwise
+		// just leave the clip as it is. If we have the right clip set we
+		// should not do a needless pop of the clip.
+		actual_clip = NULL;
+	    }
+	}
+
+	if (boxes != &box_stack) {
+	    // If the function changed the boxes pointer, we need to free it.
+	    free(boxes);
+	}
+    }
+
     if (isSolidAlphaMask) {
 	if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	    const cairo_surface_pattern_t *surf_pattern = 
 		reinterpret_cast<const cairo_surface_pattern_t*>(source);
-	    cairo_box_t box;
-	    _cairo_box_from_rectangle(&box, &extents);
 	    cairo_int_status_t rv = _cairo_d2d_try_fastblit(d2dsurf,
 							    surf_pattern->surface,
 							    &box,
 							    &source->matrix,
 							    clip,
 							    op,
                                                             source->filter,
 							    solidAlphaValue);
@@ -3223,23 +3249,28 @@ static cairo_int_status_t
 #endif
 	target_rt = _cairo_d2d_get_temp_rt(d2dsurf, clip);
 	if (!target_rt) {
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
 	}
 #ifndef ALWAYS_MANUAL_COMPOSITE
     } else {
 	_begin_draw_state(d2dsurf);
-	status = (cairo_int_status_t)_cairo_d2d_set_clip (d2dsurf, clip);
-
+
+	status = (cairo_int_status_t)_cairo_d2d_set_clip (d2dsurf, actual_clip);
 	if (unlikely(status))
 	    return status;
     }
 #endif
 
+    D2D1_RECT_F rect = D2D1::RectF(_cairo_fixed_to_float(box.p1.x),
+				   _cairo_fixed_to_float(box.p1.y),
+				   _cairo_fixed_to_float(box.p2.x),
+				   _cairo_fixed_to_float(box.p2.y));
+
     if (isSolidAlphaMask) {
 	brush->SetOpacity(solidAlphaValue);
 	target_rt->FillRectangle(rect,
 				 brush);
 	brush->SetOpacity(1.0);
 
 	if (target_rt.get() != d2dsurf->rt.get()) {
 	    return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip);