summaryrefslogtreecommitdiffstats
path: root/ui/gfx
diff options
context:
space:
mode:
authorpkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-29 16:17:55 +0000
committerpkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-29 16:17:55 +0000
commitc155c2541dc88c972115d28be7b66b152a1bedc3 (patch)
tree4a089075a7d510a4c6d5ce03e11bd8e62095576f /ui/gfx
parentea04e3db379d4ad27938969b2dc4b59f9e1db557 (diff)
downloadchromium_src-c155c2541dc88c972115d28be7b66b152a1bedc3.zip
chromium_src-c155c2541dc88c972115d28be7b66b152a1bedc3.tar.gz
chromium_src-c155c2541dc88c972115d28be7b66b152a1bedc3.tar.bz2
First pass for eliminating double painting
A simple 3D CSS benchmark shows a 20% improvement in framerate on T25 hardware: an increase from about 30 fps to 36 fps. This is a first pass to getting rid of double painting by introducing a hole in layers Currently a layer which wants its parent not to paint under it will call SetParentLayerHoley There are a number of questions in terms of implementation: 1) We are doing this with layers. We are currently setting all layers to be holey if the touch_ui flag is enabled. Another option is to merge the holey functionality into regular layers. (Get rid of the holey layer subclass) 2) We are always generating vertices matrix, even in the ui::Layer case, is this ok? 3) We are wasting video memory. We are still uploading a full bitmap. I wasn't able to find a function call which would be able to efficiently slice the bigger bitmap, notably changing the origin of where the painting starts (texture upload) git-svn-id: svn://svn.chromium.org/chrome/trunk/src@91848 0039d316-1c4b-4281-b951-d872f2087c98 BUG= TEST= Review URL: http://codereview.chromium.org/7330025 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@94677 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx')
-rw-r--r--ui/gfx/compositor/compositor.h4
-rw-r--r--ui/gfx/compositor/compositor_gl.cc59
-rw-r--r--ui/gfx/compositor/compositor_gl.h10
-rw-r--r--ui/gfx/compositor/compositor_win.cc8
-rw-r--r--ui/gfx/compositor/layer.cc83
-rw-r--r--ui/gfx/compositor/layer.h46
-rw-r--r--ui/gfx/compositor/layer_animator.cc8
7 files changed, 198 insertions, 20 deletions
diff --git a/ui/gfx/compositor/compositor.h b/ui/gfx/compositor/compositor.h
index 46544e5..9d3bdf5 100644
--- a/ui/gfx/compositor/compositor.h
+++ b/ui/gfx/compositor/compositor.h
@@ -51,6 +51,10 @@ class Texture : public base::RefCounted<Texture> {
// Draws the texture.
virtual void Draw(const ui::TextureDrawParams& params) = 0;
+ // Draws the portion of the texture contained within clip_bounds
+ virtual void Draw(const ui::TextureDrawParams& params,
+ const gfx::Rect& clip_bounds) = 0;
+
protected:
virtual ~Texture() {}
diff --git a/ui/gfx/compositor/compositor_gl.cc b/ui/gfx/compositor/compositor_gl.cc
index 3df7fee..6e1e651 100644
--- a/ui/gfx/compositor/compositor_gl.cc
+++ b/ui/gfx/compositor/compositor_gl.cc
@@ -12,6 +12,7 @@
#include "base/threading/thread_restrictions.h"
#include "third_party/skia/include/core/SkDevice.h"
#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkScalar.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
@@ -331,11 +332,17 @@ void TextureGL::SetCanvas(const SkCanvas& canvas,
void TextureGL::Draw(const ui::TextureDrawParams& params) {
DCHECK(compositor_->program_swizzle());
- DrawInternal(*compositor_->program_swizzle(), params);
+ Draw(params, gfx::Rect(0, 0, size_.width(), size_.height()));
}
+void TextureGL::Draw(const ui::TextureDrawParams& params,
+ const gfx::Rect& clip_bounds) {
+ DCHECK(compositor_->program_swizzle());
+ DrawInternal(*compositor_->program_swizzle(), params, clip_bounds);
+}
void TextureGL::DrawInternal(const ui::TextureProgramGL& program,
- const ui::TextureDrawParams& params) {
+ const ui::TextureDrawParams& params,
+ const gfx::Rect& clip_bounds) {
if (params.blend)
glEnable(GL_BLEND);
else
@@ -359,21 +366,53 @@ void TextureGL::DrawInternal(const ui::TextureProgramGL& program,
t.ConcatTranslate(0, -window_size.height());
t.ConcatScale(1, -1);
- t.ConcatTranslate(-window_size.width()/2.0f, -window_size.height()/2.0f);
- t.ConcatScale(2.0f/window_size.width(), 2.0f/window_size.height());
+ t.ConcatTranslate(-window_size.width() / 2.0f, -window_size.height() / 2.0f);
+ t.ConcatScale(2.0f / window_size.width(), 2.0f / window_size.height());
GLfloat m[16];
t.matrix().asColMajorf(m);
- static const GLfloat vertices[] = { -1., -1., +0., +0., +1.,
- +1., -1., +0., +1., +1.,
- +1., +1., +0., +1., +0.,
- -1., +1., +0., +0., +0. };
+ // TODO(pkotwicz) window_size != size_, fix this
+ SkRect texture_rect = SkRect::MakeXYWH(
+ clip_bounds.x(),
+ clip_bounds.y(),
+ clip_bounds.width(),
+ clip_bounds.height());
+
+ ui::Transform texture_rect_transform;
+ texture_rect_transform.ConcatScale(1.0f / size_.width(),
+ 1.0f / size_.height());
+ SkMatrix texture_transform_matrix = texture_rect_transform.matrix();
+ texture_transform_matrix.mapRect(&texture_rect);
+
+ SkRect clip_rect = SkRect::MakeXYWH(
+ clip_bounds.x(),
+ clip_bounds.y(),
+ clip_bounds.width(),
+ clip_bounds.height());
+
+ ui::Transform clip_rect_transform;
+ clip_rect_transform.ConcatScale(2.0f / size_.width(),
+ 2.0f / size_.height());
+ clip_rect_transform.ConcatScale(1, -1);
+ clip_rect_transform.ConcatTranslate(-1.0f, 1.0f);
+ SkMatrix clip_transform_matrix = clip_rect_transform.matrix();
+ clip_transform_matrix.mapRect(&clip_rect);
+
+ GLfloat clip_vertices[] = { clip_rect.left(), clip_rect.top(), +0.,
+ clip_rect.right(), clip_rect.top(), +0.,
+ clip_rect.right(), clip_rect.bottom(), +0.,
+ clip_rect.left(), clip_rect.bottom(), +0.};
+
+ GLfloat texture_vertices[] = { texture_rect.left(), texture_rect.bottom(),
+ texture_rect.right(), texture_rect.bottom(),
+ texture_rect.right(), texture_rect.top(),
+ texture_rect.left(), texture_rect.top()};
glVertexAttribPointer(program.a_pos_loc(), 3, GL_FLOAT,
- GL_FALSE, 5 * sizeof(GLfloat), vertices);
+ GL_FALSE, 3 * sizeof(GLfloat), clip_vertices);
glVertexAttribPointer(program.a_tex_loc(), 2, GL_FLOAT,
- GL_FALSE, 5 * sizeof(GLfloat), &vertices[3]);
+ GL_FALSE, 2 * sizeof(GLfloat), texture_vertices);
glEnableVertexAttribArray(program.a_pos_loc());
glEnableVertexAttribArray(program.a_tex_loc());
diff --git a/ui/gfx/compositor/compositor_gl.h b/ui/gfx/compositor/compositor_gl.h
index 759c653..716af7e 100644
--- a/ui/gfx/compositor/compositor_gl.h
+++ b/ui/gfx/compositor/compositor_gl.h
@@ -14,6 +14,7 @@
namespace gfx {
class GLContext;
class GLSurface;
+class Rect;
}
namespace ui {
@@ -30,15 +31,22 @@ class TextureGL : public Texture {
const gfx::Size& overall_size) OVERRIDE;
// Draws the texture.
+ // TODO(pkotwicz) merge these two methods into one, this method currently
+ // doesn't make sense in the context of windows
virtual void Draw(const ui::TextureDrawParams& params) OVERRIDE;
+ virtual void Draw(const ui::TextureDrawParams& params,
+ const gfx::Rect& clip_bounds) OVERRIDE;
+
protected:
TextureGL(CompositorGL* compositor, const gfx::Size& size);
virtual ~TextureGL();
// Actually draws the texture.
+ // Only the region defined by draw_bounds will be drawn.
void DrawInternal(const TextureProgramGL& program,
- const ui::TextureDrawParams& params);
+ const ui::TextureDrawParams& params,
+ const gfx::Rect& clip_bounds);
unsigned int texture_id_;
gfx::Size size_;
diff --git a/ui/gfx/compositor/compositor_win.cc b/ui/gfx/compositor/compositor_win.cc
index c938525..10fc36b 100644
--- a/ui/gfx/compositor/compositor_win.cc
+++ b/ui/gfx/compositor/compositor_win.cc
@@ -57,6 +57,9 @@ class ViewTexture : public Texture {
const gfx::Size& overall_size) OVERRIDE;
virtual void Draw(const ui::TextureDrawParams& params) OVERRIDE;
+ virtual void Draw(const ui::TextureDrawParams& params,
+ const gfx::Rect& clip_bounds) OVERRIDE;
+
private:
~ViewTexture();
@@ -269,6 +272,11 @@ void ViewTexture::Draw(const ui::TextureDrawParams& params) {
device_->DrawIndexed(6, 0, 0);
}
+void ViewTexture::Draw(const ui::TextureDrawParams& params,
+ const gfx::Rect& clip_bounds) {
+ NOTIMPLEMENTED();
+}
+
void ViewTexture::Errored(HRESULT result) {
// TODO: figure out error handling.
DCHECK(false);
diff --git a/ui/gfx/compositor/layer.cc b/ui/gfx/compositor/layer.cc
index ec2bf41..53097bd 100644
--- a/ui/gfx/compositor/layer.cc
+++ b/ui/gfx/compositor/layer.cc
@@ -7,14 +7,14 @@
#include <algorithm>
#include "base/logging.h"
-#include "ui/gfx/compositor/compositor.h"
namespace ui {
Layer::Layer(Compositor* compositor)
: compositor_(compositor),
texture_(compositor->CreateTexture()),
- parent_(NULL) {
+ parent_(NULL),
+ fills_bounds_opaquely_(false) {
}
Layer::~Layer() {
@@ -29,6 +29,9 @@ void Layer::Add(Layer* child) {
child->parent_->Remove(child);
child->parent_ = this;
children_.push_back(child);
+
+ if (child->fills_bounds_opaquely())
+ RecomputeHole();
}
void Layer::Remove(Layer* child) {
@@ -37,6 +40,33 @@ void Layer::Remove(Layer* child) {
DCHECK(i != children_.end());
children_.erase(i);
child->parent_ = NULL;
+
+ if (child->fills_bounds_opaquely())
+ RecomputeHole();
+}
+
+void Layer::SetTransform(const ui::Transform& transform) {
+ transform_ = transform;
+
+ if (parent() && fills_bounds_opaquely_)
+ parent()->RecomputeHole();
+}
+
+void Layer::SetBounds(const gfx::Rect& bounds) {
+ bounds_ = bounds;
+
+ if (parent() && fills_bounds_opaquely_)
+ parent()->RecomputeHole();
+}
+
+void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) {
+ if (fills_bounds_opaquely_ == fills_bounds_opaquely)
+ return;
+
+ fills_bounds_opaquely_ = fills_bounds_opaquely;
+
+ if (parent())
+ parent()->RecomputeHole();
}
void Layer::SetTexture(ui::Texture* texture) {
@@ -58,9 +88,58 @@ void Layer::Draw() {
static_cast<float>(layer->bounds_.x()),
static_cast<float>(layer->bounds_.y()));
}
+
// Only blend for child layers. The root layer will clobber the cleared bg.
texture_draw_params.blend = parent_ != NULL;
+
+#if defined(OS_WIN)
texture_->Draw(texture_draw_params);
+#else
+ hole_rect_ = hole_rect_.Intersect(
+ gfx::Rect(0, 0, bounds_.width(), bounds_.height()));
+
+ // top
+ DrawRegion(texture_draw_params, gfx::Rect(0,
+ 0,
+ bounds_.width(),
+ hole_rect_.y()));
+ // left
+ DrawRegion(texture_draw_params, gfx::Rect(0,
+ hole_rect_.y(),
+ hole_rect_.x(),
+ hole_rect_.height()));
+ // right
+ DrawRegion(texture_draw_params, gfx::Rect(
+ hole_rect_.right(),
+ hole_rect_.y(),
+ bounds_.width() - hole_rect_.right(),
+ hole_rect_.height()));
+
+ // bottom
+ DrawRegion(texture_draw_params, gfx::Rect(
+ 0,
+ hole_rect_.bottom(),
+ bounds_.width(),
+ bounds_.height() - hole_rect_.bottom()));
+#endif
+}
+
+void Layer::DrawRegion(const ui::TextureDrawParams& params,
+ const gfx::Rect& region_to_draw) {
+ if (!region_to_draw.IsEmpty())
+ texture_->Draw(params, region_to_draw);
+}
+
+void Layer::RecomputeHole() {
+ for (size_t i = 0; i < children_.size(); ++i) {
+ if (children_[i]->fills_bounds_opaquely() &&
+ !children_[i]->transform().HasChange()) {
+ hole_rect_ = children_[i]->bounds();
+ return;
+ }
+ }
+ // no opaque child layers, set hole_rect_ to empty
+ hole_rect_ = gfx::Rect();
}
} // namespace ui
diff --git a/ui/gfx/compositor/layer.h b/ui/gfx/compositor/layer.h
index e06a1f5..6e2438a 100644
--- a/ui/gfx/compositor/layer.h
+++ b/ui/gfx/compositor/layer.h
@@ -11,6 +11,7 @@
#include "base/memory/ref_counted.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
+#include "ui/gfx/compositor/compositor.h"
class SkCanvas;
@@ -44,13 +45,19 @@ class Layer {
Layer* parent() { return parent_; }
// The transform, relative to the parent.
- void set_transform(const ui::Transform& transform) { transform_ = transform; }
+ void SetTransform(const ui::Transform& transform);
const ui::Transform& transform() const { return transform_; }
// The bounds, relative to the parent.
- void set_bounds(const gfx::Rect& bounds) { bounds_ = bounds; }
+ void SetBounds(const gfx::Rect& bounds);
const gfx::Rect& bounds() const { return bounds_; }
+ // See description in View for details
+ void SetFillsBoundsOpaquely(bool fills_bounds_opaquely);
+ bool fills_bounds_opaquely() const { return fills_bounds_opaquely_; }
+
+ const gfx::Rect& hole_rect() const { return hole_rect_; }
+
// The compositor.
const Compositor* compositor() const { return compositor_; }
Compositor* compositor() { return compositor_; }
@@ -62,10 +69,39 @@ class Layer {
// Resets the canvas of the texture.
void SetCanvas(const SkCanvas& canvas, const gfx::Point& origin);
- // Draws the layer.
+// Draws the layer with hole if hole is non empty.
+// hole looks like:
+//
+// layer____________________________
+// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
+// |xxxxxxxxxxxxx top xxxxxxxxxxxxxx|
+// |________________________________|
+// |xxxxx| |xxxxx|
+// |xxxxx| Hole Rect |xxxxx|
+// |left | (not composited) |right|
+// |_____|____________________|_____|
+// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
+// |xxxxxxxxxx bottom xxxxxxxxxxxxxx|
+// |________________________________|
+//
+// Legend:
+// composited area: x
void Draw();
private:
+ // calls Texture::Draw only if the region to be drawn is non empty
+ void DrawRegion(const ui::TextureDrawParams& params,
+ const gfx::Rect& region_to_draw);
+
+ // A hole in a layer is an area in the layer that does not get drawn
+ // because this area is covered up with another layer which is known to be
+ // opaque.
+ // This method computes the dimension of the hole (if there is one)
+ // based on whether one of its child nodes is always opaque.
+ // Note: For simpicity's sake, currently a hole is only created if the child
+ // view has no transfrom with respect to its parent.
+ void RecomputeHole();
+
Compositor* compositor_;
scoped_refptr<ui::Texture> texture_;
@@ -78,6 +114,10 @@ class Layer {
gfx::Rect bounds_;
+ bool fills_bounds_opaquely_;
+
+ gfx::Rect hole_rect_;
+
DISALLOW_COPY_AND_ASSIGN(Layer);
};
diff --git a/ui/gfx/compositor/layer_animator.cc b/ui/gfx/compositor/layer_animator.cc
index 6144081..59fd9e1 100644
--- a/ui/gfx/compositor/layer_animator.cc
+++ b/ui/gfx/compositor/layer_animator.cc
@@ -94,7 +94,7 @@ void LayerAnimator::AnimationProgressed(const ui::Animation* animation) {
gfx::Rect(gfx::Point(e->second.params.location.target_x,
e->second.params.location.target_y),
current_bounds.size()));
- layer_->set_bounds(new_bounds);
+ layer_->SetBounds(new_bounds);
break;
}
@@ -106,7 +106,7 @@ void LayerAnimator::AnimationProgressed(const ui::Animation* animation) {
e->second.params.transform.target[i]);
SetMatrixElement(transform.matrix(), i, value);
}
- layer_->set_transform(transform);
+ layer_->SetTransform(transform);
break;
}
@@ -126,7 +126,7 @@ void LayerAnimator::AnimationEnded(const ui::Animation* animation) {
gfx::Point(e->second.params.location.target_x,
e->second.params.location.target_y),
layer_->bounds().size());
- layer_->set_bounds(new_bounds);
+ layer_->SetBounds(new_bounds);
break;
}
@@ -137,7 +137,7 @@ void LayerAnimator::AnimationEnded(const ui::Animation* animation) {
i,
e->second.params.transform.target[i]);
}
- layer_->set_transform(transform);
+ layer_->SetTransform(transform);
break;
}