Skip to content

Commit

Permalink
cc: Emulate BeginFrame in OutputSurfaces that don't support it natively
Browse files Browse the repository at this point in the history
This includes two small fixes for the original version of this
patch that broke software compositing and WebView.

This will allow us to avoid having two different code paths
in the Scheduler. It also allows us to more easily remove the
VSyncTimeSource and FrameRateController from the Scheduler.

This patch instantiates the FrameRateController inside of
OutputSurface for now, but the FrameRateController could be
removed in future patches.

BUG=245920
BUG=243497
TBR=nduca@chromium.org,sievers@chromium.org,kbr@chromium.org

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@206020 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
brianderson@chromium.org committed Jun 13, 2013
1 parent 96d89f8 commit 107fc12
Show file tree
Hide file tree
Showing 42 changed files with 720 additions and 825 deletions.
2 changes: 0 additions & 2 deletions cc/cc.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,6 @@
'scheduler/texture_uploader.cc',
'scheduler/texture_uploader.h',
'scheduler/time_source.h',
'scheduler/vsync_time_source.cc',
'scheduler/vsync_time_source.h',
'trees/damage_tracker.cc',
'trees/damage_tracker.h',
'trees/layer_sorter.cc',
Expand Down
1 change: 0 additions & 1 deletion cc/cc_tests.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
'scheduler/scheduler_state_machine_unittest.cc',
'scheduler/scheduler_unittest.cc',
'scheduler/texture_uploader_unittest.cc',
'scheduler/vsync_time_source_unittest.cc',
'test/fake_web_graphics_context_3d_unittest.cc',
'trees/damage_tracker_unittest.cc',
'trees/layer_sorter_unittest.cc',
Expand Down
150 changes: 127 additions & 23 deletions cc/output/output_surface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
#include <vector>

#include "base/bind.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/output_surface_client.h"
#include "cc/scheduler/delay_based_time_source.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
Expand All @@ -32,7 +34,7 @@ class OutputSurfaceCallbacks
WebGraphicsSwapBuffersCompleteCallbackCHROMIUM,
public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
public:
explicit OutputSurfaceCallbacks(OutputSurfaceClient* client)
explicit OutputSurfaceCallbacks(OutputSurface* client)
: client_(client) {
DCHECK(client_);
}
Expand All @@ -44,50 +46,155 @@ class OutputSurfaceCallbacks
virtual void onContextLost() { client_->DidLoseOutputSurface(); }

private:
OutputSurfaceClient* client_;
OutputSurface* client_;
};

OutputSurface::OutputSurface(
scoped_ptr<WebKit::WebGraphicsContext3D> context3d)
: client_(NULL),
context3d_(context3d.Pass()),
: context3d_(context3d.Pass()),
has_gl_discard_backbuffer_(false),
has_swap_buffers_complete_callback_(false),
device_scale_factor_(-1),
weak_ptr_factory_(this) {
weak_ptr_factory_(this),
max_frames_pending_(0),
pending_swap_buffers_(0),
begin_frame_pending_(false),
client_(NULL) {
}

OutputSurface::OutputSurface(
scoped_ptr<cc::SoftwareOutputDevice> software_device)
: client_(NULL),
software_device_(software_device.Pass()),
: software_device_(software_device.Pass()),
has_gl_discard_backbuffer_(false),
has_swap_buffers_complete_callback_(false),
device_scale_factor_(-1),
weak_ptr_factory_(this) {
weak_ptr_factory_(this),
max_frames_pending_(0),
pending_swap_buffers_(0),
begin_frame_pending_(false),
client_(NULL) {
}

OutputSurface::OutputSurface(
scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
scoped_ptr<cc::SoftwareOutputDevice> software_device)
: client_(NULL),
context3d_(context3d.Pass()),
: context3d_(context3d.Pass()),
software_device_(software_device.Pass()),
has_gl_discard_backbuffer_(false),
has_swap_buffers_complete_callback_(false),
device_scale_factor_(-1),
weak_ptr_factory_(this) {
weak_ptr_factory_(this),
max_frames_pending_(0),
pending_swap_buffers_(0),
begin_frame_pending_(false),
client_(NULL) {
}

void OutputSurface::InitializeBeginFrameEmulation(
Thread* thread,
bool throttle_frame_production,
base::TimeDelta interval) {
if (throttle_frame_production){
frame_rate_controller_.reset(
new FrameRateController(
DelayBasedTimeSource::Create(interval, thread)));
} else {
frame_rate_controller_.reset(new FrameRateController(thread));
}

frame_rate_controller_->SetClient(this);
frame_rate_controller_->SetMaxSwapsPending(max_frames_pending_);

// The new frame rate controller will consume the swap acks of the old
// frame rate controller, so we set that expectation up here.
for (int i = 0; i < pending_swap_buffers_; i++)
frame_rate_controller_->DidSwapBuffers();
}

void OutputSurface::SetMaxFramesPending(int max_frames_pending) {
if (frame_rate_controller_)
frame_rate_controller_->SetMaxSwapsPending(max_frames_pending);
max_frames_pending_ = max_frames_pending;
}

void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase,
base::TimeDelta interval) {
TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged",
"timebase", (timebase - base::TimeTicks()).InSecondsF(),
"interval", interval.InSecondsF());
if (frame_rate_controller_)
frame_rate_controller_->SetTimebaseAndInterval(timebase, interval);
}

void OutputSurface::FrameRateControllerTick(bool throttled) {
DCHECK(frame_rate_controller_);
if (!throttled)
BeginFrame(frame_rate_controller_->LastTickTime());
}

// Forwarded to OutputSurfaceClient
void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) {
TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
client_->SetNeedsRedrawRect(damage_rect);
}

void OutputSurface::SetNeedsBeginFrame(bool enable) {
TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginFrame", "enable", enable);
begin_frame_pending_ = false;
if (frame_rate_controller_)
frame_rate_controller_->SetActive(enable);
}

void OutputSurface::BeginFrame(base::TimeTicks frame_time) {
if (begin_frame_pending_ ||
(pending_swap_buffers_ >= max_frames_pending_ && max_frames_pending_ > 0))
return;
TRACE_EVENT1("cc", "OutputSurface::BeginFrame",
"pending_swap_buffers_", pending_swap_buffers_);
begin_frame_pending_ = true;
client_->BeginFrame(frame_time);
}

void OutputSurface::DidSwapBuffers() {
begin_frame_pending_ = false;
pending_swap_buffers_++;
TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers",
"pending_swap_buffers_", pending_swap_buffers_);
if (frame_rate_controller_)
frame_rate_controller_->DidSwapBuffers();
}

void OutputSurface::OnSwapBuffersComplete(const CompositorFrameAck* ack) {
pending_swap_buffers_--;
TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete",
"pending_swap_buffers_", pending_swap_buffers_);
client_->OnSwapBuffersComplete(ack);
if (frame_rate_controller_)
frame_rate_controller_->DidSwapBuffersComplete();
}

void OutputSurface::DidLoseOutputSurface() {
TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
begin_frame_pending_ = false;
pending_swap_buffers_ = 0;
client_->DidLoseOutputSurface();
}

void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform,
gfx::Rect viewport) {
client_->SetExternalDrawConstraints(transform, viewport);
}

OutputSurface::~OutputSurface() {
if (frame_rate_controller_)
frame_rate_controller_->SetActive(false);
}

bool OutputSurface::ForcedDrawToSoftwareDevice() const {
return false;
}

bool OutputSurface::BindToClient(
cc::OutputSurfaceClient* client) {
bool OutputSurface::BindToClient(cc::OutputSurfaceClient* client) {
DCHECK(client);
client_ = client;
bool success = true;
Expand Down Expand Up @@ -143,7 +250,7 @@ void OutputSurface::SetContext3D(


context3d_ = context3d.Pass();
callbacks_.reset(new OutputSurfaceCallbacks(client_));
callbacks_.reset(new OutputSurfaceCallbacks(this));
context3d_->setSwapBuffersCompleteCallbackCHROMIUM(callbacks_.get());
context3d_->setContextLostCallback(callbacks_.get());
}
Expand Down Expand Up @@ -186,6 +293,7 @@ void OutputSurface::BindFramebuffer() {
void OutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
if (frame->software_frame_data) {
PostSwapBuffersComplete();
DidSwapBuffers();
return;
}

Expand All @@ -207,20 +315,16 @@ void OutputSurface::SwapBuffers(cc::CompositorFrame* frame) {

if (!has_swap_buffers_complete_callback_)
PostSwapBuffersComplete();

DidSwapBuffers();
}

void OutputSurface::PostSwapBuffersComplete() {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&OutputSurface::SwapBuffersComplete,
weak_ptr_factory_.GetWeakPtr()));
}

void OutputSurface::SwapBuffersComplete() {
if (!client_)
return;

client_->OnSwapBuffersComplete(NULL);
base::Bind(&OutputSurface::OnSwapBuffersComplete,
weak_ptr_factory_.GetWeakPtr(),
static_cast<CompositorFrameAck*>(NULL)));
}

} // namespace cc
44 changes: 38 additions & 6 deletions cc/output/output_surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,24 @@
#include "cc/base/cc_export.h"
#include "cc/output/context_provider.h"
#include "cc/output/software_output_device.h"
#include "cc/scheduler/frame_rate_controller.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"

namespace ui { struct LatencyInfo; }

namespace gfx {
class Rect;
class Size;
class Transform;
}

namespace cc {

class CompositorFrame;
class CompositorFrameAck;
class OutputSurfaceClient;
class OutputSurfaceCallbacks;
class Thread;

// Represents the output surface for a compositor. The compositor owns
// and manages its destruction. Its lifetime is:
Expand All @@ -34,7 +38,7 @@ class OutputSurfaceCallbacks;
// From here on, it will only be used on the compositor thread.
// 3. If the 3D context is lost, then the compositor will delete the output
// surface (on the compositor thread) and go back to step 1.
class CC_EXPORT OutputSurface {
class CC_EXPORT OutputSurface : public FrameRateControllerClient {
public:
explicit OutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d);

Expand Down Expand Up @@ -83,6 +87,13 @@ class CC_EXPORT OutputSurface {
// thread.
virtual bool BindToClient(OutputSurfaceClient* client);

void InitializeBeginFrameEmulation(
Thread* thread,
bool throttle_frame_production,
base::TimeDelta interval);

void SetMaxFramesPending(int max_frames_pending);

virtual void EnsureBackbuffer();
virtual void DiscardBackbuffer();

Expand All @@ -103,7 +114,7 @@ class CC_EXPORT OutputSurface {
// Requests a BeginFrame notification from the output surface. The
// notification will be delivered by calling
// OutputSurfaceClient::BeginFrame until the callback is disabled.
virtual void SetNeedsBeginFrame(bool enable) {}
virtual void SetNeedsBeginFrame(bool enable);

protected:
// Synchronously initialize context3d and enter hardware mode.
Expand All @@ -116,7 +127,6 @@ class CC_EXPORT OutputSurface {

void PostSwapBuffersComplete();

OutputSurfaceClient* client_;
struct cc::OutputSurface::Capabilities capabilities_;
scoped_ptr<OutputSurfaceCallbacks> callbacks_;
scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
Expand All @@ -125,12 +135,34 @@ class CC_EXPORT OutputSurface {
bool has_swap_buffers_complete_callback_;
gfx::Size surface_size_;
float device_scale_factor_;
base::WeakPtrFactory<OutputSurface> weak_ptr_factory_;

// The FrameRateController is deprecated.
// Platforms should move to native BeginFrames instead.
void OnVSyncParametersChanged(base::TimeTicks timebase,
base::TimeDelta interval);
virtual void FrameRateControllerTick(bool throttled) OVERRIDE;
scoped_ptr<FrameRateController> frame_rate_controller_;
int max_frames_pending_;
int pending_swap_buffers_;
bool begin_frame_pending_;

// Forwarded to OutputSurfaceClient but threaded through OutputSurface
// first so OutputSurface has a chance to update the FrameRateController
bool HasClient() { return !!client_; }
void SetNeedsRedrawRect(gfx::Rect damage_rect);
void BeginFrame(base::TimeTicks frame_time);
void DidSwapBuffers();
void OnSwapBuffersComplete(const CompositorFrameAck* ack);
void DidLoseOutputSurface();
void SetExternalDrawConstraints(const gfx::Transform& transform,
gfx::Rect viewport);

private:
void SetContext3D(scoped_ptr<WebKit::WebGraphicsContext3D> context3d);
void SwapBuffersComplete();
OutputSurfaceClient* client_;
friend class OutputSurfaceCallbacks;

base::WeakPtrFactory<OutputSurface> weak_ptr_factory_;
void SetContext3D(scoped_ptr<WebKit::WebGraphicsContext3D> context3d);

DISALLOW_COPY_AND_ASSIGN(OutputSurface);
};
Expand Down
2 changes: 0 additions & 2 deletions cc/output/output_surface_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ class CC_EXPORT OutputSurfaceClient {
virtual bool DeferredInitialize(
scoped_refptr<ContextProvider> offscreen_context_provider) = 0;
virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) = 0;
virtual void OnVSyncParametersChanged(base::TimeTicks timebase,
base::TimeDelta interval) = 0;
virtual void BeginFrame(base::TimeTicks frame_time) = 0;
virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) = 0;
virtual void DidLoseOutputSurface() = 0;
Expand Down
Loading

0 comments on commit 107fc12

Please sign in to comment.