diff options
author | skaslev@chromium.org <skaslev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-08 04:38:51 +0000 |
---|---|---|
committer | skaslev@chromium.org <skaslev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-08 04:38:51 +0000 |
commit | 42f40a546f90a81727c05aea44ce299d97d7507b (patch) | |
tree | 3004f86f245e15cea8606868cdbdac2d0d1b0ac0 | |
parent | 165e50b4b57c105da46d662273f1ce4a164b195d (diff) | |
download | chromium_src-42f40a546f90a81727c05aea44ce299d97d7507b.zip chromium_src-42f40a546f90a81727c05aea44ce299d97d7507b.tar.gz chromium_src-42f40a546f90a81727c05aea44ce299d97d7507b.tar.bz2 |
[Aura] Added Support for rendering software compositor frames as cc::TextureLayers through cc::TextureMailbox.
BUG=161008
R=piman
TBR=jschuh,ben
Review URL: https://chromiumcodereview.appspot.com/15001027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@205010 0039d316-1c4b-4281-b951-d872f2087c98
35 files changed, 612 insertions, 283 deletions
@@ -9,7 +9,6 @@ include_rules = [ "+ui/base", "+ui/gfx", "+ui/gl", - "+ui/surface", # DO NOT ADD ANY NEW WEBKIT HEADERS TO THIS LIST. # TODO(danakj): Drop dependencies on WebKit Platform API from cc. "+third_party/WebKit/public/platform/WebAnimationDelegate.h", @@ -363,7 +363,6 @@ '<(DEPTH)/skia/skia.gyp:skia', '<(DEPTH)/media/media.gyp:media', '<(DEPTH)/ui/gl/gl.gyp:gl', - '<(DEPTH)/ui/surface/surface.gyp:surface', '<(DEPTH)/ui/ui.gyp:ui', '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink', ], diff --git a/cc/layers/texture_layer.cc b/cc/layers/texture_layer.cc index 4266718..d099631 100644 --- a/cc/layers/texture_layer.cc +++ b/cc/layers/texture_layer.cc @@ -12,24 +12,28 @@ namespace cc { -static void RunCallbackOnMainThread( +namespace { + +void RunCallback( const TextureMailbox::ReleaseCallback& callback, unsigned sync_point, bool lost_resource) { callback.Run(sync_point, lost_resource); } -static void PostCallbackToMainThread( - Thread* main_thread, +void PostCallbackToThread( + Thread* thread, const TextureMailbox::ReleaseCallback& callback, unsigned sync_point, bool lost_resource) { - main_thread->PostTask(base::Bind(&RunCallbackOnMainThread, - callback, - sync_point, - lost_resource)); + if (!callback.is_null()) { + thread->PostTask(base::Bind(&RunCallback, callback, + sync_point, lost_resource)); + } } +} // namespace + scoped_refptr<TextureLayer> TextureLayer::Create(TextureLayerClient* client) { return scoped_refptr<TextureLayer>(new TextureLayer(client, false)); } @@ -143,13 +147,13 @@ void TextureLayer::SetTextureId(unsigned id) { void TextureLayer::SetTextureMailbox(const TextureMailbox& mailbox) { DCHECK(uses_mailbox_); - DCHECK(mailbox.IsEmpty() || !mailbox.Equals(texture_mailbox_)); + if (own_mailbox_) + DCHECK(!mailbox.IsValid() || !mailbox.Equals(texture_mailbox_)); // If we never commited the mailbox, we need to release it here if (own_mailbox_) texture_mailbox_.RunReleaseCallback(texture_mailbox_.sync_point(), false); texture_mailbox_ = mailbox; own_mailbox_ = true; - SetNeedsCommit(); } @@ -174,7 +178,7 @@ void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) { } bool TextureLayer::DrawsContent() const { - return (client_ || texture_id_ || !texture_mailbox_.IsEmpty()) && + return (client_ || texture_id_ || texture_mailbox_.IsValid()) && !context_lost_ && Layer::DrawsContent(); } @@ -184,12 +188,16 @@ void TextureLayer::Update(ResourceUpdateQueue* queue, if (client_) { if (uses_mailbox_) { TextureMailbox mailbox; - if (client_->PrepareTextureMailbox(&mailbox)) + if (client_->PrepareTextureMailbox(&mailbox)) { + if (mailbox.IsTexture()) + DCHECK(client_->Context3d()); SetTextureMailbox(mailbox); + } } else { + DCHECK(client_->Context3d()); texture_id_ = client_->PrepareTexture(queue); } - context_lost_ = + context_lost_ = client_->Context3d() && client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR; } @@ -207,12 +215,10 @@ void TextureLayer::PushPropertiesTo(LayerImpl* layer) { texture_layer->set_premultiplied_alpha(premultiplied_alpha_); if (uses_mailbox_ && own_mailbox_) { Thread* main_thread = layer_tree_host()->proxy()->MainThread(); - TextureMailbox::ReleaseCallback callback; - if (!texture_mailbox_.IsEmpty()) - callback = base::Bind( - &PostCallbackToMainThread, main_thread, texture_mailbox_.callback()); - texture_layer->SetTextureMailbox(TextureMailbox( - texture_mailbox_.name(), callback, texture_mailbox_.sync_point())); + TextureMailbox::ReleaseCallback callback = base::Bind( + &PostCallbackToThread, main_thread, texture_mailbox_.callback()); + texture_layer->SetTextureMailbox( + texture_mailbox_.CopyWithNewCallback(callback)); own_mailbox_ = false; } else { texture_layer->set_texture_id(texture_id_); diff --git a/cc/layers/texture_layer.h b/cc/layers/texture_layer.h index cff2e3c..6de1ea49 100644 --- a/cc/layers/texture_layer.h +++ b/cc/layers/texture_layer.h @@ -62,6 +62,7 @@ class CC_EXPORT TextureLayer : public Layer { void SetTextureId(unsigned texture_id); // Code path for plugins which supply their own mailbox. + bool uses_mailbox() const { return uses_mailbox_; } void SetTextureMailbox(const TextureMailbox& mailbox); void WillModifyTexture(); diff --git a/cc/layers/texture_layer_impl.cc b/cc/layers/texture_layer_impl.cc index 4406297..58b4508 100644 --- a/cc/layers/texture_layer_impl.cc +++ b/cc/layers/texture_layer_impl.cc @@ -34,7 +34,8 @@ TextureLayerImpl::~TextureLayerImpl() { FreeTextureMailbox(); } void TextureLayerImpl::SetTextureMailbox(const TextureMailbox& mailbox) { DCHECK(uses_mailbox_); - DCHECK(mailbox.IsEmpty() || !mailbox.Equals(texture_mailbox_)); + if (own_mailbox_) + DCHECK(!mailbox.IsValid() || !mailbox.Equals(texture_mailbox_)); FreeTextureMailbox(); texture_mailbox_ = mailbox; own_mailbox_ = true; @@ -146,7 +147,7 @@ void TextureLayerImpl::DidBecomeActive() { return; DCHECK(!external_texture_resource_); ResourceProvider* resource_provider = layer_tree_impl()->resource_provider(); - if (!texture_mailbox_.IsEmpty()) { + if (texture_mailbox_.IsValid()) { external_texture_resource_ = resource_provider->CreateResourceFromTextureMailbox(texture_mailbox_); } diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc index 505c1fc..65351da 100644 --- a/cc/layers/texture_layer_unittest.cc +++ b/cc/layers/texture_layer_unittest.cc @@ -205,6 +205,9 @@ class MockMailboxCallback { MOCK_METHOD3(Release, void(const std::string& mailbox, unsigned sync_point, bool lost_resource)); + MOCK_METHOD3(Release2, void(base::SharedMemory* shared_memory, + unsigned sync_point, + bool lost_resource)); }; struct CommonMailboxObjects { @@ -212,7 +215,8 @@ struct CommonMailboxObjects { : mailbox_name1_(64, '1'), mailbox_name2_(64, '2'), sync_point1_(1), - sync_point2_(2) { + sync_point2_(2), + shared_memory_(new base::SharedMemory) { release_mailbox1_ = base::Bind(&MockMailboxCallback::Release, base::Unretained(&mock_callback_), mailbox_name1_); @@ -225,6 +229,13 @@ struct CommonMailboxObjects { gpu::Mailbox m2; m2.SetName(reinterpret_cast<const int8*>(mailbox_name2_.data())); mailbox2_ = TextureMailbox(m2, release_mailbox2_, sync_point2_); + + gfx::Size size(128, 128); + EXPECT_TRUE(shared_memory_->CreateAndMapAnonymous(4 * size.GetArea())); + release_mailbox3_ = base::Bind(&MockMailboxCallback::Release2, + base::Unretained(&mock_callback_), + shared_memory_.get()); + mailbox3_ = TextureMailbox(shared_memory_.get(), size, release_mailbox3_); } std::string mailbox_name1_; @@ -232,10 +243,13 @@ struct CommonMailboxObjects { MockMailboxCallback mock_callback_; TextureMailbox::ReleaseCallback release_mailbox1_; TextureMailbox::ReleaseCallback release_mailbox2_; + TextureMailbox::ReleaseCallback release_mailbox3_; TextureMailbox mailbox1_; TextureMailbox mailbox2_; + TextureMailbox mailbox3_; unsigned sync_point1_; unsigned sync_point2_; + scoped_ptr<base::SharedMemory> shared_memory_; }; class TextureLayerWithMailboxTest : public TextureLayerTest { @@ -288,6 +302,20 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) { Mock::VerifyAndClearExpectations(layer_tree_host_.get()); Mock::VerifyAndClearExpectations(&test_data_.mock_callback_); + test_layer->SetTextureMailbox(test_data_.mailbox3_); + Mock::VerifyAndClearExpectations(layer_tree_host_.get()); + Mock::VerifyAndClearExpectations(&test_data_.mock_callback_); + + EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0); + EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); + EXPECT_CALL(test_data_.mock_callback_, + Release2(test_data_.shared_memory_.get(), + 0, false)) + .Times(1); + test_layer->SetTextureMailbox(TextureMailbox()); + Mock::VerifyAndClearExpectations(layer_tree_host_.get()); + Mock::VerifyAndClearExpectations(&test_data_.mock_callback_); + // Test destructor. EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); test_layer->SetTextureMailbox(test_data_.mailbox1_); diff --git a/cc/output/compositor_frame_ack.cc b/cc/output/compositor_frame_ack.cc index a411b42..feb0bac 100644 --- a/cc/output/compositor_frame_ack.cc +++ b/cc/output/compositor_frame_ack.cc @@ -6,7 +6,8 @@ namespace cc { -CompositorFrameAck::CompositorFrameAck() {} +CompositorFrameAck::CompositorFrameAck() + : last_software_frame_id(0) {} CompositorFrameAck::~CompositorFrameAck() {} diff --git a/cc/output/compositor_frame_ack.h b/cc/output/compositor_frame_ack.h index 5b4bb50..276ecf0 100644 --- a/cc/output/compositor_frame_ack.h +++ b/cc/output/compositor_frame_ack.h @@ -9,7 +9,6 @@ #include "cc/base/cc_export.h" #include "cc/output/gl_frame_data.h" #include "cc/resources/transferable_resource.h" -#include "ui/surface/transport_dib.h" namespace cc { @@ -20,7 +19,7 @@ class CC_EXPORT CompositorFrameAck { TransferableResourceArray resources; scoped_ptr<GLFrameData> gl_frame_data; - TransportDIB::Id last_dib_id; + unsigned last_software_frame_id; private: DISALLOW_COPY_AND_ASSIGN(CompositorFrameAck); diff --git a/cc/output/software_frame_data.cc b/cc/output/software_frame_data.cc index 20da28e..0b43032 100644 --- a/cc/output/software_frame_data.cc +++ b/cc/output/software_frame_data.cc @@ -6,7 +6,9 @@ namespace cc { -SoftwareFrameData::SoftwareFrameData() {} +SoftwareFrameData::SoftwareFrameData() + : id(0), + handle(base::SharedMemory::NULLHandle()) {} SoftwareFrameData::~SoftwareFrameData() {} diff --git a/cc/output/software_frame_data.h b/cc/output/software_frame_data.h index c1e3dd7..b7fb44a 100644 --- a/cc/output/software_frame_data.h +++ b/cc/output/software_frame_data.h @@ -5,10 +5,9 @@ #ifndef CC_OUTPUT_SOFTWARE_FRAME_DATA_H_ #define CC_OUTPUT_SOFTWARE_FRAME_DATA_H_ -#include "base/basictypes.h" +#include "base/memory/shared_memory.h" #include "cc/base/cc_export.h" #include "ui/gfx/rect.h" -#include "ui/surface/transport_dib.h" namespace cc { @@ -17,9 +16,10 @@ class CC_EXPORT SoftwareFrameData { SoftwareFrameData(); ~SoftwareFrameData(); + unsigned id; gfx::Size size; gfx::Rect damage_rect; - TransportDIB::Id dib_id; + base::SharedMemoryHandle handle; }; } // namespace cc diff --git a/cc/output/software_output_device.cc b/cc/output/software_output_device.cc index 719eeed..30817e0 100644 --- a/cc/output/software_output_device.cc +++ b/cc/output/software_output_device.cc @@ -35,9 +35,10 @@ SkCanvas* SoftwareOutputDevice::BeginPaint(gfx::Rect damage_rect) { void SoftwareOutputDevice::EndPaint(SoftwareFrameData* frame_data) { DCHECK(device_); if (frame_data) { + frame_data->id = 0; frame_data->size = viewport_size_; frame_data->damage_rect = damage_rect_; - frame_data->dib_id = TransportDIB::Id(); + frame_data->handle = base::SharedMemory::NULLHandle(); } } @@ -53,7 +54,7 @@ void SoftwareOutputDevice::Scroll( NOTIMPLEMENTED(); } -void SoftwareOutputDevice::ReclaimDIB(const TransportDIB::Id& id) { +void SoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) { NOTIMPLEMENTED(); } diff --git a/cc/output/software_output_device.h b/cc/output/software_output_device.h index 9899629..fbada74 100644 --- a/cc/output/software_output_device.h +++ b/cc/output/software_output_device.h @@ -11,7 +11,6 @@ #include "ui/gfx/rect.h" #include "ui/gfx/size.h" #include "ui/gfx/vector2d.h" -#include "ui/surface/transport_dib.h" class SkBitmap; class SkDevice; @@ -39,7 +38,7 @@ class CC_EXPORT SoftwareOutputDevice { gfx::Rect clip_rect); // TODO(skaslev) Remove this after UberCompositor lands. - virtual void ReclaimDIB(const TransportDIB::Id& id); + virtual void ReclaimSoftwareFrame(unsigned id); protected: gfx::Size viewport_size_; @@ -47,6 +46,7 @@ class CC_EXPORT SoftwareOutputDevice { skia::RefPtr<SkDevice> device_; skia::RefPtr<SkCanvas> canvas_; + private: DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDevice); }; diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc index c53e0c7..9884666 100644 --- a/cc/output/software_renderer.cc +++ b/cc/output/software_renderer.cc @@ -113,7 +113,7 @@ void SoftwareRenderer::SwapBuffers(const ui::LatencyInfo& latency_info) { void SoftwareRenderer::ReceiveCompositorFrameAck( const CompositorFrameAck& ack) { - output_device_->ReclaimDIB(ack.last_dib_id); + output_device_->ReclaimSoftwareFrame(ack.last_software_frame_id); } bool SoftwareRenderer::FlippedFramebuffer() const { diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index a2b6eec..68882c6 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc @@ -236,7 +236,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateGLTexture( ResourceProvider::ResourceId ResourceProvider::CreateBitmap(gfx::Size size) { DCHECK(thread_checker_.CalledOnValidThread()); - uint8_t* pixels = new uint8_t[size.width() * size.height() * 4]; + uint8_t* pixels = new uint8_t[4 * size.GetArea()]; ResourceId id = next_id_++; Resource resource(pixels, size, GL_RGBA, GL_LINEAR); @@ -276,12 +276,22 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( DCHECK(thread_checker_.CalledOnValidThread()); // Just store the information. Mailbox will be consumed in LockForRead(). ResourceId id = next_id_++; - unsigned texture_id = 0; - Resource resource(texture_id, gfx::Size(), 0, GL_LINEAR); + DCHECK(mailbox.IsValid()); + Resource& resource = resources_[id]; + if (mailbox.IsTexture()) { + unsigned texture_id = 0; + resource = Resource(texture_id, gfx::Size(), 0, GL_LINEAR); + } else { + DCHECK(mailbox.IsSharedMemory()); + base::SharedMemory* shared_memory = mailbox.shared_memory(); + DCHECK(shared_memory->memory()); + uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory()); + resource = Resource(pixels, mailbox.shared_memory_size(), + GL_RGBA, GL_LINEAR); + } resource.external = true; resource.allocated = true; resource.mailbox = mailbox; - resources_[id] = resource; return id; } @@ -332,20 +342,29 @@ void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it, DCHECK(context3d); GLC(context3d, context3d->deleteBuffer(resource->gl_pixel_buffer_id)); } - if (!resource->mailbox.IsEmpty() && resource->external) { - WebGraphicsContext3D* context3d = output_surface_->context3d(); - DCHECK(context3d); + if (resource->mailbox.IsValid() && resource->external) { unsigned sync_point = resource->mailbox.sync_point(); - if (!lost_resource && resource->gl_id) { - GLC(context3d, context3d->bindTexture( - resource->mailbox.target(), resource->gl_id)); - GLC(context3d, context3d->produceTextureCHROMIUM( - resource->mailbox.target(), resource->mailbox.data())); + if (resource->mailbox.IsTexture()) { + WebGraphicsContext3D* context3d = output_surface_->context3d(); + DCHECK(context3d); + if (!lost_resource && resource->gl_id) { + GLC(context3d, context3d->bindTexture( + resource->mailbox.target(), resource->gl_id)); + GLC(context3d, context3d->produceTextureCHROMIUM( + resource->mailbox.target(), resource->mailbox.data())); + } + if (resource->gl_id) + GLC(context3d, context3d->deleteTexture(resource->gl_id)); + if (!lost_resource && resource->gl_id) + sync_point = context3d->insertSyncPoint(); + } else { + DCHECK(resource->mailbox.IsSharedMemory()); + base::SharedMemory* shared_memory = resource->mailbox.shared_memory(); + if (resource->pixels && shared_memory) { + DCHECK(shared_memory->memory() == resource->pixels); + resource->pixels = NULL; + } } - if (resource->gl_id) - GLC(context3d, context3d->deleteTexture(resource->gl_id)); - if (!lost_resource && resource->gl_id) - sync_point = context3d->insertSyncPoint(); resource->mailbox.RunReleaseCallback(sync_point, lost_resource); } if (resource->pixels) @@ -487,18 +506,21 @@ const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) { // Uninitialized! Call SetPixels or LockForWrite first. DCHECK(resource->allocated); - if (!resource->gl_id && resource->external && !resource->mailbox.IsEmpty()) { - WebGraphicsContext3D* context3d = output_surface_->context3d(); - DCHECK(context3d); - if (resource->mailbox.sync_point()) { - GLC(context3d, context3d->waitSyncPoint(resource->mailbox.sync_point())); - resource->mailbox.ResetSyncPoint(); + if (resource->external) { + if (!resource->gl_id && resource->mailbox.IsTexture()) { + WebGraphicsContext3D* context3d = output_surface_->context3d(); + DCHECK(context3d); + if (resource->mailbox.sync_point()) { + GLC(context3d, + context3d->waitSyncPoint(resource->mailbox.sync_point())); + resource->mailbox.ResetSyncPoint(); + } + resource->gl_id = context3d->createTexture(); + GLC(context3d, context3d->bindTexture( + resource->mailbox.target(), resource->gl_id)); + GLC(context3d, context3d->consumeTextureCHROMIUM( + resource->mailbox.target(), resource->mailbox.data())); } - resource->gl_id = context3d->createTexture(); - GLC(context3d, context3d->bindTexture( - resource->mailbox.target(), resource->gl_id)); - GLC(context3d, context3d->consumeTextureCHROMIUM( - resource->mailbox.target(), resource->mailbox.data())); } resource->lock_for_read_count++; @@ -840,7 +862,7 @@ void ResourceProvider::ReceiveFromParent( DCHECK(resource->exported); resource->exported = false; resource->filter = it->filter; - DCHECK(resource->mailbox.Equals(it->mailbox)); + DCHECK(resource->mailbox.ContainsMailbox(it->mailbox)); if (resource->gl_id) { if (it->sync_point) GLC(context3d, context3d->waitSyncPoint(it->sync_point)); @@ -867,7 +889,7 @@ bool ResourceProvider::TransferResource(WebGraphicsContext3D* context, Resource* source = &it->second; DCHECK(!source->locked_for_write); DCHECK(!source->lock_for_read_count); - DCHECK(!source->external || (source->external && !source->mailbox.IsEmpty())); + DCHECK(!source->external || (source->external && source->mailbox.IsValid())); DCHECK(source->allocated); if (source->exported) return false; @@ -876,7 +898,10 @@ bool ResourceProvider::TransferResource(WebGraphicsContext3D* context, resource->filter = source->filter; resource->size = source->size; - if (source->mailbox.IsEmpty()) { + // TODO(skaslev) Implement this path for shared memory resources. + DCHECK(!source->mailbox.IsSharedMemory()); + + if (!source->mailbox.IsTexture()) { GLC(context3d, context3d->genMailboxCHROMIUM(resource->mailbox.name)); source->mailbox.SetName(resource->mailbox); } else { @@ -913,7 +938,7 @@ void ResourceProvider::AcquirePixelBuffer(ResourceId id) { resource->gl_pixel_buffer_id); context3d->bufferData( GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->size.width() * resource->size.height() * 4, + 4 * resource->size.GetArea(), NULL, GL_DYNAMIC_DRAW); context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); @@ -923,8 +948,7 @@ void ResourceProvider::AcquirePixelBuffer(ResourceId id) { if (resource->pixel_buffer) return; - resource->pixel_buffer = new uint8_t[ - resource->size.width() * resource->size.height() * 4]; + resource->pixel_buffer = new uint8_t[4 * resource->size.GetArea()]; } } @@ -1049,6 +1073,7 @@ void ResourceProvider::SetPixelsFromBuffer(ResourceId id) { } if (resource->pixels) { + DCHECK(!resource->mailbox.IsValid()); DCHECK(resource->pixel_buffer); DCHECK(resource->format == GL_RGBA); diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc index c7cba3b..0ca3d02 100644 --- a/cc/resources/resource_provider_unittest.cc +++ b/cc/resources/resource_provider_unittest.cc @@ -874,6 +874,41 @@ TEST_P(ResourceProviderTest, Shutdown) { EXPECT_FALSE(lost_resource); } +static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory( + gfx::Size size, uint32_t value) { + scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory); + CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea())); + uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory()); + CHECK(pixels); + std::fill_n(pixels, size.GetArea(), value); + return shared_memory.Pass(); +} + +static void ReleaseSharedMemoryCallback( + bool* release_called, + unsigned sync_point, bool lost_resource) { + *release_called = true; +} + +TEST_P(ResourceProviderTest, ShutdownSharedMemory) { + if (GetParam() != ResourceProvider::Bitmap) + return; + + gfx::Size size(64, 64); + scoped_ptr<base::SharedMemory> shared_memory( + CreateAndFillSharedMemory(size, 0)); + + bool release_called = false; + TextureMailbox::ReleaseCallback callback = + base::Bind(ReleaseSharedMemoryCallback, &release_called); + resource_provider_->CreateResourceFromTextureMailbox( + TextureMailbox(shared_memory.get(), size, callback)); + + resource_provider_.reset(); + + EXPECT_TRUE(release_called); +} + TEST_P(ResourceProviderTest, ShutdownWithExportedResource) { // TextureMailbox callbacks only exist for GL textures for now. if (GetParam() != ResourceProvider::GLTexture) @@ -1072,6 +1107,37 @@ TEST_P(ResourceProviderTest, ManagedResource) { static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {} +TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) { + if (GetParam() != ResourceProvider::Bitmap) + return; + + gfx::Size size(64, 64); + const uint32_t kBadBeef = 0xbadbeef; + scoped_ptr<base::SharedMemory> shared_memory( + CreateAndFillSharedMemory(size, kBadBeef)); + + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::CreateSoftware(make_scoped_ptr( + new SoftwareOutputDevice))); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), 0)); + + TextureMailbox::ReleaseCallback callback = base::Bind(&EmptyReleaseCallback); + TextureMailbox mailbox(shared_memory.get(), size, callback); + + ResourceProvider::ResourceId id = + resource_provider->CreateResourceFromTextureMailbox(mailbox); + EXPECT_NE(0u, id); + + { + ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id); + const SkBitmap* sk_bitmap = lock.sk_bitmap(); + EXPECT_EQ(sk_bitmap->width(), size.width()); + EXPECT_EQ(sk_bitmap->height(), size.height()); + EXPECT_EQ(*sk_bitmap->getAddr32(16, 16), kBadBeef); + } +} + TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) { // Mailboxing is only supported for GL textures. if (GetParam() != ResourceProvider::GLTexture) diff --git a/cc/resources/texture_mailbox.cc b/cc/resources/texture_mailbox.cc index 6900518..0d47874 100644 --- a/cc/resources/texture_mailbox.cc +++ b/cc/resources/texture_mailbox.cc @@ -11,16 +11,18 @@ namespace cc { TextureMailbox::TextureMailbox() : target_(GL_TEXTURE_2D), - sync_point_(0) { + sync_point_(0), + shared_memory_(NULL) { } TextureMailbox::TextureMailbox( const std::string& mailbox_name, - const ReleaseCallback& mailbox_callback) - : callback_(mailbox_callback), + const ReleaseCallback& callback) + : callback_(callback), target_(GL_TEXTURE_2D), - sync_point_(0) { - DCHECK(mailbox_name.empty() == mailbox_callback.is_null()); + sync_point_(0), + shared_memory_(NULL) { + DCHECK(mailbox_name.empty() == callback.is_null()); if (!mailbox_name.empty()) { CHECK(mailbox_name.size() == sizeof(name_.name)); name_.SetName(reinterpret_cast<const int8*>(mailbox_name.data())); @@ -29,50 +31,70 @@ TextureMailbox::TextureMailbox( TextureMailbox::TextureMailbox( const gpu::Mailbox& mailbox_name, - const ReleaseCallback& mailbox_callback) - : callback_(mailbox_callback), + const ReleaseCallback& callback) + : callback_(callback), target_(GL_TEXTURE_2D), - sync_point_(0) { - DCHECK(mailbox_name.IsZero() == mailbox_callback.is_null()); + sync_point_(0), + shared_memory_(NULL) { + DCHECK(mailbox_name.IsZero() == callback.is_null()); name_.SetName(mailbox_name.name); } TextureMailbox::TextureMailbox( const gpu::Mailbox& mailbox_name, - const ReleaseCallback& mailbox_callback, + const ReleaseCallback& callback, unsigned sync_point) - : callback_(mailbox_callback), + : callback_(callback), target_(GL_TEXTURE_2D), - sync_point_(sync_point) { - DCHECK(mailbox_name.IsZero() == mailbox_callback.is_null()); + sync_point_(sync_point), + shared_memory_(NULL) { + DCHECK(mailbox_name.IsZero() == callback.is_null()); name_.SetName(mailbox_name.name); } TextureMailbox::TextureMailbox( const gpu::Mailbox& mailbox_name, - const ReleaseCallback& mailbox_callback, + const ReleaseCallback& callback, unsigned texture_target, unsigned sync_point) - : callback_(mailbox_callback), + : callback_(callback), target_(texture_target), - sync_point_(sync_point) { - DCHECK(mailbox_name.IsZero() == mailbox_callback.is_null()); + sync_point_(sync_point), + shared_memory_(NULL) { + DCHECK(mailbox_name.IsZero() == callback.is_null()); name_.SetName(mailbox_name.name); } -TextureMailbox::~TextureMailbox() { +TextureMailbox::TextureMailbox( + base::SharedMemory* shared_memory, + gfx::Size size, + const ReleaseCallback& callback) + : callback_(callback), + target_(GL_TEXTURE_2D), + sync_point_(0), + shared_memory_(shared_memory), + shared_memory_size_(size) { } -bool TextureMailbox::Equals(const gpu::Mailbox& other) const { - return !memcmp(data(), other.name, sizeof(name_.name)); +TextureMailbox::~TextureMailbox() { } bool TextureMailbox::Equals(const TextureMailbox& other) const { - return Equals(other.name()); + if (other.IsTexture()) + return ContainsMailbox(other.name()); + else if (other.IsSharedMemory()) + return ContainsHandle(other.shared_memory_->handle()); + + DCHECK(!other.IsValid()); + return !IsValid(); } -bool TextureMailbox::IsEmpty() const { - return name_.IsZero(); +bool TextureMailbox::ContainsMailbox(const gpu::Mailbox& other) const { + return IsTexture() && !memcmp(data(), other.name, sizeof(name_.name)); +} + +bool TextureMailbox::ContainsHandle(base::SharedMemoryHandle handle) const { + return shared_memory_ && shared_memory_->handle() == handle; } void TextureMailbox::RunReleaseCallback(unsigned sync_point, @@ -82,7 +104,19 @@ void TextureMailbox::RunReleaseCallback(unsigned sync_point, } void TextureMailbox::SetName(const gpu::Mailbox& other) { + DCHECK(shared_memory_ == NULL); name_.SetName(other.name); } +TextureMailbox TextureMailbox::CopyWithNewCallback( + const ReleaseCallback& callback) const { + TextureMailbox result(*this); + result.callback_ = callback; + return result; +} + +size_t TextureMailbox::shared_memory_size_in_bytes() const { + return 4 * shared_memory_size_.GetArea(); +} + } // namespace cc diff --git a/cc/resources/texture_mailbox.h b/cc/resources/texture_mailbox.h index ff8c184..855287d 100644 --- a/cc/resources/texture_mailbox.h +++ b/cc/resources/texture_mailbox.h @@ -7,13 +7,16 @@ #include <string> -#include "base/basictypes.h" #include "base/callback.h" +#include "base/memory/shared_memory.h" #include "cc/base/cc_export.h" #include "gpu/command_buffer/common/mailbox.h" +#include "ui/gfx/size.h" namespace cc { +// TODO(skaslev, danakj) Rename this class more apropriately since now it +// can hold a shared memory resource as well as a texture mailbox. class CC_EXPORT TextureMailbox { public: typedef base::Callback<void(unsigned sync_point, @@ -30,14 +33,22 @@ class CC_EXPORT TextureMailbox { const ReleaseCallback& callback, unsigned texture_target, unsigned sync_point); + TextureMailbox(base::SharedMemory* shared_memory, + gfx::Size size, + const ReleaseCallback& callback); ~TextureMailbox(); + bool IsValid() const { return IsTexture() || IsSharedMemory(); } + bool IsTexture() const { return !name_.IsZero(); } + bool IsSharedMemory() const { return shared_memory_ != NULL; } + + bool Equals(const TextureMailbox&) const; + bool ContainsMailbox(const gpu::Mailbox&) const; + bool ContainsHandle(base::SharedMemoryHandle handle) const; + const ReleaseCallback& callback() const { return callback_; } const int8* data() const { return name_.name; } - bool Equals(const gpu::Mailbox&) const; - bool Equals(const TextureMailbox&) const; - bool IsEmpty() const; const gpu::Mailbox& name() const { return name_; } void ResetSyncPoint() { sync_point_ = 0; } void RunReleaseCallback(unsigned sync_point, bool lost_resource) const; @@ -45,11 +56,19 @@ class CC_EXPORT TextureMailbox { unsigned target() const { return target_; } unsigned sync_point() const { return sync_point_; } + base::SharedMemory* shared_memory() const { return shared_memory_; } + gfx::Size shared_memory_size() const { return shared_memory_size_; } + size_t shared_memory_size_in_bytes() const; + + TextureMailbox CopyWithNewCallback(const ReleaseCallback& callback) const; + private: gpu::Mailbox name_; ReleaseCallback callback_; unsigned target_; unsigned sync_point_; + base::SharedMemory* shared_memory_; + gfx::Size shared_memory_size_; }; } // namespace cc diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/content/browser/android/in_process/synchronous_compositor_output_surface.cc index b0e2d0e..4000a2c 100644 --- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc +++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc @@ -72,13 +72,6 @@ class SynchronousCompositorOutputSurface::SoftwareDevice virtual void CopyToBitmap(gfx::Rect rect, SkBitmap* output) OVERRIDE { NOTIMPLEMENTED(); } - virtual void Scroll(gfx::Vector2d delta, - gfx::Rect clip_rect) OVERRIDE { - NOTIMPLEMENTED(); - } - virtual void ReclaimDIB(const TransportDIB::Id& id) OVERRIDE { - NOTIMPLEMENTED(); - } private: SynchronousCompositorOutputSurface* surface_; diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 49fcbd9..62fa6cb 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -1715,7 +1715,7 @@ bool RenderWidgetHostImpl::OnSwapCompositorFrame( } else if (frame->delegated_frame_data) { ack.resources.swap(frame->delegated_frame_data->resource_list); } else if (frame->software_frame_data) { - ack.last_dib_id = frame->software_frame_data->dib_id; + ack.last_software_frame_id = frame->software_frame_data->id; } SendSwapCompositorFrameAck(routing_id_, process_->GetID(), ack); } diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index a5daece..4c77599 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -13,6 +13,7 @@ #include "base/string_number_conversions.h" #include "cc/output/compositor_frame.h" #include "cc/output/compositor_frame_ack.h" +#include "cc/resources/texture_mailbox.h" #include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/accessibility/browser_accessibility_state_impl.h" #include "content/browser/renderer_host/backing_store_aura.h" @@ -344,6 +345,12 @@ void AcknowledgeBufferForGpu( route_id, gpu_host_id, ack); } +void ReleaseMailbox(scoped_ptr<base::SharedMemory> shared_memory, + base::Callback<void()> callback, + unsigned sync_point, bool lost_resource) { + callback.Run(); +} + } // namespace // We need to watch for mouse events outside a Web Popup or its parent @@ -941,7 +948,9 @@ bool RenderWidgetHostViewAura::HasFocus() const { } bool RenderWidgetHostViewAura::IsSurfaceAvailableForCopy() const { - return current_surface_ || current_dib_ || !!host_->GetBackingStore(false); + return current_surface_ || + current_software_frame_.IsValid() || + !!host_->GetBackingStore(false); } void RenderWidgetHostViewAura::Show() { @@ -1285,6 +1294,7 @@ void RenderWidgetHostViewAura::CopyFromCompositingSurfaceToVideoFrame( } bool RenderWidgetHostViewAura::CanCopyToVideoFrame() const { + // TODO(skaslev): Implement this path for s/w compositing. return current_surface_ != NULL && host_->is_accelerated_compositing_active(); } @@ -1347,17 +1357,20 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { bool is_compositing_active = host_->is_accelerated_compositing_active(); if (is_compositing_active && current_surface_) { - window_->SetExternalTexture(current_surface_.get()); + window_->layer()->SetExternalTexture(current_surface_.get()); current_frame_size_ = ConvertSizeToDIP( current_surface_->device_scale_factor(), current_surface_->size()); CheckResizeLock(); - } else if (is_compositing_active && current_dib_) { - window_->SetExternalTexture(NULL); - current_frame_size_ = ConvertSizeToDIP(last_swapped_surface_scale_factor_, - last_swapped_surface_size_); + } else if (is_compositing_active && + current_software_frame_.IsSharedMemory()) { + window_->layer()->SetTextureMailbox(current_software_frame_, + last_swapped_surface_scale_factor_); + current_frame_size_ = ConvertSizeToDIP( + last_swapped_surface_scale_factor_, + current_software_frame_.shared_memory_size()); CheckResizeLock(); } else { - window_->SetExternalTexture(NULL); + window_->layer()->SetExternalTexture(NULL); resize_lock_.reset(); host_->WasResized(); } @@ -1522,60 +1535,67 @@ void RenderWidgetHostViewAura::SwapSoftwareFrame( const ui::LatencyInfo& latency_info) { const gfx::Size& frame_size = frame_data->size; const gfx::Rect& damage_rect = frame_data->damage_rect; - const TransportDIB::Id& dib_id = frame_data->dib_id; - scoped_ptr<TransportDIB> dib(host_->GetProcess()->MapTransportDIB(dib_id)); + gfx::Size frame_size_in_dip = + ConvertSizeToDIP(frame_device_scale_factor, frame_size); + if (ShouldSkipFrame(frame_size_in_dip)) { + SendSoftwareFrameAck(frame_data->id); + return; + } - // Validate the received DIB. - size_t expected_size = 4 * frame_size.GetArea(); - if (!dib || dib->size() < expected_size) { + base::SharedMemoryHandle handle = frame_data->handle; +#ifdef OS_WIN + BOOL success = ::DuplicateHandle( + host_->GetProcess()->GetHandle(), frame_data->handle, + ::GetCurrentProcess(), &handle, + 0, TRUE, DUPLICATE_SAME_ACCESS); + if (!success) { + host_->GetProcess()->ReceivedBadMessage(); + return; + } +#endif + const size_t expected_size = 4 * frame_size.GetArea(); + scoped_ptr<base::SharedMemory> shared_memory( + new base::SharedMemory(handle, false)); + if (!shared_memory->Map(expected_size)) { host_->GetProcess()->ReceivedBadMessage(); return; } if (last_swapped_surface_size_ != frame_size) { DLOG_IF(ERROR, damage_rect != gfx::Rect(frame_size)) - << "Expected full damage rect"; + << "Expected full damage rect"; } - - TransportDIB::Id last_dib_id = current_dib_id_; - current_dib_.reset(dib.release()); - current_dib_id_ = dib_id; last_swapped_surface_size_ = frame_size; last_swapped_surface_scale_factor_ = frame_device_scale_factor; - ui::Compositor* compositor = GetCompositor(); - if (!compositor) { - SendSoftwareFrameAck(last_dib_id); - return; - } - - gfx::Size frame_size_in_dip = - ConvertSizeToDIP(frame_device_scale_factor, frame_size); - if (ShouldSkipFrame(frame_size_in_dip)) { - can_lock_compositor_ = NO_PENDING_COMMIT; - SendSoftwareFrameAck(last_dib_id); - } else { - AddOnCommitCallbackAndDisableLocks( - base::Bind(&RenderWidgetHostViewAura::SendSoftwareFrameAck, - AsWeakPtr(), last_dib_id)); - } - + base::SharedMemory* shared_memory_raw_ptr = shared_memory.get(); + cc::TextureMailbox::ReleaseCallback callback = + base::Bind(ReleaseMailbox, Passed(&shared_memory), + base::Bind(&RenderWidgetHostViewAura::SendSoftwareFrameAck, + AsWeakPtr(), frame_data->id)); + current_software_frame_ = + cc::TextureMailbox(shared_memory_raw_ptr, frame_size, callback); + DCHECK(current_software_frame_.IsSharedMemory()); current_frame_size_ = frame_size_in_dip; - CheckResizeLock(); + released_front_lock_ = NULL; - window_->SetExternalTexture(NULL); + CheckResizeLock(); + window_->layer()->SetTextureMailbox(current_software_frame_, + frame_device_scale_factor); window_->SchedulePaintInRect( ConvertRectToDIP(frame_device_scale_factor, damage_rect)); - compositor->SetLatencyInfo(latency_info); + ui::Compositor* compositor = GetCompositor(); + if (compositor) + compositor->SetLatencyInfo(latency_info); if (paint_observer_) paint_observer_->OnUpdateCompositorContent(); } void RenderWidgetHostViewAura::SendSoftwareFrameAck( - const TransportDIB::Id& id) { + unsigned software_frame_id) { cc::CompositorFrameAck ack; - ack.last_dib_id = id; + ack.last_software_frame_id = software_frame_id; RenderWidgetHostImpl::SendSwapCompositorFrameAck( host_->GetRoutingID(), host_->GetProcess()->GetID(), ack); } @@ -2192,36 +2212,8 @@ void RenderWidgetHostViewAura::OnCaptureLost() { } void RenderWidgetHostViewAura::OnPaint(gfx::Canvas* canvas) { - bool is_compositing_active = host_->is_accelerated_compositing_active(); bool has_backing_store = !!host_->GetBackingStore(false); - if (is_compositing_active && current_dib_) { - const gfx::Size window_size = window_->bounds().size(); - const gfx::Size& frame_size = last_swapped_surface_size_; - - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, - frame_size.width(), - frame_size.height()); - bitmap.setPixels(current_dib_->memory()); - - SkCanvas* sk_canvas = canvas->sk_canvas(); - sk_canvas->drawBitmap(bitmap, 0, 0); - - if (frame_size != window_size) { - SkRegion region; - region.op(0, 0, window_size.width(), window_size.height(), - SkRegion::kUnion_Op); - region.op(0, 0, frame_size.width(), frame_size.height(), - SkRegion::kDifference_Op); - SkPaint paint; - paint.setColor(SK_ColorWHITE); - for (SkRegion::Iterator it(region); !it.done(); it.next()) - sk_canvas->drawIRect(it.rect(), paint); - } - - if (paint_observer_) - paint_observer_->OnPaintComplete(); - } else if (!is_compositing_active && has_backing_store) { + if (has_backing_store) { paint_canvas_ = canvas; BackingStoreAura* backing_store = static_cast<BackingStoreAura*>( host_->GetBackingStore(true)); diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 0ed95a0..58e5d08 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -15,6 +15,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "cc/resources/texture_mailbox.h" #include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/renderer_host/image_transport_factory.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" @@ -484,7 +485,7 @@ class RenderWidgetHostViewAura scoped_ptr<cc::SoftwareFrameData> frame_data, float frame_device_scale_factor, const ui::LatencyInfo& latency_info); - void SendSoftwareFrameAck(const TransportDIB::Id& id); + void SendSoftwareFrameAck(unsigned software_frame_id); BrowserAccessibilityManager* GetOrCreateBrowserAccessibilityManager(); @@ -562,12 +563,8 @@ class RenderWidgetHostViewAura // The current frontbuffer texture. scoped_refptr<ui::Texture> current_surface_; - // The current frontbuffer DIB. - scoped_ptr<TransportDIB> current_dib_; - - // The current DIB id as it was received from the renderer. Note that on - // some platforms (e.g. Windows) this is different from current_dib_->id(). - TransportDIB::Id current_dib_id_; + // The current software frontbuffer. + cc::TextureMailbox current_software_frame_; // The damage in the previously presented buffer. SkRegion previous_damage_; diff --git a/content/common/cc_messages.cc b/content/common/cc_messages.cc index aadac97..43b6ce1 100644 --- a/content/common/cc_messages.cc +++ b/content/common/cc_messages.cc @@ -626,7 +626,7 @@ void ParamTraits<cc::CompositorFrame>::Log(const param_type& p, void ParamTraits<cc::CompositorFrameAck>::Write(Message* m, const param_type& p) { WriteParam(m, p.resources); - WriteParam(m, p.last_dib_id); + WriteParam(m, p.last_software_frame_id); if (p.gl_frame_data) { WriteParam(m, static_cast<int>(GL_FRAME)); WriteParam(m, *p.gl_frame_data); @@ -641,7 +641,7 @@ bool ParamTraits<cc::CompositorFrameAck>::Read(const Message* m, if (!ReadParam(m, iter, &p->resources)) return false; - if (!ReadParam(m, iter, &p->last_dib_id)) + if (!ReadParam(m, iter, &p->last_software_frame_id)) return false; int compositor_frame_type; @@ -667,7 +667,7 @@ void ParamTraits<cc::CompositorFrameAck>::Log(const param_type& p, l->append("CompositorFrameAck("); LogParam(p.resources, l); l->append(", "); - LogParam(p.last_dib_id, l); + LogParam(p.last_software_frame_id, l); l->append(", "); if (p.gl_frame_data) LogParam(*p.gl_frame_data, l); diff --git a/content/common/cc_messages.h b/content/common/cc_messages.h index f09c9f2..4986dd3 100644 --- a/content/common/cc_messages.h +++ b/content/common/cc_messages.h @@ -233,7 +233,8 @@ IPC_STRUCT_TRAITS_BEGIN(cc::GLFrameData) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(cc::SoftwareFrameData) + IPC_STRUCT_TRAITS_MEMBER(id) IPC_STRUCT_TRAITS_MEMBER(size) IPC_STRUCT_TRAITS_MEMBER(damage_rect) - IPC_STRUCT_TRAITS_MEMBER(dib_id) + IPC_STRUCT_TRAITS_MEMBER(handle) IPC_STRUCT_TRAITS_END() diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h index dc1c4ac..a99024d 100644 --- a/content/common/gpu/gpu_command_buffer_stub.h +++ b/content/common/gpu/gpu_command_buffer_stub.h @@ -29,7 +29,6 @@ #include "ui/gfx/size.h" #include "ui/gl/gl_surface.h" #include "ui/gl/gpu_preference.h" -#include "ui/surface/transport_dib.h" namespace gpu { struct Mailbox; diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h index 95de041..763e657 100644 --- a/content/common/gpu/gpu_messages.h +++ b/content/common/gpu/gpu_messages.h @@ -28,7 +28,6 @@ #include "ui/gfx/native_widget_types.h" #include "ui/gfx/size.h" #include "ui/gl/gpu_preference.h" -#include "ui/surface/transport_dib.h" #if defined(OS_ANDROID) #include "content/common/android/surface_texture_peer.h" diff --git a/content/common/gpu/image_transport_surface.h b/content/common/gpu/image_transport_surface.h index 4de68a4..7b2d11d 100644 --- a/content/common/gpu/image_transport_surface.h +++ b/content/common/gpu/image_transport_surface.h @@ -20,7 +20,6 @@ #include "ui/gfx/rect.h" #include "ui/gfx/size.h" #include "ui/gl/gl_surface.h" -#include "ui/surface/transport_dib.h" struct AcceleratedSurfaceMsg_BufferPresented_Params; struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params; diff --git a/content/renderer/gpu/compositor_software_output_device.cc b/content/renderer/gpu/compositor_software_output_device.cc index cd22bed..23710ab 100644 --- a/content/renderer/gpu/compositor_software_output_device.cc +++ b/content/renderer/gpu/compositor_software_output_device.cc @@ -10,27 +10,56 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkDevice.h" #include "third_party/skia/include/core/SkPixelRef.h" +#include "third_party/skia/include/core/SkRegion.h" #include "ui/gfx/skia_util.h" -#include "ui/surface/transport_dib.h" namespace content { -CompositorSoftwareOutputDevice::DIB::DIB(size_t size) { - RenderProcess* render_process = RenderProcess::current(); - dib_ = render_process->CreateTransportDIB(size); - CHECK(dib_); - bool success = dib_->Map(); - CHECK(success); +CompositorSoftwareOutputDevice::Buffer::Buffer( + unsigned id, scoped_ptr<base::SharedMemory> mem) + : id_(id), + mem_(mem.Pass()), + free_(true), + parent_(NULL) { +} + +CompositorSoftwareOutputDevice::Buffer::~Buffer() { } -CompositorSoftwareOutputDevice::DIB::~DIB() { - RenderProcess* render_process = RenderProcess::current(); - render_process->FreeTransportDIB(dib_); +void CompositorSoftwareOutputDevice::Buffer::SetParent( + Buffer* parent, const gfx::Rect& damage) { + parent_ = parent; + damage_ = damage; +} + +bool CompositorSoftwareOutputDevice::Buffer::FindDamageDifferenceFrom( + Buffer* buffer, SkRegion* result) const { + if (!buffer) + return false; + + if (buffer == this) { + *result = SkRegion(); + return true; + } + + SkRegion damage; + const Buffer* current = this; + while (current->parent_) { + damage.op(RectToSkIRect(current->damage_), SkRegion::kUnion_Op); + if (current->parent_ == buffer) { + *result = damage; + return true; + } + current = current->parent_; + } + + return false; } CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice() - : front_buffer_(-1), - num_free_buffers_(0) { + : current_index_(-1), + next_buffer_id_(1), + render_thread_(RenderThread::Get()) { DetachFromThread(); } @@ -38,10 +67,34 @@ CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() { DCHECK(CalledOnValidThread()); } -CompositorSoftwareOutputDevice::DIB* -CompositorSoftwareOutputDevice::CreateDIB() { - const size_t size = 4 * viewport_size_.GetArea(); - return new DIB(size); +unsigned CompositorSoftwareOutputDevice::GetNextId() { + unsigned id = next_buffer_id_++; + // Zero is reserved to label invalid frame id. + if (id == 0) + id = next_buffer_id_++; + return id; +} + +CompositorSoftwareOutputDevice::Buffer* +CompositorSoftwareOutputDevice::CreateBuffer() { + const size_t size = 4 * viewport_size_.GetArea(); + scoped_ptr<base::SharedMemory> mem = + render_thread_->HostAllocateSharedMemoryBuffer(size).Pass(); + CHECK(mem); + bool success = mem->Map(size); + CHECK(success); + return new Buffer(GetNextId(), mem.Pass()); +} + +size_t CompositorSoftwareOutputDevice::FindFreeBuffer(size_t hint) { + for (size_t i = 0; i < buffers_.size(); ++i) { + size_t index = (hint + i) % buffers_.size(); + if (buffers_[index]->free()) + return index; + } + + buffers_.push_back(CreateBuffer()); + return buffers_.size() - 1; } void CompositorSoftwareOutputDevice::Resize(gfx::Size viewport_size) { @@ -50,66 +103,76 @@ void CompositorSoftwareOutputDevice::Resize(gfx::Size viewport_size) { if (viewport_size_ == viewport_size) return; - // Keep non-ACKed dibs open. - int first_non_free = front_buffer_ + num_free_buffers_ + 1; - int num_non_free = dibs_.size() - num_free_buffers_; - for (int i = 0; i < num_non_free; ++i) { - int index = (first_non_free + i) % dibs_.size(); - awaiting_ack_.push_back(dibs_[index]); - dibs_[index] = NULL; + // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged. + for (size_t i = 0; i < buffers_.size(); ++i) { + if (!buffers_[i]->free()) { + awaiting_ack_.push_back(buffers_[i]); + buffers_[i] = NULL; + } } - dibs_.clear(); - front_buffer_ = -1; - num_free_buffers_ = 0; + buffers_.clear(); + current_index_ = -1; viewport_size_ = viewport_size; } SkCanvas* CompositorSoftwareOutputDevice::BeginPaint(gfx::Rect damage_rect) { DCHECK(CalledOnValidThread()); - gfx::Rect last_damage_rect = damage_rect_; - damage_rect_ = damage_rect; - - int last_buffer = front_buffer_; - if (num_free_buffers_ == 0) { - dibs_.insert(dibs_.begin() + (front_buffer_ + 1), CreateDIB()); - last_damage_rect = gfx::Rect(viewport_size_); - } else { - --num_free_buffers_; - } - front_buffer_ = (front_buffer_ + 1) % dibs_.size(); - - TransportDIB* front_dib = dibs_[front_buffer_]->dib(); - DCHECK(front_dib); - DCHECK(front_dib->memory()); + Buffer* previous = NULL; + if (current_index_ != size_t(-1)) + previous = buffers_[current_index_]; + current_index_ = FindFreeBuffer(current_index_ + 1); + Buffer* current = buffers_[current_index_]; + DCHECK(current->free()); + current->SetFree(false); // Set up a canvas for the current front buffer. bitmap_.setConfig(SkBitmap::kARGB_8888_Config, viewport_size_.width(), viewport_size_.height()); - bitmap_.setPixels(front_dib->memory()); + bitmap_.setPixels(current->memory()); device_ = skia::AdoptRef(new SkDevice(bitmap_)); canvas_ = skia::AdoptRef(new SkCanvas(device_.get())); - // Copy over previous damage. - if (last_buffer != -1) { - TransportDIB* last_dib = dibs_[last_buffer]->dib(); - SkBitmap back_bitmap; - back_bitmap.setConfig(SkBitmap::kARGB_8888_Config, - viewport_size_.width(), - viewport_size_.height()); - back_bitmap.setPixels(last_dib->memory()); - - SkRegion region(RectToSkIRect(last_damage_rect)); + if (!previous) { + DCHECK(damage_rect == gfx::Rect(viewport_size_)); + } else { + // Find the smallest damage region that needs + // to be copied from the |previous| buffer. + SkRegion region; + bool found = + current->FindDamageDifferenceFrom(previous, ®ion) || + previous->FindDamageDifferenceFrom(current, ®ion); + if (!found) + region = SkRegion(RectToSkIRect(gfx::Rect(viewport_size_))); region.op(RectToSkIRect(damage_rect), SkRegion::kDifference_Op); - for (SkRegion::Iterator it(region); !it.done(); it.next()) { - const SkIRect& src_rect = it.rect(); - SkRect dst_rect = SkRect::Make(src_rect); - canvas_->drawBitmapRect(back_bitmap, &src_rect, dst_rect, NULL); + + // Copy over the damage region. + if (!region.isEmpty()) { + SkBitmap back_bitmap; + back_bitmap.setConfig(SkBitmap::kARGB_8888_Config, + viewport_size_.width(), + viewport_size_.height()); + back_bitmap.setPixels(previous->memory()); + + for (SkRegion::Iterator it(region); !it.done(); it.next()) { + const SkIRect& src_rect = it.rect(); + SkRect dst_rect = SkRect::Make(src_rect); + canvas_->drawBitmapRect(back_bitmap, &src_rect, dst_rect, NULL); + } } } + // Make |current| child of |previous| and orphan all of |current|'s children. + current->SetParent(previous, damage_rect); + for (size_t i = 0; i < buffers_.size(); ++i) { + Buffer* buffer = buffers_[i]; + if (buffer->parent() == current) + buffer->SetParent(NULL, gfx::Rect(viewport_size_)); + } + damage_rect_ = damage_rect; + return canvas_.get(); } @@ -118,25 +181,27 @@ void CompositorSoftwareOutputDevice::EndPaint( DCHECK(CalledOnValidThread()); if (frame_data) { + Buffer* buffer = buffers_[current_index_]; + frame_data->id = buffer->id(); frame_data->size = viewport_size_; frame_data->damage_rect = damage_rect_; - frame_data->dib_id = dibs_[front_buffer_]->dib()->id(); + frame_data->handle = buffer->handle(); } } -void CompositorSoftwareOutputDevice::ReclaimDIB(const TransportDIB::Id& id) { +void CompositorSoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) { DCHECK(CalledOnValidThread()); - if (!TransportDIB::is_valid_id(id)) + if (!id) return; - // The reclaimed dib id might not be among the currently - // active dibs if we got a resize event in the mean time. - ScopedVector<DIB>::iterator it = - std::find_if(dibs_.begin(), dibs_.end(), CompareById(id)); - if (it != dibs_.end()) { - ++num_free_buffers_; - DCHECK_LE(static_cast<size_t>(num_free_buffers_), dibs_.size()); + // The reclaimed buffer id might not be among the currently + // active buffers if we got a resize event in the mean time. + ScopedVector<Buffer>::iterator it = + std::find_if(buffers_.begin(), buffers_.end(), CompareById(id)); + if (it != buffers_.end()) { + DCHECK(!(*it)->free()); + (*it)->SetFree(true); return; } else { it = std::find_if(awaiting_ack_.begin(), awaiting_ack_.end(), diff --git a/content/renderer/gpu/compositor_software_output_device.h b/content/renderer/gpu/compositor_software_output_device.h index b82ffe2..49b90c2 100644 --- a/content/renderer/gpu/compositor_software_output_device.h +++ b/content/renderer/gpu/compositor_software_output_device.h @@ -5,11 +5,16 @@ #ifndef CONTENT_RENDERER_GPU_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_H_ #define CONTENT_RENDERER_GPU_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_H_ +#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" +#include "base/memory/shared_memory.h" #include "base/threading/non_thread_safe.h" #include "cc/output/software_output_device.h" +#include "content/public/renderer/render_thread.h" #include "third_party/skia/include/core/SkBitmap.h" +class SkRegion; + namespace content { // This class can be created only on the main thread, but then becomes pinned @@ -26,43 +31,63 @@ public: virtual SkCanvas* BeginPaint(gfx::Rect damage_rect) OVERRIDE; virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE; - virtual void ReclaimDIB(const TransportDIB::Id& id) OVERRIDE; + virtual void ReclaimSoftwareFrame(unsigned id) OVERRIDE; private: - class DIB { + // Internal buffer class that manages shared memory lifetime and ownership. + // It also tracks buffers' history so we can calculate what's the minimum + // damage rect difference between any two given buffers (see SetParent and + // FindDamageDifferenceFrom). + class Buffer { public: - explicit DIB(size_t size); - ~DIB(); + explicit Buffer(unsigned id, scoped_ptr<base::SharedMemory> mem); + ~Buffer(); - TransportDIB* dib() const { - return dib_; - } + unsigned id() const { return id_; } + + void* memory() const { return mem_->memory(); } + base::SharedMemoryHandle handle() const { return mem_->handle(); } + + bool free() const { return free_; } + void SetFree(bool free) { free_ = free; } + + Buffer* parent() const { return parent_; } + void SetParent(Buffer* parent, const gfx::Rect& damage); + + bool FindDamageDifferenceFrom(Buffer* buffer, SkRegion* result) const; private: - TransportDIB* dib_; + const unsigned id_; + scoped_ptr<base::SharedMemory> mem_; + bool free_; + Buffer* parent_; + gfx::Rect damage_; - DISALLOW_COPY_AND_ASSIGN(DIB); + DISALLOW_COPY_AND_ASSIGN(Buffer); }; class CompareById { public: - CompareById(const TransportDIB::Id& id) : id_(id) {} + CompareById(unsigned id) : id_(id) {} - bool operator()(const DIB* dib) const { - return dib->dib() && dib->dib()->id() == id_; + bool operator()(const Buffer* buffer) const { + return buffer->id() == id_; } private: - TransportDIB::Id id_; + const unsigned id_; }; - DIB* CreateDIB(); + unsigned GetNextId(); + Buffer* CreateBuffer(); + size_t FindFreeBuffer(size_t hint); - int front_buffer_; - int num_free_buffers_; - ScopedVector<DIB> dibs_; - ScopedVector<DIB> awaiting_ack_; + size_t current_index_; + unsigned next_buffer_id_; + ScopedVector<Buffer> buffers_; + ScopedVector<Buffer> awaiting_ack_; SkBitmap bitmap_; + RenderThread* render_thread_; }; } // namespace content diff --git a/gpu/command_buffer/common/mailbox.cc b/gpu/command_buffer/common/mailbox.cc index 653d1d664..be2bebf 100644 --- a/gpu/command_buffer/common/mailbox.cc +++ b/gpu/command_buffer/common/mailbox.cc @@ -22,6 +22,10 @@ bool Mailbox::IsZero() const { return true; } +void Mailbox::SetZero() { + memset(name, 0, sizeof(name)); +} + void Mailbox::SetName(const int8* n) { GPU_DCHECK(IsZero() || !memcmp(name, n, sizeof(name))); memcpy(name, n, sizeof(name)); diff --git a/gpu/command_buffer/common/mailbox.h b/gpu/command_buffer/common/mailbox.h index ca24a71..d0e4c2c 100644 --- a/gpu/command_buffer/common/mailbox.h +++ b/gpu/command_buffer/common/mailbox.h @@ -13,6 +13,7 @@ namespace gpu { struct GPU_EXPORT Mailbox { Mailbox(); bool IsZero() const; + void SetZero(); void SetName(const int8* name); int8 name[64]; }; diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp index 43d2d9e..7915d09 100644 --- a/ui/aura/aura.gyp +++ b/ui/aura/aura.gyp @@ -14,6 +14,8 @@ '../../base/base.gyp:base', '../../base/base.gyp:base_i18n', '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + '../../cc/cc.gyp:cc', + '../../gpu/gpu.gyp:gpu', '../../skia/skia.gyp:skia', '../compositor/compositor.gyp:compositor', '../ui.gyp:ui', diff --git a/ui/aura/window.cc b/ui/aura/window.cc index 5160bf6..dac1405 100644 --- a/ui/aura/window.cc +++ b/ui/aura/window.cc @@ -34,6 +34,15 @@ namespace aura { +namespace { + +void MailboxReleaseCallback(scoped_ptr<base::SharedMemory> shared_memory, + unsigned sync_point, bool lost_resource) { + // NOTE: shared_memory will get released when we go out of scope. +} + +} // namespace + Window::Window(WindowDelegate* delegate) : type_(client::WINDOW_TYPE_UNKNOWN), owned_by_parent_(true), @@ -145,6 +154,9 @@ ui::Layer* Window::RecreateLayer() { return NULL; old_layer->set_delegate(NULL); + float mailbox_scale_factor; + cc::TextureMailbox old_mailbox = + old_layer->GetTextureMailbox(&mailbox_scale_factor); scoped_refptr<ui::Texture> old_texture = old_layer->external_texture(); if (delegate_ && old_texture) old_layer->SetExternalTexture(delegate_->CopyTexture()); @@ -158,8 +170,26 @@ ui::Layer* Window::RecreateLayer() { // Move the original texture to the new layer if the old layer has a // texture and we could copy it into the old layer, // crbug.com/175211. - if (delegate_ && old_texture) + if (delegate_ && old_texture) { layer_->SetExternalTexture(old_texture); + } else if (old_mailbox.IsSharedMemory()) { + base::SharedMemory* old_buffer = old_mailbox.shared_memory(); + const size_t size = old_mailbox.shared_memory_size_in_bytes(); + + scoped_ptr<base::SharedMemory> new_buffer(new base::SharedMemory); + new_buffer->CreateAndMapAnonymous(size); + + if (old_buffer->memory() && new_buffer->memory()) { + memcpy(new_buffer->memory(), old_buffer->memory(), size); + base::SharedMemory* new_buffer_raw_ptr = new_buffer.get(); + cc::TextureMailbox::ReleaseCallback callback = + base::Bind(MailboxReleaseCallback, Passed(&new_buffer)); + cc::TextureMailbox new_mailbox(new_buffer_raw_ptr, + old_mailbox.shared_memory_size(), + callback); + layer_->SetTextureMailbox(new_mailbox, mailbox_scale_factor); + } + } UpdateLayerName(name_); layer_->SetFillsBoundsOpaquely(!transparent_); @@ -313,10 +343,6 @@ void Window::SchedulePaintInRect(const gfx::Rect& rect) { } } -void Window::SetExternalTexture(ui::Texture* texture) { - layer_->SetExternalTexture(texture); -} - void Window::SetDefaultParentByRootWindow(RootWindow* root_window, const gfx::Rect& bounds_in_screen) { DCHECK(root_window); diff --git a/ui/aura/window.h b/ui/aura/window.h index a73f784..cbc700d 100644 --- a/ui/aura/window.h +++ b/ui/aura/window.h @@ -157,9 +157,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Marks the a portion of window as needing to be painted. void SchedulePaintInRect(const gfx::Rect& rect); - // Assigns a new external texture to the window's layer. - void SetExternalTexture(ui::Texture* texture); - // Places this window per |root_window|'s stacking client. The final location // may be a RootWindow other than the one passed in. |root_window| may not be // NULL. |bounds_in_screen| may be empty; it is more optional context that diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index a2f0a95..3949402 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc @@ -86,6 +86,7 @@ Layer::Layer(LayerType type) zoom_(1), zoom_inset_(0), delegate_(NULL), + cc_layer_(NULL), scale_content_(true), device_scale_factor_(1.0f) { CreateWebLayer(); @@ -514,6 +515,32 @@ void Layer::SetExternalTexture(Texture* texture) { RecomputeDrawsContentAndUVRect(); } +void Layer::SetTextureMailbox(const cc::TextureMailbox& mailbox, + float scale_factor) { + DCHECK_EQ(type_, LAYER_TEXTURED); + DCHECK(!solid_color_layer_); + layer_updated_externally_ = true; + texture_ = NULL; + if (!texture_layer_ || !texture_layer_->uses_mailbox()) { + scoped_refptr<cc::TextureLayer> new_layer = + cc::TextureLayer::CreateForMailbox(this); + new_layer->SetFlipped(false); + SwitchToLayer(new_layer); + texture_layer_ = new_layer; + } + texture_layer_->SetTextureMailbox(mailbox); + mailbox_ = mailbox; + mailbox_scale_factor_ = scale_factor; + RecomputeDrawsContentAndUVRect(); +} + +cc::TextureMailbox Layer::GetTextureMailbox(float* scale_factor) { + if (scale_factor) + *scale_factor = mailbox_scale_factor_; + cc::TextureMailbox::ReleaseCallback callback; + return mailbox_.CopyWithNewCallback(callback); +} + void Layer::SetDelegatedFrame(scoped_ptr<cc::DelegatedFrameData> frame, gfx::Size frame_size_in_dip) { DCHECK_EQ(type_, LAYER_TEXTURED); @@ -640,7 +667,9 @@ unsigned Layer::PrepareTexture(cc::ResourceUpdateQueue* queue) { WebKit::WebGraphicsContext3D* Layer::Context3d() { DCHECK(texture_layer_.get()); - return texture_->HostContext3D(); + if (texture_) + return texture_->HostContext3D(); + return NULL; } bool Layer::PrepareTextureMailbox(cc::TextureMailbox* mailbox) { @@ -918,11 +947,18 @@ void Layer::RecomputeDrawsContentAndUVRect() { DCHECK(cc_layer_); gfx::Size size(bounds_.size()); if (texture_layer_.get()) { - DCHECK(texture_.get()); - - float texture_scale_factor = 1.0f / texture_->device_scale_factor(); - gfx::Size texture_size = gfx::ToFlooredSize( - gfx::ScaleSize(texture_->size(), texture_scale_factor)); + gfx::Size texture_size; + if (!texture_layer_->uses_mailbox()) { + DCHECK(texture_); + float texture_scale_factor = 1.0f / texture_->device_scale_factor(); + texture_size = gfx::ToFlooredSize( + gfx::ScaleSize(texture_->size(), texture_scale_factor)); + } else { + DCHECK(mailbox_.IsSharedMemory()); + float texture_scale_factor = 1.0f / mailbox_scale_factor_; + texture_size = gfx::ToFlooredSize( + gfx::ScaleSize(mailbox_.shared_memory_size(), texture_scale_factor)); + } size.SetToMin(texture_size); gfx::PointF uv_top_left(0.f, 0.f); diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h index a5afd6b..1159d0b 100644 --- a/ui/compositor/layer.h +++ b/ui/compositor/layer.h @@ -17,6 +17,7 @@ #include "cc/base/scoped_ptr_vector.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/texture_layer_client.h" +#include "cc/resources/texture_mailbox.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/compositor/compositor.h" @@ -250,6 +251,11 @@ class COMPOSITOR_EXPORT Layer void SetExternalTexture(ui::Texture* texture); ui::Texture* external_texture() { return texture_.get(); } + // Set new TextureMailbox for this layer. Note that |mailbox| may hold a + // shared memory resource or an actual mailbox for a texture. + void SetTextureMailbox(const cc::TextureMailbox& mailbox, float scale_factor); + cc::TextureMailbox GetTextureMailbox(float* scale_factor); + // Sets a delegated frame, coming from a child compositor. void SetDelegatedFrame(scoped_ptr<cc::DelegatedFrameData> frame, gfx::Size frame_size_in_dip); @@ -465,6 +471,12 @@ class COMPOSITOR_EXPORT Layer // A cached copy of |Compositor::device_scale_factor()|. float device_scale_factor_; + // A cached copy of the TextureMailbox given texture_layer_. + cc::TextureMailbox mailbox_; + + // Device scale factor in which mailbox_ was rendered in. + float mailbox_scale_factor_; + // The size of the delegated frame in DIP, set when SetDelegatedFrame was // called. gfx::Size delegated_frame_size_in_dip_; |