0

Flag and adapter class for software compositing.

I'm adding a new CCRendererSkia class to CC, providing support for
compositing a website to a software bitmap. However, the rest of the
software compositing pipeline (delegating shared-memory resources and
quadlists to the root compositor) is not yet done, so there's no way to
get this bitmap onto the screen. As a stopgap, add an adapter class that
uploads to a viewport-sized GL texture every frame, and a flag
--force-software-compositing to activate it.

BUG=124671

Review URL: https://chromiumcodereview.appspot.com/10873099

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158388 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
aelias@chromium.org
2012-09-24 21:26:47 +00:00
parent 1144ce1e05
commit 7d4481d16a
9 changed files with 272 additions and 13 deletions

@ -816,6 +816,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableSandboxLogging,
#endif
switches::kEnableSeccompSandbox,
switches::kEnableSoftwareCompositingGLAdapter,
switches::kEnableStatsTable,
switches::kEnableThreadedCompositing,
switches::kDisableThreadedCompositing,

@ -85,6 +85,8 @@
'renderer/geolocation_dispatcher.h',
'renderer/gpu/compositor_output_surface.cc',
'renderer/gpu/compositor_output_surface.h',
'renderer/gpu/compositor_software_output_device_gl_adapter.cc',
'renderer/gpu/compositor_software_output_device_gl_adapter.h',
'renderer/gpu/compositor_thread.cc',
'renderer/gpu/compositor_thread.h',
'renderer/gpu/input_event_filter.cc',

@ -401,6 +401,10 @@ const char kForceFieldTrials[] = "force-fieldtrials";
// overrides this if present.
const char kForceRendererAccessibility[] = "force-renderer-accessibility";
// Force the compositor to use its software implementation instead of GL.
const char kEnableSoftwareCompositingGLAdapter[] =
"enable-software-compositing-gl-adapter";
// Passes gpu device_id from browser process to GPU process.
const char kGpuDeviceID[] = "gpu-device-id";

@ -115,6 +115,7 @@ extern const char kEnableRendererSideMixing[];
extern const char kEnableSSLCachedInfo[];
extern const char kEnableSandboxLogging[];
extern const char kEnableSeccompSandbox[];
CONTENT_EXPORT extern const char kEnableSoftwareCompositingGLAdapter[];
CONTENT_EXPORT extern const char kEnableSmoothScrolling[];
CONTENT_EXPORT extern const char kEnableStatsTable[];
extern const char kEnableStrictSiteIsolation[];

@ -13,6 +13,7 @@
#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
using WebKit::WebGraphicsContext3D;
using WebKit::WebCompositorSoftwareOutputDevice;
//------------------------------------------------------------------------------
@ -28,12 +29,14 @@ IPC::ForwardingMessageFilter* CompositorOutputSurface::CreateFilter(
CompositorOutputSurface::CompositorOutputSurface(
int32 routing_id,
WebGraphicsContext3D* context3D)
WebGraphicsContext3D* context3D,
WebCompositorSoftwareOutputDevice* software_device)
: output_surface_filter_(
RenderThreadImpl::current()->compositor_output_surface_filter())
, client_(NULL)
, routing_id_(routing_id)
, context3D_(context3D) {
RenderThreadImpl::current()->compositor_output_surface_filter()),
client_(NULL),
routing_id_(routing_id),
context3D_(context3D),
software_device_(software_device) {
DCHECK(output_surface_filter_);
capabilities_.hasParentCompositor = false;
DetachFromThread();
@ -56,8 +59,10 @@ bool CompositorOutputSurface::bindToClient(
WebKit::WebCompositorOutputSurfaceClient* client) {
DCHECK(CalledOnValidThread());
DCHECK(!client_);
if (!context3D_->makeContextCurrent())
return false;
if (context3D_.get()) {
if (!context3D_->makeContextCurrent())
return false;
}
client_ = client;
@ -74,6 +79,11 @@ WebGraphicsContext3D* CompositorOutputSurface::context3D() const {
return context3D_.get();
}
WebCompositorSoftwareOutputDevice* CompositorOutputSurface::softwareDevice()
const {
return software_device_.get();
}
void CompositorOutputSurface::sendFrameToParentCompositor(
const WebKit::WebCompositorFrame&) {
DCHECK(CalledOnValidThread());

@ -12,6 +12,7 @@
#include "base/threading/non_thread_safe.h"
#include "base/time.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebCompositorOutputSurface.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebCompositorSoftwareOutputDevice.h"
namespace base {
class TaskRunner;
@ -33,7 +34,8 @@ class CompositorOutputSurface
base::TaskRunner* target_task_runner);
CompositorOutputSurface(int32 routing_id,
WebKit::WebGraphicsContext3D* context3d);
WebKit::WebGraphicsContext3D* context3d,
WebKit::WebCompositorSoftwareOutputDevice* software);
virtual ~CompositorOutputSurface();
// WebCompositorOutputSurface implementation.
@ -41,6 +43,7 @@ class CompositorOutputSurface
WebKit::WebCompositorOutputSurfaceClient* client) OVERRIDE;
virtual const Capabilities& capabilities() const OVERRIDE;
virtual WebKit::WebGraphicsContext3D* context3D() const OVERRIDE;
virtual WebKit::WebCompositorSoftwareOutputDevice* softwareDevice() const;
virtual void sendFrameToParentCompositor(
const WebKit::WebCompositorFrame&) OVERRIDE;
@ -54,7 +57,7 @@ class CompositorOutputSurface
int routing_id_;
Capabilities capabilities_;
scoped_ptr<WebKit::WebGraphicsContext3D> context3D_;
scoped_ptr<WebKit::WebCompositorSoftwareOutputDevice> software_device_;
};
#endif // CONTENT_RENDERER_GPU_COMPOSITOR_OUTPUT_SURFACE_H_

@ -0,0 +1,178 @@
// Copyright (c) 2012 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 "content/renderer/gpu/compositor_software_output_device_gl_adapter.h"
#include "base/logging.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixelRef.h"
#include "third_party/skia/include/core/SkDevice.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
#include <GLES2/gl2.h>
using WebKit::WebImage;
using WebKit::WebGraphicsContext3D;
using WebKit::WebSize;
//------------------------------------------------------------------------------
CompositorSoftwareOutputDeviceGLAdapter::
CompositorSoftwareOutputDeviceGLAdapter(WebGraphicsContext3D* context3D)
: initialized_(false),
program_(0),
vertex_shader_(0),
fragment_shader_(0),
vertex_buffer_(0),
framebuffer_texture_id_(0),
context3d_(context3D),
locked_for_write_(false) {
}
CompositorSoftwareOutputDeviceGLAdapter::
~CompositorSoftwareOutputDeviceGLAdapter() {
Destroy();
}
WebImage* CompositorSoftwareOutputDeviceGLAdapter::lock(bool forWrite) {
locked_for_write_ = forWrite;
image_ = device_->accessBitmap(forWrite);
return &image_;
}
void CompositorSoftwareOutputDeviceGLAdapter::unlock() {
if (locked_for_write_)
Draw(device_->accessBitmap(false).pixelRef()->pixels());
image_.reset();
}
void CompositorSoftwareOutputDeviceGLAdapter::didChangeViewportSize(
WebSize size) {
if (!initialized_)
Initialize();
if (framebuffer_texture_size_ != gfx::Size(size))
Resize(size);
}
void CompositorSoftwareOutputDeviceGLAdapter::Initialize() {
// Vertex shader that flips the y axis.
static const char g_vertex_shader[] =
"attribute vec4 a_Position;"
"attribute vec2 a_texCoord;"
"varying vec2 v_texCoord;"
"void main() {"
" gl_Position = a_Position;"
" gl_Position.y = -gl_Position.y;"
" v_texCoord = a_texCoord;"
"}";
// Pixel shader that swizzles RGBA -> BGRA.
static const char g_fragment_shader[] =
"precision mediump float;"
"varying vec2 v_texCoord;"
"uniform sampler2D s_texture;"
"void main() {"
" gl_FragColor = texture2D(s_texture, v_texCoord).bgra;"
"}";
const GLfloat attribs[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f
};
context3d_->makeContextCurrent();
vertex_shader_ = context3d_->createShader(GL_VERTEX_SHADER);
context3d_->shaderSource(vertex_shader_, g_vertex_shader);
context3d_->compileShader(vertex_shader_);
fragment_shader_ = context3d_->createShader(GL_FRAGMENT_SHADER);
context3d_->shaderSource(fragment_shader_, g_fragment_shader);
context3d_->compileShader(fragment_shader_);
program_ = context3d_->createProgram();
context3d_->attachShader(program_, vertex_shader_);
context3d_->attachShader(program_, fragment_shader_);
vertex_buffer_ = context3d_->createBuffer();
context3d_->bindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
context3d_->bufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), attribs,
GL_STATIC_DRAW);
context3d_->enableVertexAttribArray(0);
context3d_->vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
context3d_->bindAttribLocation(program_, 0, "a_Position");
context3d_->enableVertexAttribArray(1);
context3d_->vertexAttribPointer(
1, 2, GL_FLOAT, GL_FALSE, 0, 8 * sizeof(GLfloat));
context3d_->bindAttribLocation(program_, 1, "a_texCoord");
context3d_->linkProgram(program_);
context3d_->useProgram(program_);
int texture_uniform = context3d_->getUniformLocation(program_, "s_texture");
context3d_->uniform1i(texture_uniform, 0);
context3d_->disable(GL_SCISSOR_TEST);
context3d_->clearColor(0, 0, 1, 1);
initialized_ = true;
}
void CompositorSoftwareOutputDeviceGLAdapter::Destroy() {
if (!initialized_)
return;
context3d_->makeContextCurrent();
context3d_->deleteShader(vertex_shader_);
context3d_->deleteShader(fragment_shader_);
context3d_->deleteProgram(program_);
context3d_->deleteBuffer(vertex_buffer_);
if (framebuffer_texture_id_)
context3d_->deleteTexture(framebuffer_texture_id_);
}
void CompositorSoftwareOutputDeviceGLAdapter::Resize(
const gfx::Size& viewport_size) {
framebuffer_texture_size_ = viewport_size;
device_.reset(new SkDevice(SkBitmap::kARGB_8888_Config,
viewport_size.width(), viewport_size.height(), true));
context3d_->makeContextCurrent();
context3d_->ensureFramebufferCHROMIUM();
framebuffer_texture_id_ = context3d_->createTexture();
context3d_->bindTexture(GL_TEXTURE_2D, framebuffer_texture_id_);
context3d_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
context3d_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
context3d_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
context3d_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
context3d_->viewport(0, 0, viewport_size.width(), viewport_size.height());
context3d_->reshape(viewport_size.width(), viewport_size.height());
}
void CompositorSoftwareOutputDeviceGLAdapter::Draw(void* pixels) {
if (!initialized_)
NOTREACHED();
if (!framebuffer_texture_id_)
NOTREACHED();
context3d_->makeContextCurrent();
context3d_->ensureFramebufferCHROMIUM();
context3d_->clear(GL_COLOR_BUFFER_BIT);
context3d_->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
framebuffer_texture_size_.width(), framebuffer_texture_size_.height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
context3d_->drawArrays(GL_TRIANGLE_STRIP, 0, 4);
context3d_->prepareTexture();
}

@ -0,0 +1,54 @@
// Copyright (c) 2012 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 CONTENT_RENDERER_GPU_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_GL_ADAPTER_H_
#define CONTENT_RENDERER_GPU_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_GL_ADAPTER_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/threading/non_thread_safe.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebImage.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebCompositorSoftwareOutputDevice.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
#include "ui/gfx/size.h"
// This class can be created only on the main thread, but then becomes pinned
// to a fixed thread when bindToClient is called.
class CompositorSoftwareOutputDeviceGLAdapter
: NON_EXPORTED_BASE(public WebKit::WebCompositorSoftwareOutputDevice),
NON_EXPORTED_BASE(public base::NonThreadSafe) {
public:
CompositorSoftwareOutputDeviceGLAdapter(
WebKit::WebGraphicsContext3D* context3d);
virtual ~CompositorSoftwareOutputDeviceGLAdapter();
virtual WebKit::WebImage* lock(bool forWrite) OVERRIDE;
virtual void unlock() OVERRIDE;
virtual void didChangeViewportSize(WebKit::WebSize size) OVERRIDE;
private:
void Initialize();
void Destroy();
void Resize(const gfx::Size& viewportSize);
void Draw(void* pixels);
bool initialized_;
int program_;
int vertex_shader_;
int fragment_shader_;
unsigned int vertex_buffer_;
unsigned framebuffer_texture_id_;
gfx::Size framebuffer_texture_size_;
scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
scoped_ptr<SkDevice> device_;
WebKit::WebImage image_;
bool locked_for_write_;
};
#endif // CONTENT_RENDERER_GPU_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_GL_ADAPTER_H_

@ -74,6 +74,7 @@
#include "content/renderer/geolocation_dispatcher.h"
#include "content/renderer/gpu/compositor_thread.h"
#include "content/renderer/gpu/compositor_output_surface.h"
#include "content/renderer/gpu/compositor_software_output_device_gl_adapter.h"
#include "content/renderer/idle_user_detector.h"
#include "content/renderer/input_tag_speech_dispatcher.h"
#include "content/renderer/java/java_bridge_dispatcher.h"
@ -1888,9 +1889,6 @@ WebStorageNamespace* RenderViewImpl::createSessionStorageNamespace(
}
WebKit::WebCompositorOutputSurface* RenderViewImpl::createOutputSurface() {
// TODO(aelias): if force-software-mode is on, create an output surface
// without a 3D context.
// Explicitly disable antialiasing for the compositor. As of the time of
// this writing, the only platform that supported antialiasing for the
// compositor was Mac OS X, because the on-screen OpenGL context creation
@ -1908,7 +1906,15 @@ WebKit::WebCompositorOutputSurface* RenderViewImpl::createOutputSurface() {
if (!context)
return NULL;
return new CompositorOutputSurface(routing_id(), context);
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kEnableSoftwareCompositingGLAdapter)) {
// In the absence of a software-based delegating renderer, use this
// stopgap adapter class to present the software renderer output using a
// 3d context.
return new CompositorOutputSurface(routing_id(), NULL,
new CompositorSoftwareOutputDeviceGLAdapter(context));
} else
return new CompositorOutputSurface(routing_id(), context, NULL);
}
void RenderViewImpl::didAddMessageToConsole(