summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-28 16:18:57 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-28 16:18:57 +0000
commit8386a521873c4ea37b2682fff32260acdf245138 (patch)
treea0fd60732a77e1ed1e0d3516e5cb82114188fdd5
parentd8921c432923fd6bdbbc176110258c2e3416eaa7 (diff)
downloadchromium_src-8386a521873c4ea37b2682fff32260acdf245138.zip
chromium_src-8386a521873c4ea37b2682fff32260acdf245138.tar.gz
chromium_src-8386a521873c4ea37b2682fff32260acdf245138.tar.bz2
Add scrolling to the GPU-accelerated backing store. This also fixes some bugs
in the regular painting mode and adds handling for expose events. Accelerated tabs now seem to look and behave properly as far as I can tell. Scrolling works by keeping a secondary texture which the current backing store is painted into. To save copies and excess texture creation, the current texture and the newly generated one are just swapped whan scrolling completes. Scrolling does not actually trigger painting to the screen. This is because scrolling is always followed by a paint to the exposed area, which then triggers copying the GPU backing store to the screen. BUG=none TEST=none Review URL: http://codereview.chromium.org/552207 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37409 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/renderer_host/gpu_view_host.cc4
-rw-r--r--chrome/browser/renderer_host/gpu_view_host.h6
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc5
-rwxr-xr-xchrome/chrome_browser.gypi2
-rw-r--r--chrome/common/gpu_messages_internal.h5
-rw-r--r--chrome/gpu/gpu_backing_store_glx.cc78
-rw-r--r--chrome/gpu/gpu_backing_store_glx_context.cc73
-rw-r--r--chrome/gpu/gpu_backing_store_glx_context.h22
-rw-r--r--chrome/gpu/gpu_view_x.cc5
-rw-r--r--chrome/gpu/gpu_view_x.h2
10 files changed, 189 insertions, 13 deletions
diff --git a/chrome/browser/renderer_host/gpu_view_host.cc b/chrome/browser/renderer_host/gpu_view_host.cc
index 9b9404a..8fcb288 100644
--- a/chrome/browser/renderer_host/gpu_view_host.cc
+++ b/chrome/browser/renderer_host/gpu_view_host.cc
@@ -30,3 +30,7 @@ BackingStore* GpuViewHost::CreateBackingStore(const gfx::Size& size) {
return new BackingStoreProxy(widget_, size,
process_, backing_store_routing_id);
}
+
+void GpuViewHost::OnWindowPainted() {
+ process_->Send(new GpuMsg_WindowPainted(routing_id_));
+}
diff --git a/chrome/browser/renderer_host/gpu_view_host.h b/chrome/browser/renderer_host/gpu_view_host.h
index adafbf7..c6aa2d2 100644
--- a/chrome/browser/renderer_host/gpu_view_host.h
+++ b/chrome/browser/renderer_host/gpu_view_host.h
@@ -26,6 +26,12 @@ class GpuViewHost {
// the new pointer to the caller.
BackingStore* CreateBackingStore(const gfx::Size& size);
+ // Notification that the RenderWidgetHost has been asked to paint the window.
+ // Depending on the backing store, the GPU backing store may have to repaint
+ // at this time. On Linux this is needed because the GPU process paints
+ // directly into the RWH's X window.
+ void OnWindowPainted();
+
private:
RenderWidgetHost* widget_;
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
index ced2f16..66cbe52 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -636,6 +636,11 @@ void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) {
if (kUseGPURendering) {
// When we're proxying painting, we don't actually display the web page
// ourselves.
+ if (gpu_view_host_.get())
+ gpu_view_host_->OnWindowPainted();
+
+ // Erase the background. This will prevent a flash of black when resizing
+ // or exposing the window. White is usually better than black.
return;
}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 84c6305..4b62edd 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2060,6 +2060,8 @@
'browser/password_manager/password_store_win.h',
'browser/renderer_host/backing_store_proxy.cc',
'browser/renderer_host/backing_store_proxy.h',
+ 'browser/renderer_host/gpu_view_host.cc',
+ 'browser/renderer_host/gpu_view_host.h',
'browser/views/extensions/extension_shelf.cc',
'browser/views/extensions/extension_shelf.h',
'browser/views/extensions/extension_view.cc',
diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h
index 4209a12..76f264f 100644
--- a/chrome/common/gpu_messages_internal.h
+++ b/chrome/common/gpu_messages_internal.h
@@ -40,6 +40,11 @@ IPC_BEGIN_MESSAGES(Gpu)
gfx::Rect, /* clip_rect */
gfx::Size) /* view_size */
+ // Tells the GPU process that the RenderWidgetHost has painted the window.
+ // Depending on the platform, the accelerated content may need to be painted
+ // over the top.
+ IPC_MESSAGE_ROUTED0(GpuMsg_WindowPainted)
+
IPC_END_MESSAGES(Gpu)
//------------------------------------------------------------------------------
diff --git a/chrome/gpu/gpu_backing_store_glx.cc b/chrome/gpu/gpu_backing_store_glx.cc
index e653284..015e913 100644
--- a/chrome/gpu/gpu_backing_store_glx.cc
+++ b/chrome/gpu/gpu_backing_store_glx.cc
@@ -32,9 +32,8 @@ GpuBackingStoreGLX::GpuBackingStoreGLX(GpuViewX* view,
glBindTexture(GL_TEXTURE_2D, texture_id_);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- DCHECK(glGetError() == GL_NO_ERROR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
GpuBackingStoreGLX::~GpuBackingStoreGLX() {
@@ -83,7 +82,70 @@ void GpuBackingStoreGLX::OnPaintToBackingStore(
void GpuBackingStoreGLX::OnScrollBackingStore(int dx, int dy,
const gfx::Rect& clip_rect,
const gfx::Size& view_size) {
+ // Create a framebuffer to render our scrolled texture into.
+ GpuBackingStoreGLXContext* context = view_->gpu_thread()->GetGLXContext();
+ if (!context->BindTextureForScrolling(view_->window(), size_))
+ return;
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, texture_id_);
+
+ // Set up the the tranform so we can paint exact pixels to the screen, with
+ // (0, 0) at the bottom left.
+ float w = static_cast<float>(size_.width());
+ float h = static_cast<float>(size_.height());
+ glViewport(0, 0, size_.width(), size_.height());
+ glLoadIdentity();
+ glOrtho(0.0, w, 0.0, h, -1.0, 1.0);
+
+ // Paint the non-scrolled background of the page. Note that we try to avoid
+ // this if the entire thing is scrolling, which is a common case.
+ if (view_size != clip_rect.size()) {
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(0.0, 0.0);
+
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex2f(0.0, h);
+
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex2f(w, h);
+
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex2f(w, 0.0);
+ glEnd();
+ }
+
+ // Constrain the painting to only the area we're scrolling. Compute the clip
+ // rect in OpenGL pixel coords, which uses the lower-left as the origin.
+ gfx::Rect gl_clip_rect(clip_rect.x(), clip_rect.y(),
+ clip_rect.width(), clip_rect.height());
+
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(gl_clip_rect.x(), gl_clip_rect.y(),
+ gl_clip_rect.width(), gl_clip_rect.height());
+
+ // Paint the offset texture.
+ glTranslatef(static_cast<float>(dx), static_cast<float>(dy), 0.0f);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(0.0, 0.0);
+
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex2f(0.0, h);
+
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex2f(w, h);
+
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex2f(w, 0.0);
+ glEnd();
+ glDisable(GL_SCISSOR_TEST);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ texture_id_ = context->SwapTextureForScrolling(texture_id_, size_);
+ glFlush();
+ DCHECK(texture_id_);
}
void GpuBackingStoreGLX::PaintOneRectToBackingStore(
@@ -113,14 +175,10 @@ void GpuBackingStoreGLX::PaintOneRectToBackingStore(
// the updated bitmap to avoid the copy. We will have to benchmark that
// approach against making the copy here to see if it performs better on
// the systems we're targeting.
- SkIRect subset;
- subset.fLeft = copy_rect.x() - bitmap_rect.x();
- subset.fTop = copy_rect.y() - bitmap_rect.y();
- subset.fRight = subset.fLeft + copy_rect.width();
- subset.fBottom = subset.fTop + copy_rect.height();
SkIRect sk_copy_rect = { copy_rect.x() - bitmap_rect.x(),
copy_rect.y() - bitmap_rect.y(),
- copy_rect.right(), copy_rect.bottom() };
+ copy_rect.right() - bitmap_rect.x(),
+ copy_rect.bottom() - bitmap_rect.y()};
// extractSubset will not acutually make a copy, and Skia will refer to the
// original data which is not what we want, since rows won't be contiguous.
@@ -139,7 +197,6 @@ void GpuBackingStoreGLX::PaintOneRectToBackingStore(
copy_rect.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE,
copy_bitmap.getAddr32(0, 0));
texture_size_ = copy_rect.size();
- DCHECK(glGetError() == GL_NO_ERROR);
} else {
/* Debugging code for why the below call may fail.
int existing_width = 0, existing_height = 0;
@@ -152,7 +209,6 @@ void GpuBackingStoreGLX::PaintOneRectToBackingStore(
copy_rect.width(), copy_rect.height(),
GL_BGRA, GL_UNSIGNED_BYTE,
copy_bitmap.getAddr32(0, 0));
- DCHECK(glGetError() == GL_NO_ERROR);
/* Enable if you're having problems with TexSubImage failing.
int err = glGetError();
DCHECK(err == GL_NO_ERROR) << "Error " << err <<
diff --git a/chrome/gpu/gpu_backing_store_glx_context.cc b/chrome/gpu/gpu_backing_store_glx_context.cc
index e66f07b..1b9f04a 100644
--- a/chrome/gpu/gpu_backing_store_glx_context.cc
+++ b/chrome/gpu/gpu_backing_store_glx_context.cc
@@ -17,15 +17,28 @@ GpuBackingStoreGLXContext::GpuBackingStoreGLXContext(GpuThread* gpu_thread)
: gpu_thread_(gpu_thread),
tried_to_init_(false),
context_(NULL),
- previous_window_id_(0) {
+ previous_window_id_(0),
+ frame_buffer_for_scrolling_(0),
+ is_frame_buffer_bound_(false),
+ temp_scroll_texture_id_(0) {
}
GpuBackingStoreGLXContext::~GpuBackingStoreGLXContext() {
+ if (temp_scroll_texture_id_) {
+ glDeleteTextures(1, &temp_scroll_texture_id_);
+ temp_scroll_texture_id_ = 0;
+ }
+
+ if (frame_buffer_for_scrolling_)
+ glDeleteFramebuffers(1, &frame_buffer_for_scrolling_);
+
if (context_)
glXDestroyContext(gpu_thread_->display(), context_);
}
GLXContext GpuBackingStoreGLXContext::BindContext(XID window_id) {
+ DCHECK(!is_frame_buffer_bound_);
+
if (tried_to_init_) {
if (!context_)
return NULL;
@@ -52,3 +65,61 @@ GLXContext GpuBackingStoreGLXContext::BindContext(XID window_id) {
glewInit();
return context_;
}
+
+bool GpuBackingStoreGLXContext::BindTextureForScrolling(
+ XID window_id,
+ const gfx::Size& size) {
+ DCHECK(!is_frame_buffer_bound_);
+ BindContext(window_id);
+
+ // Create a new destination texture if the old one isn't properly sized.
+ // This means we try to re-use old ones without re-creating all the texture
+ // to save work in the common case of scrolling a window repeatedly that
+ // doesn't change size.
+ if (temp_scroll_texture_id_ == 0 ||
+ size != temp_scroll_texture_size_) {
+ if (!temp_scroll_texture_id_) {
+ // There may be no temporary one created yet.
+ glGenTextures(1, &temp_scroll_texture_id_);
+ }
+
+ // Create a new texture in the context with random garbage in it large
+ // enough to fit the required size.
+ glBindTexture(GL_TEXTURE_2D, temp_scroll_texture_id_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(),
+ 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ if (!frame_buffer_for_scrolling_)
+ glGenFramebuffers(1, &frame_buffer_for_scrolling_);
+ glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_for_scrolling_);
+ is_frame_buffer_bound_ = true;
+
+ // Release our color attachment.
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ temp_scroll_texture_id_, 0);
+
+ DCHECK(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) ==
+ GL_FRAMEBUFFER_COMPLETE_EXT);
+ return true;
+}
+
+unsigned int GpuBackingStoreGLXContext::SwapTextureForScrolling(
+ unsigned int old_texture,
+ const gfx::Size& old_size) {
+ // Unbind the framebuffer, which we expect to be bound.
+ DCHECK(is_frame_buffer_bound_);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ is_frame_buffer_bound_ = false;
+
+ DCHECK(temp_scroll_texture_id_);
+ unsigned int new_texture = temp_scroll_texture_id_;
+
+ temp_scroll_texture_id_ = old_texture;
+ temp_scroll_texture_size_ = old_size;
+
+ return new_texture;
+}
diff --git a/chrome/gpu/gpu_backing_store_glx_context.h b/chrome/gpu/gpu_backing_store_glx_context.h
index 211b010..393cd92 100644
--- a/chrome/gpu/gpu_backing_store_glx_context.h
+++ b/chrome/gpu/gpu_backing_store_glx_context.h
@@ -6,13 +6,15 @@
#define CHROME_GPU_GPU_BACKING_STORE_GLX_CONTEXT_H_
#include "base/basictypes.h"
+#include "base/gfx/size.h"
#include "chrome/gpu/x_util.h"
class GpuThread;
+
class GpuBackingStoreGLXContext {
public:
- GpuBackingStoreGLXContext(GpuThread* gpu_thread);
+ explicit GpuBackingStoreGLXContext(GpuThread* gpu_thread);
~GpuBackingStoreGLXContext();
// Returns the context, creating it if necessary, and binding it to the given
@@ -21,6 +23,12 @@ class GpuBackingStoreGLXContext {
// Returns NULL on failure.
GLXContext BindContext(XID window_id);
+ bool BindTextureForScrolling(XID window_id,
+ const gfx::Size& size);
+
+ unsigned int SwapTextureForScrolling(unsigned int old_texture,
+ const gfx::Size& old_size);
+
private:
GpuThread* gpu_thread_;
@@ -35,6 +43,18 @@ class GpuBackingStoreGLXContext {
// duplicate "MakeCurrent" calls which are expensive.
XID previous_window_id_;
+ // The frame buffer object we use to render scrolled images into. We'll set
+ // is_frame_buffer_bound_ when the FBO is bound so we can perform some checks
+ // to make sure we're not forgetting to unbind it.
+ unsigned int frame_buffer_for_scrolling_;
+ bool is_frame_buffer_bound_;
+
+ // The temporary texture we use for scrolling. The ID will be 0 if it is
+ // uninitialized. Otherwise, this will give the ID and size of an existing
+ // texture that can be re-used for a temporary buffer for scrolling.
+ unsigned int temp_scroll_texture_id_;
+ gfx::Size temp_scroll_texture_size_;
+
DISALLOW_COPY_AND_ASSIGN(GpuBackingStoreGLXContext);
};
diff --git a/chrome/gpu/gpu_view_x.cc b/chrome/gpu/gpu_view_x.cc
index c8e4613..d52154a 100644
--- a/chrome/gpu/gpu_view_x.cc
+++ b/chrome/gpu/gpu_view_x.cc
@@ -39,6 +39,7 @@ GLXContext GpuViewX::BindContext() {
void GpuViewX::OnMessageReceived(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(GpuViewX, msg)
IPC_MESSAGE_HANDLER(GpuMsg_NewBackingStore, OnNewBackingStore)
+ IPC_MESSAGE_HANDLER(GpuMsg_WindowPainted, OnWindowPainted)
IPC_END_MESSAGE_MAP_EX()
}
@@ -94,3 +95,7 @@ void GpuViewX::OnNewBackingStore(int32 routing_id, const gfx::Size& size) {
backing_store_.reset(
new GpuBackingStoreGLX(this, gpu_thread_, routing_id, size));
}
+
+void GpuViewX::OnWindowPainted() {
+ Repaint();
+}
diff --git a/chrome/gpu/gpu_view_x.h b/chrome/gpu/gpu_view_x.h
index 29543a6..4274f82 100644
--- a/chrome/gpu/gpu_view_x.h
+++ b/chrome/gpu/gpu_view_x.h
@@ -28,6 +28,7 @@ class GpuViewX
~GpuViewX();
GpuThread* gpu_thread() const { return gpu_thread_; }
+ XID window() const { return window_; }
// Wrapper around GPUBackingStoreGLXContext using our current window.
GLXContext BindContext();
@@ -44,6 +45,7 @@ class GpuViewX
private:
// IPC message handlers.
void OnNewBackingStore(int32 routing_id, const gfx::Size& size);
+ void OnWindowPainted();
GpuThread* gpu_thread_;
int32 routing_id_;