summaryrefslogtreecommitdiffstats
path: root/chrome/browser/renderer_host
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-22 05:12:32 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-22 05:12:32 +0000
commit1163813d7c2a26cef1487d472e43ec3dfb22f247 (patch)
treec3dafba579e420c745c5387f5ba72b8fcf6f7f15 /chrome/browser/renderer_host
parent30f894bafbd04380db0615b87e734e0dbfad9915 (diff)
downloadchromium_src-1163813d7c2a26cef1487d472e43ec3dfb22f247.zip
chromium_src-1163813d7c2a26cef1487d472e43ec3dfb22f247.tar.gz
chromium_src-1163813d7c2a26cef1487d472e43ec3dfb22f247.tar.bz2
Create an OpenGL backing store. This version works for all the basic operations
except for scrolling. There are a lot of future enhancements which I have put TODOs in to cover. This is currently not built with Chrome as I'm not checking in the build file changes yet. BUG=none TEST=none Review URL: http://codereview.chromium.org/502001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35139 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/renderer_host')
-rw-r--r--chrome/browser/renderer_host/backing_store.h16
-rw-r--r--chrome/browser/renderer_host/backing_store_gl.cc210
-rw-r--r--chrome/browser/renderer_host/backing_store_manager_glx.cc57
-rw-r--r--chrome/browser/renderer_host/backing_store_manager_glx.h43
4 files changed, 325 insertions, 1 deletions
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index 68514e4..d52e560 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -136,7 +136,21 @@ class BackingStore {
#elif defined(OS_MACOSX)
scoped_cftyperef<CGContextRef> cg_bitmap_;
scoped_cftyperef<CGLayerRef> cg_layer_;
-#elif defined(OS_LINUX)
+#elif defined(OS_LINUX) && defined(USE_GL)
+ Display* const display_;
+
+ // The parent window for this backing store.
+ const XID root_window_;
+
+ unsigned int texture_id_; // 0 when uninitialized.
+
+ // The size of the texture loaded into GL. This is 0x0 when there is no
+ // texture loaded. This may be different than the size of the backing store
+ // because we could have been resized without yet getting the updated
+ // bitmap.
+ gfx::Size texture_size_;
+
+#elif defined(OS_LINUX) && !defined(USE_GL)
// Paints the bitmap from the renderer onto the backing store without
// using Xrender to composite the pixmaps.
void PaintRectWithoutXrender(TransportDIB* bitmap,
diff --git a/chrome/browser/renderer_host/backing_store_gl.cc b/chrome/browser/renderer_host/backing_store_gl.cc
new file mode 100644
index 0000000..414f071
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_gl.cc
@@ -0,0 +1,210 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/renderer_host/backing_store.h"
+
+#include <GL/gl.h>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/renderer_host/backing_store_manager.h"
+#include "chrome/browser/renderer_host/backing_store_manager_glx.h"
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/common/transport_dib.h"
+#include "chrome/common/x11_util.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+BackingStore::BackingStore(RenderWidgetHost* widget,
+ const gfx::Size& size,
+ void* visual,
+ int depth)
+ : render_widget_host_(widget),
+ size_(size),
+ display_(x11_util::GetXDisplay()),
+ root_window_(x11_util::GetX11RootWindow()),
+ texture_id_(0) {
+ XID id = x11_util::GetX11WindowFromGtkWidget(widget->view()->GetNativeView());
+ BackingStoreManager::GetGlManager()->BindContext(id);
+
+ glGenTextures(1, &texture_id_);
+ 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);
+}
+
+BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
+ : render_widget_host_(widget),
+ size_(size),
+ display_(NULL),
+ root_window_(0),
+ texture_id_(0) {
+}
+
+BackingStore::~BackingStore() {
+ if (texture_id_)
+ glDeleteTextures(1, &texture_id_);
+}
+
+void BackingStore::ShowRect(const gfx::Rect& damage, XID target) {
+ DCHECK(texture_id_ > 0);
+
+ // TODO(brettw) is this necessray?
+ XID id = x11_util::GetX11WindowFromGtkWidget(
+ render_widget_host_->view()->GetNativeView());
+ BackingStoreManager::GetGlManager()->BindContext(id);
+
+ glViewport(0, 0, size_.width(), size_.height());
+
+ // TODO(brettw) only repaint the damaged area. This currently erases and
+ // repaints the entire screen.
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, texture_id_);
+
+ // TODO(brettw) use vertex buffers.
+ // TODO(brettw) make this so we use the texture size rather than the whole
+ // area size so we don't stretch bitmaps.
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(-1.0, 1.0);
+
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex2f(-1.0, -1.0);
+
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex2f(1.0, -1.0);
+
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex2f(1.0, 1.0);
+ glEnd();
+ DCHECK(glGetError() == GL_NO_ERROR);
+
+ // TODO(brettw) when we no longer stretch non-fitting bitmaps, we should
+ // paint white over any unpainted area here.
+
+ glXSwapBuffers(display_, id);
+}
+
+SkBitmap BackingStore::PaintRectToBitmap(const gfx::Rect& rect) {
+ NOTIMPLEMENTED();
+ return SkBitmap();
+}
+
+#if defined(TOOLKIT_GTK)
+void BackingStore::PaintToRect(const gfx::Rect& rect, GdkDrawable* target) {
+ NOTIMPLEMENTED();
+}
+#endif
+
+// Paint the given transport DIB into our backing store.
+void BackingStore::PaintRect(base::ProcessHandle process,
+ TransportDIB* bitmap,
+ const gfx::Rect& bitmap_rect,
+ const gfx::Rect& copy_rect) {
+ if (!display_)
+ return;
+
+ if (bitmap_rect.IsEmpty() || copy_rect.IsEmpty())
+ return;
+
+ scoped_ptr<skia::PlatformCanvas> canvas(
+ bitmap->GetPlatformCanvas(bitmap_rect.width(), bitmap_rect.height()));
+ const SkBitmap& transport_bitmap =
+ canvas->getTopPlatformDevice().accessBitmap(false);
+
+ // Make a bitmap referring to the correct subset of the input bitmap.
+ SkBitmap copy_bitmap;
+ if (copy_rect.x() == 0 &&
+ copy_rect.y() == 0 &&
+ copy_rect.width() == bitmap_rect.width() &&
+ copy_rect.height() == bitmap_rect.height()) {
+ // The subregion we're being asked to copy is the full bitmap. We don't
+ // have to do any extra work to make the bitmap, we can just refer to the
+ // original data (bitmap assignments are just refs to the original).
+ copy_bitmap = transport_bitmap;
+ } else {
+ // Make a rect referring to the subset into the original (copy_rect and
+ // bitmap_rect are both in global coords) and make a copy of that data to
+ // give to OpenGL later.
+ //
+ // TODO(brettw) on desktop GL (not ES) we can do a trick here using
+ // GL_UNPACK_ROW_WIDTH, GL_UNPACK_SKIP_PIXELS and GL_UNPACK_SKIP_ROWS to
+ // avoid this copy.
+ //
+ // On ES, it may be better to actually call subimage for each row of
+ // 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() };
+
+ // 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.
+ // However, since this is very cheap, we can do it and *then* make a copy.
+ SkBitmap non_copied_subset;
+ transport_bitmap.extractSubset(&non_copied_subset, sk_copy_rect);
+ non_copied_subset.copyTo(&copy_bitmap, SkBitmap::kARGB_8888_Config);
+ CHECK(!copy_bitmap.isNull());
+ }
+
+ glBindTexture(GL_TEXTURE_2D, texture_id_);
+
+ SkAutoLockPixels lock(copy_bitmap);
+ if (copy_rect.size() == size_ && copy_rect.size() != texture_size_) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, copy_rect.width(),
+ 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;
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
+ &existing_width);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
+ &existing_height);
+ */
+ glTexSubImage2D(GL_TEXTURE_2D, 0, copy_rect.x(), copy_rect.y(),
+ 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 <<
+ " copying (" << copy_rect.x() << "," << copy_rect.y() <<
+ ")," << copy_rect.width() << "x" << copy_rect.height() <<
+ " for bitmap " << texture_size_.width() << "x" <<
+ texture_size_.height() <<
+ " real size " << existing_width << "x" << existing_height <<
+ " for " << this;
+ */
+ }
+}
+
+void BackingStore::ScrollRect(base::ProcessHandle process,
+ TransportDIB* bitmap,
+ const gfx::Rect& bitmap_rect,
+ int dx, int dy,
+ const gfx::Rect& clip_rect,
+ const gfx::Size& view_size) {
+ NOTIMPLEMENTED();
+}
+
+size_t BackingStore::MemorySize() {
+ return texture_size_.GetArea() * 4;
+}
diff --git a/chrome/browser/renderer_host/backing_store_manager_glx.cc b/chrome/browser/renderer_host/backing_store_manager_glx.cc
new file mode 100644
index 0000000..d220bb2
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_manager_glx.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/renderer_host/backing_store_manager_glx.h"
+
+#include <GL/gl.h>
+#include <X11/Xutil.h>
+
+#include "base/scoped_ptr.h"
+#include "chrome/common/x11_util.h"
+
+namespace {
+
+// scoped_ptr functor for XFree().
+class ScopedPtrXFree {
+ public:
+ inline void operator()(void* x) const {
+ ::XFree(x);
+ }
+};
+
+} // namespace
+
+BackingStoreManagerGlx::BackingStoreManagerGlx()
+ : display_(x11_util::GetXDisplay()),
+ tried_to_init_(false),
+ context_(NULL),
+ previous_window_id_(0) {
+}
+
+BackingStoreManagerGlx::~BackingStoreManagerGlx() {
+ if (context_)
+ glXDestroyContext(display_, context_);
+}
+
+GLXContext BackingStoreManagerGlx::BindContext(XID window_id) {
+ if (tried_to_init_) {
+ if (!context_)
+ return NULL;
+ if (!previous_window_id_ || previous_window_id_ != window_id)
+ ::glXMakeCurrent(display_, window_id, context_);
+ previous_window_id_ = window_id;
+ return context_;
+ }
+ tried_to_init_ = true;
+
+ int attrib_list[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
+ scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info(
+ ::glXChooseVisual(display_, 0, attrib_list));
+ if (!visual_info.get())
+ return NULL;
+
+ context_ = ::glXCreateContext(display_, visual_info.get(), NULL, True);
+ ::glXMakeCurrent(display_, window_id, context_);
+ return context_;
+}
diff --git a/chrome/browser/renderer_host/backing_store_manager_glx.h b/chrome/browser/renderer_host/backing_store_manager_glx.h
new file mode 100644
index 0000000..cf6bbe2
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_manager_glx.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_MANAGER_GLX_H_
+#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_MANAGER_GLX_H_
+
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+
+#include "base/basictypes.h"
+
+class BackingStoreManagerGlx {
+ public:
+ BackingStoreManagerGlx();
+ ~BackingStoreManagerGlx();
+
+ Display* display() const { return display_; }
+
+ // Returns the context, creating it if necessary, and binding it to the given
+ // display and window identified by the XID. This will avoid duplicate calls
+ // to MakeCurrent if the display/XID hasn't changed from the last call.
+ // Returns NULL on failure.
+ GLXContext BindContext(XID window_id);
+
+ private:
+ Display* display_;
+
+ // Set to true when we've tried to create the context. This prevents us from
+ // trying to initialize the OpenGL context over and over in the failure case.
+ bool tried_to_init_;
+
+ // The OpenGL context. Non-NULL when initialized.
+ GLXContext context_;
+
+ // The last window we've bound our context to. This allows us to avoid
+ // duplicate "MakeCurrent" calls which are expensive.
+ XID previous_window_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackingStoreManagerGlx);
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_MANAGER_GLX_H_