diff options
Diffstat (limited to 'gpu')
17 files changed, 370 insertions, 100 deletions
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate.h b/gpu/command_buffer/service/async_pixel_transfer_delegate.h index b21a63b..f90e2af 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_delegate.h +++ b/gpu/command_buffer/service/async_pixel_transfer_delegate.h @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "base/callback.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/synchronization/lock.h" @@ -74,18 +75,20 @@ class AsyncPixelTransferUploadStats // AsyncPixelTransferState holds the resources required to do async // transfers on one texture. It should stay alive for the lifetime // of the texture to allow multiple transfers. -class GPU_EXPORT AsyncPixelTransferState : - public base::SupportsWeakPtr<AsyncPixelTransferState> { +class GPU_EXPORT AsyncPixelTransferState + : public base::RefCounted<AsyncPixelTransferState>, + public base::SupportsWeakPtr<AsyncPixelTransferState> { public: - virtual ~AsyncPixelTransferState(); - // Returns true if there is a transfer in progress. virtual bool TransferIsInProgress() = 0; protected: AsyncPixelTransferState(); + virtual ~AsyncPixelTransferState(); private: + friend class base::RefCounted<AsyncPixelTransferState>; + DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferState); }; diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.cc index c56f72a..246acb4 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.cc +++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.cc @@ -393,7 +393,6 @@ class AsyncTransferStateImpl : public AsyncPixelTransferState { wait_for_creation, use_image_preserved)) { } - virtual ~AsyncTransferStateImpl() {} virtual bool TransferIsInProgress() OVERRIDE { return internal_->TransferIsInProgress(); @@ -404,6 +403,9 @@ class AsyncTransferStateImpl : public AsyncPixelTransferState { } scoped_refptr<TransferStateInternal> internal_; + + private: + virtual ~AsyncTransferStateImpl() {} }; } // namespace diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.cc index f4a3e48..d8bf916 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.cc +++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.cc @@ -32,7 +32,6 @@ class AsyncPixelTransferStateImpl : public AsyncPixelTransferState { texture_id_(texture_id), transfer_in_progress_(false) { } - virtual ~AsyncPixelTransferStateImpl() {} // Implement AsyncPixelTransferState: virtual bool TransferIsInProgress() OVERRIDE { @@ -53,6 +52,8 @@ class AsyncPixelTransferStateImpl : public AsyncPixelTransferState { } private: + virtual ~AsyncPixelTransferStateImpl() {} + uint64 id_; GLuint texture_id_; bool transfer_in_progress_; diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc index 2affd24..17d2b65 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc +++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc @@ -10,6 +10,7 @@ MockAsyncPixelTransferState::MockAsyncPixelTransferState() { } MockAsyncPixelTransferState::~MockAsyncPixelTransferState() { + Destroy(); } MockAsyncPixelTransferDelegate::MockAsyncPixelTransferDelegate() { diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h index 146eaa4..f16934c 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h +++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h @@ -15,6 +15,9 @@ class MockAsyncPixelTransferState : public AsyncPixelTransferState { public: MockAsyncPixelTransferState(); + // Called in ~MockAsyncPixelTransferState. + MOCK_METHOD0(Destroy, void()); + // Implement AsyncPixelTransferState. MOCK_METHOD0(TransferIsInProgress, bool()); MOCK_METHOD1(BindTransfer, void(AsyncTexImage2DParams* level_params)); diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_share_group.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_share_group.cc index a71bd66..7a9c1a9 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_delegate_share_group.cc +++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_share_group.cc @@ -305,12 +305,6 @@ class AsyncTransferStateImpl : public AsyncPixelTransferState { const AsyncTexImage2DParams& define_params) : internal_(new TransferStateInternal(texture_id, define_params)) {} - virtual ~AsyncTransferStateImpl() { - TRACE_EVENT0("gpu", " ~AsyncTransferStateImpl"); - base::AutoLock locked(*internal_->upload_lock()); - internal_->cancel_upload_flag()->Set(); - } - virtual bool TransferIsInProgress() OVERRIDE { return internal_->TransferIsInProgress(); } @@ -318,6 +312,12 @@ class AsyncTransferStateImpl : public AsyncPixelTransferState { TransferStateInternal* internal() { return internal_.get(); } private: + virtual ~AsyncTransferStateImpl() { + TRACE_EVENT0("gpu", " ~AsyncTransferStateImpl"); + base::AutoLock locked(*internal_->upload_lock()); + internal_->cancel_upload_flag()->Set(); + } + scoped_refptr<TransferStateInternal> internal_; }; diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.cc index 474e245..5bd7db9 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.cc +++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.cc @@ -11,12 +11,14 @@ namespace { class AsyncPixelTransferStateImpl : public AsyncPixelTransferState { public: AsyncPixelTransferStateImpl() {} - virtual ~AsyncPixelTransferStateImpl() {} // Implement AsyncPixelTransferState: virtual bool TransferIsInProgress() OVERRIDE { return false; } + + private: + virtual ~AsyncPixelTransferStateImpl() {} }; } // namespace diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.cc index dd132a6..6eb58f2 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.cc +++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.cc @@ -11,12 +11,14 @@ namespace { class AsyncPixelTransferStateImpl : public AsyncPixelTransferState { public: AsyncPixelTransferStateImpl() {} - virtual ~AsyncPixelTransferStateImpl() {} // Implement AsyncPixelTransferState: virtual bool TransferIsInProgress() OVERRIDE { return false; } + + private: + virtual ~AsyncPixelTransferStateImpl() {} }; } // namespace diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager.cc b/gpu/command_buffer/service/async_pixel_transfer_manager.cc new file mode 100644 index 0000000..92ecfd6 --- /dev/null +++ b/gpu/command_buffer/service/async_pixel_transfer_manager.cc @@ -0,0 +1,72 @@ +// Copyright 2013 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 "gpu/command_buffer/service/async_pixel_transfer_manager.h" + +#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h" + +namespace gpu { + +AsyncPixelTransferManager::AsyncPixelTransferManager( + gles2::TextureManager* manager, + gfx::GLContext* context) + : manager_(manager), + delegate_(AsyncPixelTransferDelegate::Create(context)) { + manager_->AddObserver(this); +} + +AsyncPixelTransferManager::~AsyncPixelTransferManager() { + if (manager_) + manager_->RemoveObserver(this); +} + +AsyncPixelTransferState* AsyncPixelTransferManager::CreatePixelTransferState( + gles2::TextureRef* ref, + const AsyncTexImage2DParams& define_params) { + DCHECK(!GetPixelTransferState(ref)); + AsyncPixelTransferState* state = delegate_->CreatePixelTransferState( + ref->texture()->service_id(), define_params); + state_map_[ref] = state; + return state; +} + +AsyncPixelTransferState* +AsyncPixelTransferManager::GetPixelTransferState( + gles2::TextureRef* ref) { + TextureToStateMap::iterator it = state_map_.find(ref); + if (it == state_map_.end()) { + return NULL; + } else { + return it->second; + } +} + +void AsyncPixelTransferManager::ClearPixelTransferStateForTest( + gles2::TextureRef* ref) { + TextureToStateMap::iterator it = state_map_.find(ref); + if (it != state_map_.end()) + state_map_.erase(it); +} + +bool AsyncPixelTransferManager::AsyncTransferIsInProgress( + gles2::TextureRef* ref) { + AsyncPixelTransferState* state = GetPixelTransferState(ref); + return state && state->TransferIsInProgress(); +} + +void AsyncPixelTransferManager::OnTextureManagerDestroying( + gles2::TextureManager* manager) { + // TextureManager should outlive AsyncPixelTransferManager. + NOTREACHED(); + manager_ = NULL; +} + +void AsyncPixelTransferManager::OnTextureRefDestroying( + gles2::TextureRef* texture) { + TextureToStateMap::iterator it = state_map_.find(texture); + if (it != state_map_.end()) + state_map_.erase(it); +} + +} // namespace gpu diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager.h b/gpu/command_buffer/service/async_pixel_transfer_manager.h new file mode 100644 index 0000000..2f61099 --- /dev/null +++ b/gpu/command_buffer/service/async_pixel_transfer_manager.h @@ -0,0 +1,83 @@ +// Copyright 2013 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 GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_H_ + +#include <set> + +#include "base/basictypes.h" +#include "base/hash_tables.h" +#include "base/memory/ref_counted.h" +#include "gpu/command_buffer/service/texture_manager.h" +#include "gpu/gpu_export.h" + +#if defined(COMPILER_GCC) +namespace BASE_HASH_NAMESPACE { +template <> + struct hash<gpu::gles2::TextureRef*> { + size_t operator()(gpu::gles2::TextureRef* ptr) const { + return hash<size_t>()(reinterpret_cast<size_t>(ptr)); + } +}; +} // namespace BASE_HASH_NAMESPACE +#endif // COMPILER + +namespace gfx { +class GLContext; +} + +namespace gpu { +class AsyncPixelTransferDelegate; +class AsyncPixelTransferState; +struct AsyncTexImage2DParams; + +class GPU_EXPORT AsyncPixelTransferManager + : public gles2::TextureManager::DestructionObserver { + public: + AsyncPixelTransferManager(gles2::TextureManager* texture_manager_, + gfx::GLContext* context); + virtual ~AsyncPixelTransferManager(); + + AsyncPixelTransferDelegate* GetAsyncPixelTransferDelegate() { + return delegate_.get(); + } + + void SetAsyncPixelTransferDelegateForTest( + AsyncPixelTransferDelegate* delegate) { + delegate_ = make_scoped_ptr(delegate); + } + + AsyncPixelTransferState* CreatePixelTransferState( + gles2::TextureRef* ref, + const AsyncTexImage2DParams& define_params); + + AsyncPixelTransferState* GetPixelTransferState( + gles2::TextureRef* ref); + + void ClearPixelTransferStateForTest(gles2::TextureRef* ref); + + bool AsyncTransferIsInProgress(gles2::TextureRef* ref); + + // gles2::TextureRef::DestructionObserver implementation: + virtual void OnTextureManagerDestroying(gles2::TextureManager* manager) + OVERRIDE; + virtual void OnTextureRefDestroying(gles2::TextureRef* texture) OVERRIDE; + + private: + gles2::TextureManager* manager_; + + scoped_ptr<AsyncPixelTransferDelegate> delegate_; + + typedef base::hash_map<gles2::TextureRef*, + scoped_refptr<AsyncPixelTransferState> > + TextureToStateMap; + TextureToStateMap state_map_; + + DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferManager); +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_H_ diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 28d3b57..6bfcc18 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -56,6 +56,7 @@ #include "gpu/command_buffer/service/vertex_attrib_manager.h" #include "gpu/command_buffer/service/vertex_array_manager.h" #include "gpu/command_buffer/service/async_pixel_transfer_delegate.h" +#include "gpu/command_buffer/service/async_pixel_transfer_manager.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_image.h" #include "ui/gl/gl_implementation.h" @@ -574,8 +575,11 @@ class GLES2DecoderImpl : public GLES2Decoder { virtual AsyncPixelTransferDelegate* GetAsyncPixelTransferDelegate() OVERRIDE; - virtual void SetAsyncPixelTransferDelegate( + virtual void SetAsyncPixelTransferDelegateForTest( AsyncPixelTransferDelegate* delegate) OVERRIDE; + virtual AsyncPixelTransferManager* + GetAsyncPixelTransferManager() OVERRIDE; + virtual void ResetAsyncPixelTransferManagerForTest() OVERRIDE; void ProcessFinishedAsyncTransfers(); virtual bool GetServiceTextureId(uint32 client_texture_id, @@ -820,7 +824,7 @@ class GLES2DecoderImpl : public GLES2Decoder { // Extra validation for async tex(Sub)Image2D. bool ValidateAsyncTransfer( const char* function_name, - Texture* texture, + TextureRef* texture_ref, GLenum target, GLint level, const void * data); @@ -1632,7 +1636,7 @@ class GLES2DecoderImpl : public GLES2Decoder { ShaderCacheCallback shader_cache_callback_; StreamTextureManager* stream_texture_manager_; - scoped_ptr<AsyncPixelTransferDelegate> async_pixel_transfer_delegate_; + scoped_ptr<AsyncPixelTransferManager> async_pixel_transfer_manager_; // The format of the back buffer_ GLenum back_buffer_color_format_; @@ -2471,9 +2475,8 @@ bool GLES2DecoderImpl::Initialize( if (!offscreen) context_->SetSafeToForceGpuSwitch(); - // Create a delegate to perform async pixel transfers. - async_pixel_transfer_delegate_.reset( - AsyncPixelTransferDelegate::Create(context.get())); + async_pixel_transfer_manager_.reset( + new AsyncPixelTransferManager(texture_manager(), context.get())); return true; } @@ -2789,7 +2792,7 @@ void GLES2DecoderImpl::ProcessFinishedAsyncTransfers() { // from the client, as the client may have recieved an async // completion while issuing those commands. // "DidFlushStart" would be ideal if we had such a callback. - async_pixel_transfer_delegate_->BindCompletedAsyncTransfers(); + GetAsyncPixelTransferDelegate()->BindCompletedAsyncTransfers(); } void GLES2DecoderImpl::ReleaseCurrent() { @@ -3053,12 +3056,21 @@ void GLES2DecoderImpl::SetStreamTextureManager(StreamTextureManager* manager) { AsyncPixelTransferDelegate* GLES2DecoderImpl::GetAsyncPixelTransferDelegate() { - return async_pixel_transfer_delegate_.get(); + return async_pixel_transfer_manager_->GetAsyncPixelTransferDelegate(); } -void GLES2DecoderImpl::SetAsyncPixelTransferDelegate( +void GLES2DecoderImpl::SetAsyncPixelTransferDelegateForTest( AsyncPixelTransferDelegate* delegate) { - async_pixel_transfer_delegate_ = make_scoped_ptr(delegate); + async_pixel_transfer_manager_->SetAsyncPixelTransferDelegateForTest(delegate); +} + +AsyncPixelTransferManager* + GLES2DecoderImpl::GetAsyncPixelTransferManager() { + return async_pixel_transfer_manager_.get(); +} + +void GLES2DecoderImpl::ResetAsyncPixelTransferManagerForTest() { + async_pixel_transfer_manager_.reset(); } bool GLES2DecoderImpl::GetServiceTextureId(uint32 client_texture_id, @@ -3073,12 +3085,12 @@ bool GLES2DecoderImpl::GetServiceTextureId(uint32 client_texture_id, uint32 GLES2DecoderImpl::GetTextureUploadCount() { return texture_upload_count_ + - async_pixel_transfer_delegate_->GetTextureUploadCount(); + GetAsyncPixelTransferDelegate()->GetTextureUploadCount(); } base::TimeDelta GLES2DecoderImpl::GetTotalTextureUploadTime() { return total_texture_upload_time_ + - async_pixel_transfer_delegate_->GetTotalTextureUploadTime(); + GetAsyncPixelTransferDelegate()->GetTotalTextureUploadTime(); } base::TimeDelta GLES2DecoderImpl::GetTotalProcessingCommandsTime() { @@ -3190,6 +3202,10 @@ void GLES2DecoderImpl::Destroy(bool have_context) { offscreen_resolved_frame_buffer_.reset(); offscreen_resolved_color_texture_.reset(); + // Should destroy the transfer manager before the texture manager held + // by the context group. + async_pixel_transfer_manager_.reset(); + if (group_) { group_->Destroy(this, have_context); group_ = NULL; @@ -8095,7 +8111,7 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D( GL_INVALID_VALUE, "glCopyTexSubImage2D", "bad dimensions."); return; } - if (texture->AsyncTransferIsInProgress()) { + if (async_pixel_transfer_manager_->AsyncTransferIsInProgress(texture_ref)) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, "glCopyTexSubImage2D", "async upload pending for texture"); @@ -8231,7 +8247,7 @@ bool GLES2DecoderImpl::ValidateTexSubImage2D( function_name, "type does not match type of texture."); return false; } - if (texture->AsyncTransferIsInProgress()) { + if (async_pixel_transfer_manager_->AsyncTransferIsInProgress(texture_ref)) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, function_name, "async upload pending for texture"); @@ -9096,13 +9112,13 @@ bool GLES2DecoderImpl::ProcessPendingQueries() { } bool GLES2DecoderImpl::HasMoreIdleWork() { - return async_pixel_transfer_delegate_->NeedsProcessMorePendingTransfers(); + return GetAsyncPixelTransferDelegate()->NeedsProcessMorePendingTransfers(); } void GLES2DecoderImpl::PerformIdleWork() { - if (!async_pixel_transfer_delegate_->NeedsProcessMorePendingTransfers()) + if (!GetAsyncPixelTransferDelegate()->NeedsProcessMorePendingTransfers()) return; - async_pixel_transfer_delegate_->ProcessMorePendingTransfers(); + GetAsyncPixelTransferDelegate()->ProcessMorePendingTransfers(); ProcessFinishedAsyncTransfers(); } @@ -10099,7 +10115,7 @@ void GLES2DecoderImpl::DoDrawBuffersEXT( bool GLES2DecoderImpl::ValidateAsyncTransfer( const char* function_name, - Texture* texture, + TextureRef* texture_ref, GLenum target, GLint level, const void * data) { @@ -10119,7 +10135,8 @@ bool GLES2DecoderImpl::ValidateAsyncTransfer( return false; } // We only support one async transfer in progress. - if (!texture || texture->AsyncTransferIsInProgress()) { + if (!texture_ref || + async_pixel_transfer_manager_->AsyncTransferIsInProgress(texture_ref)) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, function_name, "transfer already in progress"); @@ -10170,7 +10187,7 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM( TextureRef* texture_ref = GetTextureInfoForTarget(target); Texture* texture = texture_ref->texture(); if (!ValidateAsyncTransfer( - "glAsyncTexImage2DCHROMIUM", texture, target, level, pixels)) + "glAsyncTexImage2DCHROMIUM", texture_ref, target, level, pixels)) return error::kNoError; // Don't allow async redefinition of a textures. @@ -10205,16 +10222,13 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM( // Set up the async state if needed, and make the texture // immutable so the async state stays valid. The level info // is set up lazily when the transfer completes. - DCHECK(!texture->GetAsyncTransferState()); - texture_ref->SetAsyncTransferState( - make_scoped_ptr( - async_pixel_transfer_delegate_->CreatePixelTransferState( - texture->service_id(), - tex_params))); + AsyncPixelTransferState* state = + async_pixel_transfer_manager_->CreatePixelTransferState(texture_ref, + tex_params); texture->SetImmutable(true); - async_pixel_transfer_delegate_->AsyncTexImage2D( - texture->GetAsyncTransferState(), + GetAsyncPixelTransferDelegate()->AsyncTexImage2D( + state, tex_params, mem_params, base::Bind(&TextureManager::SetLevelInfoFromParams, @@ -10261,7 +10275,7 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM( TextureRef* texture_ref = GetTextureInfoForTarget(target); Texture* texture = texture_ref->texture(); if (!ValidateAsyncTransfer( - "glAsyncTexSubImage2DCHROMIUM", texture, target, level, pixels)) + "glAsyncTexSubImage2DCHROMIUM", texture_ref, target, level, pixels)) return error::kNoError; // Guarantee async textures are always 'cleared' as follows: @@ -10293,7 +10307,8 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM( width, height, format, type}; AsyncMemoryParams mem_params = {shared_memory, shm_size, shm_data_offset, shm_data_size}; - AsyncPixelTransferState* state = texture->GetAsyncTransferState(); + AsyncPixelTransferState* state = + async_pixel_transfer_manager_->GetPixelTransferState(texture_ref); if (!state) { // TODO(epenner): We may want to enforce exclusive use // of async APIs in which case this should become an error, @@ -10306,14 +10321,12 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM( &define_params.internal_format); // Set up the async state if needed, and make the texture // immutable so the async state stays valid. - state = async_pixel_transfer_delegate_->CreatePixelTransferState( - texture->service_id(), - define_params); - texture_ref->SetAsyncTransferState(make_scoped_ptr(state)); + state = async_pixel_transfer_manager_->CreatePixelTransferState( + texture_ref, define_params); texture->SetImmutable(true); } - async_pixel_transfer_delegate_->AsyncTexSubImage2D( + GetAsyncPixelTransferDelegate()->AsyncTexSubImage2D( state, tex_params, mem_params); return error::kNoError; } @@ -10336,14 +10349,14 @@ error::Error GLES2DecoderImpl::HandleWaitAsyncTexImage2DCHROMIUM( return error::kNoError; } AsyncPixelTransferState* state = - texture_ref->texture()->GetAsyncTransferState(); + async_pixel_transfer_manager_->GetPixelTransferState(texture_ref); if (!state) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, "glWaitAsyncTexImage2DCHROMIUM", "No async transfer started"); return error::kNoError; } - async_pixel_transfer_delegate_->WaitForTransferCompletion(state); + GetAsyncPixelTransferDelegate()->WaitForTransferCompletion(state); ProcessFinishedAsyncTransfers(); return error::kNoError; } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index 86d4801..65ebe76 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h @@ -26,6 +26,7 @@ class GLSurface; namespace gpu { class AsyncPixelTransferDelegate; +class AsyncPixelTransferManager; class StreamTextureManager; namespace gles2 { @@ -179,9 +180,12 @@ class GPU_EXPORT GLES2Decoder : public base::SupportsWeakPtr<GLES2Decoder>, // Interface to performing async pixel transfers. virtual AsyncPixelTransferDelegate* GetAsyncPixelTransferDelegate() = 0; - virtual void SetAsyncPixelTransferDelegate( + virtual void SetAsyncPixelTransferDelegateForTest( AsyncPixelTransferDelegate* delegate) = 0; + virtual AsyncPixelTransferManager* GetAsyncPixelTransferManager() = 0; + virtual void ResetAsyncPixelTransferManagerForTest() = 0; + // Get the service texture ID corresponding to a client texture ID. // If no such record is found then return false. virtual bool GetServiceTextureId(uint32 client_texture_id, diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h index 3f714bd..ded5e4b 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h @@ -73,8 +73,11 @@ class MockGLES2Decoder : public GLES2Decoder { MOCK_METHOD1(SetStreamTextureManager, void(StreamTextureManager*)); MOCK_METHOD0(GetAsyncPixelTransferDelegate, AsyncPixelTransferDelegate*()); - MOCK_METHOD1(SetAsyncPixelTransferDelegate, + MOCK_METHOD1(SetAsyncPixelTransferDelegateForTest, void(AsyncPixelTransferDelegate*)); + MOCK_METHOD0(GetAsyncPixelTransferManager, + AsyncPixelTransferManager*()); + MOCK_METHOD0(ResetAsyncPixelTransferManagerForTest, void()); MOCK_METHOD3(DoCommand, error::Error(unsigned int command, unsigned int arg_count, const void* cmd_data)); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index c2413d1..b4baf8b 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -9,6 +9,7 @@ #include "gpu/command_buffer/common/gles2_cmd_utils.h" #include "gpu/command_buffer/common/id_allocator.h" #include "gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h" +#include "gpu/command_buffer/service/async_pixel_transfer_manager.h" #include "gpu/command_buffer/service/cmd_buffer_engine.h" #include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/gl_surface_mock.h" @@ -8082,7 +8083,7 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { // Set a mock Async delegate StrictMock<gpu::MockAsyncPixelTransferDelegate>* delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>; - decoder_->SetAsyncPixelTransferDelegate(delegate); + decoder_->SetAsyncPixelTransferDelegateForTest(delegate); StrictMock<gpu::MockAsyncPixelTransferState>* state = NULL; // Tex(Sub)Image2D upload commands. @@ -8096,7 +8097,8 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { wait_cmd.Init(GL_TEXTURE_2D); // No transfer state exists initially. - EXPECT_FALSE(texture->GetAsyncTransferState()); + EXPECT_FALSE(decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); base::Closure bind_callback; @@ -8113,7 +8115,8 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { // Command succeeds. EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); - EXPECT_TRUE(texture->GetAsyncTransferState()); + EXPECT_TRUE(decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); EXPECT_TRUE(texture->IsImmutable()); // The texture is safe but the level has not been defined yet. EXPECT_TRUE(texture->SafeToRenderFrom()); @@ -8125,7 +8128,8 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { // Command fails. EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); - EXPECT_TRUE(texture->GetAsyncTransferState()); + EXPECT_TRUE(decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); EXPECT_TRUE(texture->IsImmutable()); EXPECT_TRUE(texture->SafeToRenderFrom()); } @@ -8149,7 +8153,8 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { } // AsyncTexSubImage2D - texture_ref->SetAsyncTransferState(scoped_ptr<AsyncPixelTransferState>()); + decoder_->GetAsyncPixelTransferManager() + ->ClearPixelTransferStateForTest(texture_ref); texture->SetImmutable(false); { // Create transfer state since it doesn't exist. @@ -8162,7 +8167,8 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { // Command succeeds. EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); - EXPECT_TRUE(texture->GetAsyncTransferState()); + EXPECT_TRUE(decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); EXPECT_TRUE(texture->IsImmutable()); EXPECT_TRUE(texture->SafeToRenderFrom()); } @@ -8177,7 +8183,8 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { // Command succeeds. EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); - EXPECT_TRUE(texture->GetAsyncTransferState()); + EXPECT_TRUE(decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); EXPECT_TRUE(texture->IsImmutable()); EXPECT_TRUE(texture->SafeToRenderFrom()); } @@ -8189,23 +8196,33 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { // No async call, command fails. EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd)); EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); - EXPECT_TRUE(texture->GetAsyncTransferState()); + EXPECT_TRUE(decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); EXPECT_TRUE(texture->IsImmutable()); EXPECT_TRUE(texture->SafeToRenderFrom()); } + // Delete state on DeleteTexture. + { + EXPECT_CALL(*state, Destroy()).RetiresOnSaturation(); + DoDeleteTexture(client_texture_id_, kServiceTextureId); + EXPECT_FALSE( + decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); + state = NULL; + } + // WaitAsyncTexImage2D { // Get a fresh texture since the existing texture cannot be respecified // asynchronously and AsyncTexSubImage2D does not involved binding. EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgumentPointee<1>(kServiceTextureId)); - texture_ref->SetAsyncTransferState(scoped_ptr<AsyncPixelTransferState>()); - DoDeleteTexture(client_texture_id_, kServiceTextureId); DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); texture_ref = GetTexture(client_texture_id_); texture = texture_ref->texture(); - texture_ref->SetAsyncTransferState(scoped_ptr<AsyncPixelTransferState>()); + decoder_->GetAsyncPixelTransferManager() + ->ClearPixelTransferStateForTest(texture_ref); texture->SetImmutable(false); // Create transfer state since it doesn't exist. EXPECT_CALL(*delegate, CreatePixelTransferState(kServiceTextureId, _)) @@ -8217,7 +8234,9 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { // Start async transfer. EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); - EXPECT_TRUE(texture->GetAsyncTransferState()); + EXPECT_TRUE(decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); + EXPECT_TRUE(texture->IsImmutable()); // Wait for completion. EXPECT_CALL(*delegate, WaitForTransferCompletion(state)); @@ -8226,8 +8245,63 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { EXPECT_EQ(GL_NO_ERROR, GetGLError()); } - decoder_->SetAsyncPixelTransferDelegate(NULL); - texture_ref->SetAsyncTransferState(scoped_ptr<AsyncPixelTransferState>()); + decoder_->SetAsyncPixelTransferDelegateForTest(NULL); + decoder_->GetAsyncPixelTransferManager() + ->ClearPixelTransferStateForTest(texture_ref); +} + +TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransferManager) { + InitDecoder( + "GL_CHROMIUM_async_pixel_transfers", // extensions + false, false, false, // has alpha/depth/stencil + false, false, false, // request alpha/depth/stencil + true); // bind generates resource + + // Set up the texture. + DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); + TextureRef* texture_ref = GetTexture(client_texture_id_); + + // Set a mock Async delegate. + StrictMock<gpu::MockAsyncPixelTransferDelegate>* delegate = + new StrictMock<gpu::MockAsyncPixelTransferDelegate>; + decoder_->SetAsyncPixelTransferDelegateForTest(delegate); + StrictMock<gpu::MockAsyncPixelTransferState>* state = NULL; + + AsyncTexImage2DCHROMIUM teximage_cmd; + teximage_cmd.Init(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, + GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset); + + // No transfer state exists initially. + EXPECT_FALSE(decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); + + // Create state on AsyncTexImage2D. + { + EXPECT_CALL(*delegate, CreatePixelTransferState(kServiceTextureId, _)) + .WillOnce( + Return(state = new StrictMock<gpu::MockAsyncPixelTransferState>)) + .RetiresOnSaturation(); + EXPECT_CALL(*delegate, AsyncTexImage2D(state, _, _, _)) + .RetiresOnSaturation(); + + // Command succeeds. + EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + } + + // State is cached. + EXPECT_EQ(state, + decoder_->GetAsyncPixelTransferManager()->GetPixelTransferState( + texture_ref)); + + // Delete state on manager teardown. + { + EXPECT_CALL(*state, Destroy()).RetiresOnSaturation(); + decoder_->ResetAsyncPixelTransferManagerForTest(); + + // Texture ref still valid. + EXPECT_EQ(texture_ref, GetTexture(client_texture_id_)); + } } namespace { diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 9e67849..f878df3 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc @@ -60,7 +60,15 @@ static size_t FaceIndexToGLTarget(size_t index) { } } +TextureManager::DestructionObserver::DestructionObserver() {} + +TextureManager::DestructionObserver::~DestructionObserver() {} + TextureManager::~TextureManager() { + FOR_EACH_OBSERVER(DestructionObserver, + destruction_observers_, + OnTextureManagerDestroying(this)); + DCHECK(textures_.empty()); // If this triggers, that means something is keeping a reference to @@ -432,15 +440,6 @@ void Texture::IncAllFramebufferStateChangeCount() { (*it)->manager()->IncFramebufferStateChangeCount(); } -AsyncPixelTransferState* Texture::GetAsyncTransferState() const { - for (RefSet::const_iterator it = refs_.begin(); it != refs_.end(); ++it) { - AsyncPixelTransferState* state = (*it)->async_transfer_state(); - if (state) - return state; - } - return NULL; -} - void Texture::SetLevelInfo( const FeatureInfo* feature_info, GLenum target, @@ -1097,6 +1096,10 @@ void TextureManager::StartTracking(TextureRef* ref) { } void TextureManager::StopTracking(TextureRef* ref) { + FOR_EACH_OBSERVER(DestructionObserver, + destruction_observers_, + OnTextureRefDestroying(ref)); + Texture* texture = ref->texture(); --texture_count_; if (!texture->CanRender(feature_info_)) { diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index ec0b5a6..2d4640e 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h @@ -13,6 +13,7 @@ #include "base/hash_tables.h" #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/observer_list.h" #include "gpu/command_buffer/service/async_pixel_transfer_delegate.h" #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/command_buffer/service/memory_tracking.h" @@ -144,15 +145,6 @@ class GPU_EXPORT Texture { return stream_texture_; } - // Gets the async transfer state for this texture. Note: the transfer state is - // owned by a single TextureRef. - AsyncPixelTransferState* GetAsyncTransferState() const; - - bool AsyncTransferIsInProgress() { - AsyncPixelTransferState* state = GetAsyncTransferState(); - return state && state->TransferIsInProgress(); - } - void SetImmutable(bool immutable) { immutable_ = immutable; } @@ -411,15 +403,6 @@ class GPU_EXPORT TextureRef : public base::RefCounted<TextureRef> { GLuint client_id() const { return client_id_; } GLuint service_id() const { return texture_->service_id(); } - // Sets the async transfer state for this texture. Only a single TextureRef - // can set this on a given texture at any time. - // NOTE: this should be per-context rather than per-texture. crbug.com/240504 - void SetAsyncTransferState( - scoped_ptr<AsyncPixelTransferState> state) { - DCHECK(!state || !texture_->GetAsyncTransferState()); - async_transfer_state_ = state.Pass(); - } - private: friend class base::RefCounted<TextureRef>; friend class Texture; @@ -428,18 +411,12 @@ class GPU_EXPORT TextureRef : public base::RefCounted<TextureRef> { ~TextureRef(); const TextureManager* manager() const { return manager_; } TextureManager* manager() { return manager_; } - AsyncPixelTransferState* async_transfer_state() const { - return async_transfer_state_.get(); - } void reset_client_id() { client_id_ = 0; } TextureManager* manager_; Texture* texture_; GLuint client_id_; - // State to facilitate async transfers on this texture. - scoped_ptr<AsyncPixelTransferState> async_transfer_state_; - DISALLOW_COPY_AND_ASSIGN(TextureRef); }; @@ -450,6 +427,21 @@ class GPU_EXPORT TextureRef : public base::RefCounted<TextureRef> { // shared by multiple GLES2Decoders. class GPU_EXPORT TextureManager { public: + class GPU_EXPORT DestructionObserver { + public: + DestructionObserver(); + virtual ~DestructionObserver(); + + // Called in ~TextureManager. + virtual void OnTextureManagerDestroying(TextureManager* manager) = 0; + + // Called via ~TextureRef. + virtual void OnTextureRefDestroying(TextureRef* texture) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(DestructionObserver); + }; + enum DefaultAndBlackTextures { kTexture2D, kCubeMap, @@ -654,6 +646,14 @@ class GPU_EXPORT TextureManager { GLint level, std::string* signature) const; + void AddObserver(DestructionObserver* observer) { + destruction_observers_.AddObserver(observer); + } + + void RemoveObserver(DestructionObserver* observer) { + destruction_observers_.RemoveObserver(observer); + } + private: friend class Texture; friend class TextureRef; @@ -707,6 +707,8 @@ class GPU_EXPORT TextureManager { // The default textures for each target (texture name = 0) scoped_refptr<TextureRef> default_textures_[kNumDefaultTextures]; + ObserverList<DestructionObserver> destruction_observers_; + DISALLOW_COPY_AND_ASSIGN(TextureManager); }; diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi index 8895526..9dc5efd 100644 --- a/gpu/command_buffer_service.gypi +++ b/gpu/command_buffer_service.gypi @@ -39,6 +39,8 @@ 'command_buffer/service/async_pixel_transfer_delegate_sync.cc', 'command_buffer/service/async_pixel_transfer_delegate_sync.h', 'command_buffer/service/async_pixel_transfer_delegate_win.cc', + 'command_buffer/service/async_pixel_transfer_manager.cc', + 'command_buffer/service/async_pixel_transfer_manager.h', 'command_buffer/service/buffer_manager.h', 'command_buffer/service/buffer_manager.cc', 'command_buffer/service/cmd_buffer_engine.h', |