summaryrefslogtreecommitdiffstats
path: root/chrome/gpu
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 /chrome/gpu
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
Diffstat (limited to 'chrome/gpu')
-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
5 files changed, 167 insertions, 13 deletions
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_;