Commit 76e9cc47 authored by boliu@chromium.org's avatar boliu@chromium.org

[Android WebView] Fix video in software mode

First ensure that main thread offscreen context is created after
on-screen context by keeping count of the number of compositors
that are initialized for hardware draw. Also release the compositor
thread offscreen context when the last compositor releases hardware
draw. Freeing the main thread context is still a TODO.

In software mode, still create StreamTextureFactory, but skip creating
StreamTextureProxy. WebMediaPlayerAndroid already works in this
mode, and it just means in-line video does not work in this case.
But video playback is still successful and user is able to enter fullscreen
to get working playback.

BUG=285349

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221843 0039d316-1c4b-4281-b951-d872f2087c98
parent aeb3cc10
...@@ -76,7 +76,8 @@ class VideoContextProvider ...@@ -76,7 +76,8 @@ class VideoContextProvider
class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory { class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
public: public:
SynchronousCompositorFactoryImpl() SynchronousCompositorFactoryImpl()
: wrapped_gl_context_for_main_thread_(NULL) { : wrapped_gl_context_for_main_thread_(NULL),
num_hardware_compositors_(0) {
SynchronousCompositorFactory::SetInstance(this); SynchronousCompositorFactory::SetInstance(this);
} }
...@@ -135,16 +136,24 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory { ...@@ -135,16 +136,24 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
virtual scoped_refptr<cc::ContextProvider> virtual scoped_refptr<cc::ContextProvider>
GetOffscreenContextProviderForMainThread() OVERRIDE { GetOffscreenContextProviderForMainThread() OVERRIDE {
if (!offscreen_context_for_main_thread_.get() || // This check only guarantees the main thread context is created after
offscreen_context_for_main_thread_->DestroyedOnMainThread()) { // a compositor did successfully initialize hardware draw in the past.
// In particular this does not guarantee that the main thread context
// will fail creation when all compositors release hardware draw.
bool failed = !CanCreateMainThreadContext();
if (!failed &&
(!offscreen_context_for_main_thread_.get() ||
offscreen_context_for_main_thread_->DestroyedOnMainThread())) {
offscreen_context_for_main_thread_ = offscreen_context_for_main_thread_ =
webkit::gpu::ContextProviderInProcess::Create( webkit::gpu::ContextProviderInProcess::Create(
CreateOffscreenContext()); CreateOffscreenContext());
if (offscreen_context_for_main_thread_.get() && failed = !offscreen_context_for_main_thread_.get() ||
!offscreen_context_for_main_thread_->BindToCurrentThread()) { !offscreen_context_for_main_thread_->BindToCurrentThread();
offscreen_context_for_main_thread_ = NULL; }
wrapped_gl_context_for_main_thread_ = NULL;
} if (failed) {
offscreen_context_for_main_thread_ = NULL;
wrapped_gl_context_for_main_thread_ = NULL;
} }
return offscreen_context_for_main_thread_; return offscreen_context_for_main_thread_;
} }
...@@ -157,7 +166,7 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory { ...@@ -157,7 +166,7 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
// any thread and is lightweight. // any thread and is lightweight.
virtual scoped_refptr<cc::ContextProvider> virtual scoped_refptr<cc::ContextProvider>
GetOffscreenContextProviderForCompositorThread() OVERRIDE { GetOffscreenContextProviderForCompositorThread() OVERRIDE {
base::AutoLock lock(offscreen_context_for_compositor_thread_creation_lock_); base::AutoLock lock(offscreen_context_for_compositor_thread_lock_);
if (!offscreen_context_for_compositor_thread_.get() || if (!offscreen_context_for_compositor_thread_.get() ||
offscreen_context_for_compositor_thread_->DestroyedOnMainThread()) { offscreen_context_for_compositor_thread_->DestroyedOnMainThread()) {
offscreen_context_for_compositor_thread_ = offscreen_context_for_compositor_thread_ =
...@@ -168,27 +177,75 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory { ...@@ -168,27 +177,75 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
virtual scoped_ptr<StreamTextureFactory> CreateStreamTextureFactory( virtual scoped_ptr<StreamTextureFactory> CreateStreamTextureFactory(
int view_id) OVERRIDE { int view_id) OVERRIDE {
scoped_refptr<VideoContextProvider> context_provider = scoped_refptr<VideoContextProvider> context_provider;
new VideoContextProvider(offscreen_context_for_main_thread_, if (CanCreateMainThreadContext()) {
wrapped_gl_context_for_main_thread_); context_provider =
new VideoContextProvider(offscreen_context_for_main_thread_,
wrapped_gl_context_for_main_thread_);
}
return make_scoped_ptr(new StreamTextureFactorySynchronousImpl( return make_scoped_ptr(new StreamTextureFactorySynchronousImpl(
context_provider.get(), view_id)) context_provider.get(), view_id))
.PassAs<StreamTextureFactory>(); .PassAs<StreamTextureFactory>();
} }
void CompositorInitializedHardwareDraw(SynchronousCompositorImpl* compositor);
void CompositorReleasedHardwareDraw(SynchronousCompositorImpl* compositor);
private: private:
void ReleaseGlobalHardwareResources();
bool CanCreateMainThreadContext();
SynchronousInputEventFilter synchronous_input_event_filter_; SynchronousInputEventFilter synchronous_input_event_filter_;
// Only guards construction of |offscreen_context_for_compositor_thread_|, // Only guards construction and destruction of
// not usage. // |offscreen_context_for_compositor_thread_|, not usage.
base::Lock offscreen_context_for_compositor_thread_creation_lock_; base::Lock offscreen_context_for_compositor_thread_lock_;
scoped_refptr<cc::ContextProvider> offscreen_context_for_main_thread_; scoped_refptr<cc::ContextProvider> offscreen_context_for_main_thread_;
// This is a pointer to the context owned by // This is a pointer to the context owned by
// |offscreen_context_for_main_thread_|. // |offscreen_context_for_main_thread_|.
gpu::GLInProcessContext* wrapped_gl_context_for_main_thread_; gpu::GLInProcessContext* wrapped_gl_context_for_main_thread_;
scoped_refptr<cc::ContextProvider> offscreen_context_for_compositor_thread_; scoped_refptr<cc::ContextProvider> offscreen_context_for_compositor_thread_;
// |num_hardware_compositor_lock_| is updated on UI thread only but can be
// read on renderer main thread.
base::Lock num_hardware_compositor_lock_;
unsigned int num_hardware_compositors_;
}; };
void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw(
SynchronousCompositorImpl* compositor) {
base::AutoLock lock(num_hardware_compositor_lock_);
num_hardware_compositors_++;
}
void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw(
SynchronousCompositorImpl* compositor) {
bool should_release_resources = false;
{
base::AutoLock lock(num_hardware_compositor_lock_);
DCHECK_GT(num_hardware_compositors_, 0u);
num_hardware_compositors_--;
should_release_resources = num_hardware_compositors_ == 0u;
}
if (should_release_resources)
ReleaseGlobalHardwareResources();
}
void SynchronousCompositorFactoryImpl::ReleaseGlobalHardwareResources() {
{
base::AutoLock lock(offscreen_context_for_compositor_thread_lock_);
offscreen_context_for_compositor_thread_ = NULL;
}
// TODO(boliu): Properly clean up command buffer server of main thread
// context here.
}
bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
base::AutoLock lock(num_hardware_compositor_lock_);
return num_hardware_compositors_ > 0;
}
base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory = base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
LAZY_INSTANCE_INITIALIZER; LAZY_INSTANCE_INITIALIZER;
...@@ -239,15 +296,19 @@ bool SynchronousCompositorImpl::InitializeHwDraw( ...@@ -239,15 +296,19 @@ bool SynchronousCompositorImpl::InitializeHwDraw(
scoped_refptr<gfx::GLSurface> surface) { scoped_refptr<gfx::GLSurface> surface) {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
DCHECK(output_surface_); DCHECK(output_surface_);
return output_surface_->InitializeHwDraw( bool success = output_surface_->InitializeHwDraw(
surface, surface,
g_factory.Get().GetOffscreenContextProviderForCompositorThread()); g_factory.Get().GetOffscreenContextProviderForCompositorThread());
if (success)
g_factory.Get().CompositorInitializedHardwareDraw(this);
return success;
} }
void SynchronousCompositorImpl::ReleaseHwDraw() { void SynchronousCompositorImpl::ReleaseHwDraw() {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
DCHECK(output_surface_); DCHECK(output_surface_);
return output_surface_->ReleaseHwDraw(); output_surface_->ReleaseHwDraw();
g_factory.Get().CompositorReleasedHardwareDraw(this);
} }
bool SynchronousCompositorImpl::DemandDrawHw( bool SynchronousCompositorImpl::DemandDrawHw(
......
...@@ -124,11 +124,14 @@ StreamTextureFactorySynchronousImpl::StreamTextureFactorySynchronousImpl( ...@@ -124,11 +124,14 @@ StreamTextureFactorySynchronousImpl::StreamTextureFactorySynchronousImpl(
StreamTextureFactorySynchronousImpl::~StreamTextureFactorySynchronousImpl() {} StreamTextureFactorySynchronousImpl::~StreamTextureFactorySynchronousImpl() {}
StreamTextureProxy* StreamTextureFactorySynchronousImpl::CreateProxy() { StreamTextureProxy* StreamTextureFactorySynchronousImpl::CreateProxy() {
if (!context_provider_)
return NULL;
return new StreamTextureProxyImpl(context_provider_); return new StreamTextureProxyImpl(context_provider_);
} }
void StreamTextureFactorySynchronousImpl::EstablishPeer(int32 stream_id, void StreamTextureFactorySynchronousImpl::EstablishPeer(int32 stream_id,
int player_id) { int player_id) {
DCHECK(context_provider_);
scoped_refptr<gfx::SurfaceTexture> surface_texture = scoped_refptr<gfx::SurfaceTexture> surface_texture =
context_provider_->GetSurfaceTexture(stream_id); context_provider_->GetSurfaceTexture(stream_id);
if (surface_texture) { if (surface_texture) {
...@@ -145,6 +148,7 @@ unsigned StreamTextureFactorySynchronousImpl::CreateStreamTexture( ...@@ -145,6 +148,7 @@ unsigned StreamTextureFactorySynchronousImpl::CreateStreamTexture(
unsigned* texture_id, unsigned* texture_id,
gpu::Mailbox* texture_mailbox, gpu::Mailbox* texture_mailbox,
unsigned* texture_mailbox_sync_point) { unsigned* texture_mailbox_sync_point) {
DCHECK(context_provider_);
WebKit::WebGraphicsContext3D* context = context_provider_->Context3d(); WebKit::WebGraphicsContext3D* context = context_provider_->Context3d();
unsigned stream_id = 0; unsigned stream_id = 0;
if (context->makeContextCurrent()) { if (context->makeContextCurrent()) {
...@@ -163,6 +167,7 @@ unsigned StreamTextureFactorySynchronousImpl::CreateStreamTexture( ...@@ -163,6 +167,7 @@ unsigned StreamTextureFactorySynchronousImpl::CreateStreamTexture(
void StreamTextureFactorySynchronousImpl::DestroyStreamTexture( void StreamTextureFactorySynchronousImpl::DestroyStreamTexture(
unsigned texture_id) { unsigned texture_id) {
DCHECK(context_provider_);
WebKit::WebGraphicsContext3D* context = context_provider_->Context3d(); WebKit::WebGraphicsContext3D* context = context_provider_->Context3d();
if (context->makeContextCurrent()) { if (context->makeContextCurrent()) {
context->destroyStreamTextureCHROMIUM(texture_id); context->destroyStreamTextureCHROMIUM(texture_id);
......
...@@ -127,7 +127,7 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid( ...@@ -127,7 +127,7 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
#endif #endif
if (stream_texture_factory_) { if (stream_texture_factory_) {
stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy()); stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy());
if (needs_establish_peer_) { if (needs_establish_peer_ && stream_texture_proxy_) {
stream_id_ = stream_texture_factory_->CreateStreamTexture( stream_id_ = stream_texture_factory_->CreateStreamTexture(
kGLTextureExternalOES, kGLTextureExternalOES,
&texture_id_, &texture_id_,
...@@ -860,6 +860,9 @@ void WebMediaPlayerAndroid::PutCurrentFrame( ...@@ -860,6 +860,9 @@ void WebMediaPlayerAndroid::PutCurrentFrame(
} }
void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() { void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() {
if (!stream_texture_proxy_)
return;
if (media_source_delegate_ && stream_texture_factory_) { if (media_source_delegate_ && stream_texture_factory_) {
// MediaCodec will release the old surface when it goes away, we need to // MediaCodec will release the old surface when it goes away, we need to
// recreate a new one each time this is called. // recreate a new one each time this is called.
......
...@@ -3015,26 +3015,26 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer( ...@@ -3015,26 +3015,26 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer(
scoped_refptr<cc::ContextProvider> context_provider = scoped_refptr<cc::ContextProvider> context_provider =
RenderThreadImpl::current()->OffscreenContextProviderForMainThread(); RenderThreadImpl::current()->OffscreenContextProviderForMainThread();
if (!context_provider.get()) {
LOG(ERROR) << "Failed to get context3d for media player";
return NULL;
}
if (!media_player_proxy_) {
media_player_proxy_ = new WebMediaPlayerProxyAndroid(
this, media_player_manager_.get());
}
scoped_ptr<StreamTextureFactory> stream_texture_factory; scoped_ptr<StreamTextureFactory> stream_texture_factory;
if (UsingSynchronousRendererCompositor()) { if (UsingSynchronousRendererCompositor()) {
SynchronousCompositorFactory* factory = SynchronousCompositorFactory* factory =
SynchronousCompositorFactory::GetInstance(); SynchronousCompositorFactory::GetInstance();
stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_); stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_);
} else { } else {
if (!context_provider.get()) {
LOG(ERROR) << "Failed to get context3d for media player";
return NULL;
}
stream_texture_factory.reset(new StreamTextureFactoryImpl( stream_texture_factory.reset(new StreamTextureFactoryImpl(
context_provider->Context3d(), gpu_channel_host, routing_id_)); context_provider->Context3d(), gpu_channel_host, routing_id_));
} }
if (!media_player_proxy_) {
media_player_proxy_ = new WebMediaPlayerProxyAndroid(
this, media_player_manager_.get());
}
scoped_ptr<WebMediaPlayerAndroid> web_media_player_android( scoped_ptr<WebMediaPlayerAndroid> web_media_player_android(
new WebMediaPlayerAndroid( new WebMediaPlayerAndroid(
frame, frame,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment