diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-01 22:41:16 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-01 22:41:16 +0000 |
commit | d304cbdeccf3db7330c09cb218096a45a2bdc746 (patch) | |
tree | d0b939398f1fe3f4beb1def5fbede824d1dea94d | |
parent | e7f7509f4ab3672f61e6fc5ec6b5ce0b5eefb4a8 (diff) | |
download | chromium_src-d304cbdeccf3db7330c09cb218096a45a2bdc746.zip chromium_src-d304cbdeccf3db7330c09cb218096a45a2bdc746.tar.gz chromium_src-d304cbdeccf3db7330c09cb218096a45a2bdc746.tar.bz2 |
Free the resources used by a context group.
TEST=unit tests
BUG=none
Review URL: http://codereview.chromium.org/2880013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@51441 0039d316-1c4b-4281-b951-d872f2087c98
24 files changed, 371 insertions, 2 deletions
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc index c4c750e..2abc764 100644 --- a/gpu/command_buffer/service/buffer_manager.cc +++ b/gpu/command_buffer/service/buffer_manager.cc @@ -10,6 +10,24 @@ namespace gpu { namespace gles2 { +BufferManager::~BufferManager() { + DCHECK(buffer_infos_.empty()); +} + +void BufferManager::Destroy(bool have_context) { + while (!buffer_infos_.empty()) { + if (have_context) { + BufferInfo* info = buffer_infos_.begin()->second; + if (!info->IsDeleted()) { + GLuint service_id = info->service_id(); + glDeleteBuffersARB(1, &service_id); + info->MarkAsDeleted(); + } + } + buffer_infos_.erase(buffer_infos_.begin()); + } +} + void BufferManager::CreateBufferInfo(GLuint client_id, GLuint service_id) { std::pair<BufferInfoMap::iterator, bool> result = buffer_infos_.insert( diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h index bc0d1db..f89faeb 100644 --- a/gpu/command_buffer/service/buffer_manager.h +++ b/gpu/command_buffer/service/buffer_manager.h @@ -143,6 +143,10 @@ class BufferManager { BufferManager() : allow_buffers_on_multiple_targets_(false) { } + ~BufferManager(); + + // Must call before destruction. + void Destroy(bool have_context); // Creates a BufferInfo for the given buffer. void CreateBufferInfo(GLuint client_id, GLuint service_id); diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc index 96a4f03..3f78fbe 100644 --- a/gpu/command_buffer/service/buffer_manager_unittest.cc +++ b/gpu/command_buffer/service/buffer_manager_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "gpu/command_buffer/service/buffer_manager.h" +#include "app/gfx/gl/gl_mock.h" #include "testing/gtest/include/gtest/gtest.h" namespace gpu { @@ -12,18 +13,27 @@ class BufferManagerTest : public testing::Test { public: BufferManagerTest() { } + ~BufferManagerTest() { + manager_.Destroy(false); + } protected: virtual void SetUp() { + gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); + ::gfx::GLInterface::SetGLInterface(gl_.get()); } virtual void TearDown() { + ::gfx::GLInterface::SetGLInterface(NULL); + gl_.reset(); } GLenum GetTarget(const BufferManager::BufferInfo* info) const { return info->target(); } + // Use StrictMock to make 100% sure we know how GL will be called. + scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; BufferManager manager_; }; @@ -58,6 +68,24 @@ TEST_F(BufferManagerTest, Basic) { EXPECT_TRUE(manager_.GetBufferInfo(kClientBuffer1Id) == NULL); } +TEST_F(BufferManagerTest, Destroy) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + // Check we can create buffer. + manager_.CreateBufferInfo(kClient1Id, kService1Id); + // Check buffer got created. + BufferManager::BufferInfo* info1 = + manager_.GetBufferInfo(kClient1Id); + ASSERT_TRUE(info1 != NULL); + EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kService1Id))) + .Times(1) + .RetiresOnSaturation(); + manager_.Destroy(true); + // Check the resources were released. + info1 = manager_.GetBufferInfo(kClient1Id); + ASSERT_TRUE(info1 == NULL); +} + TEST_F(BufferManagerTest, SetRange) { const GLuint kClientBufferId = 1; const GLuint kServiceBufferId = 11; diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc index 71b796c..4f30ad5 100644 --- a/gpu/command_buffer/service/context_group.cc +++ b/gpu/command_buffer/service/context_group.cc @@ -26,6 +26,13 @@ ContextGroup::ContextGroup() } ContextGroup::~ContextGroup() { + // Check that Destroy has been called. + DCHECK(buffer_manager_ == NULL); + DCHECK(framebuffer_manager_ == NULL); + DCHECK(renderbuffer_manager_ == NULL); + DCHECK(texture_manager_ == NULL); + DCHECK(program_manager_ == NULL); + DCHECK(shader_manager_ == NULL); } static void GetIntegerv(GLenum pname, uint32* var) { @@ -87,6 +94,38 @@ bool ContextGroup::Initialize() { return true; } +void ContextGroup::Destroy(bool have_context) { + if (buffer_manager_ != NULL) { + buffer_manager_->Destroy(have_context); + buffer_manager_.reset(); + } + + if (framebuffer_manager_ != NULL) { + framebuffer_manager_->Destroy(have_context); + framebuffer_manager_.reset(); + } + + if (renderbuffer_manager_ != NULL) { + renderbuffer_manager_->Destroy(have_context); + renderbuffer_manager_.reset(); + } + + if (texture_manager_ != NULL) { + texture_manager_->Destroy(have_context); + texture_manager_.reset(); + } + + if (program_manager_ != NULL) { + program_manager_->Destroy(have_context); + program_manager_.reset(); + } + + if (shader_manager_ != NULL) { + shader_manager_->Destroy(have_context); + shader_manager_.reset(); + } +} + IdAllocator* ContextGroup::GetIdAllocator(unsigned namespace_id) { IdAllocatorMap::iterator it = id_namespaces_.find(namespace_id); if (it != id_namespaces_.end()) { diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h index 477983f..21fc061 100644 --- a/gpu/command_buffer/service/context_group.h +++ b/gpu/command_buffer/service/context_group.h @@ -35,6 +35,9 @@ class ContextGroup { // This should only be called by GLES2Decoder. bool Initialize(); + // Destroys all the resources. MUST be called before destruction. + void Destroy(bool have_context); + uint32 max_vertex_attribs() const { return max_vertex_attribs_; } diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc index 1a7d739..8dd036b 100644 --- a/gpu/command_buffer/service/framebuffer_manager.cc +++ b/gpu/command_buffer/service/framebuffer_manager.cc @@ -9,6 +9,24 @@ namespace gpu { namespace gles2 { +FramebufferManager::~FramebufferManager() { + DCHECK(framebuffer_infos_.empty()); +} + +void FramebufferManager::Destroy(bool have_context) { + while (!framebuffer_infos_.empty()) { + if (have_context) { + FramebufferInfo* info = framebuffer_infos_.begin()->second; + if (!info->IsDeleted()) { + GLuint service_id = info->service_id(); + glDeleteFramebuffersEXT(1, &service_id); + info->MarkAsDeleted(); + } + } + framebuffer_infos_.erase(framebuffer_infos_.begin()); + } +} + void FramebufferManager::CreateFramebufferInfo( GLuint client_id, GLuint service_id) { std::pair<FramebufferInfoMap::iterator, bool> result = diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h index 3ecb54b..f437e6a 100644 --- a/gpu/command_buffer/service/framebuffer_manager.h +++ b/gpu/command_buffer/service/framebuffer_manager.h @@ -63,6 +63,10 @@ class FramebufferManager { }; FramebufferManager() { } + ~FramebufferManager(); + + // Must call before destruction. + void Destroy(bool have_context); // Creates a FramebufferInfo for the given framebuffer. void CreateFramebufferInfo(GLuint client_id, GLuint service_id); diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc index 75d0da6..ed435c1 100644 --- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc +++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "gpu/command_buffer/service/framebuffer_manager.h" +#include "app/gfx/gl/gl_mock.h" #include "testing/gtest/include/gtest/gtest.h" namespace gpu { @@ -12,14 +13,23 @@ class FramebufferManagerTest : public testing::Test { public: FramebufferManagerTest() { } + ~FramebufferManagerTest() { + manager_.Destroy(false); + } protected: virtual void SetUp() { + gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); + ::gfx::GLInterface::SetGLInterface(gl_.get()); } virtual void TearDown() { + ::gfx::GLInterface::SetGLInterface(NULL); + gl_.reset(); } + // Use StrictMock to make 100% sure we know how GL will be called. + scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; FramebufferManager manager_; }; @@ -47,6 +57,24 @@ TEST_F(FramebufferManagerTest, Basic) { EXPECT_TRUE(manager_.GetFramebufferInfo(kClient1Id) == NULL); } +TEST_F(FramebufferManagerTest, Destroy) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + // Check we can create framebuffer. + manager_.CreateFramebufferInfo(kClient1Id, kService1Id); + // Check framebuffer got created. + FramebufferManager::FramebufferInfo* info1 = + manager_.GetFramebufferInfo(kClient1Id); + ASSERT_TRUE(info1 != NULL); + EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, ::testing::Pointee(kService1Id))) + .Times(1) + .RetiresOnSaturation(); + manager_.Destroy(true); + // Check the resources were released. + info1 = manager_.GetFramebufferInfo(kClient1Id); + ASSERT_TRUE(info1 == NULL); +} + // TODO(gman): Write test for AttachRenderbuffer } // namespace gles2 diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 2671058..edb5745 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -201,6 +201,7 @@ void GLES2DecoderTestBase::TearDown() { .RetiresOnSaturation(); decoder_->Destroy(); decoder_.reset(); + group_.Destroy(false); engine_.reset(); ::gfx::GLInterface::SetGLInterface(NULL); gl_.reset(); diff --git a/gpu/command_buffer/service/gpu_processor.cc b/gpu/command_buffer/service/gpu_processor.cc index 993e81e..7872b22 100644 --- a/gpu/command_buffer/service/gpu_processor.cc +++ b/gpu/command_buffer/service/gpu_processor.cc @@ -70,11 +70,15 @@ bool GPUProcessor::InitializeCommon(const gfx::Size& size, } void GPUProcessor::DestroyCommon() { + bool have_context = false; if (decoder_.get()) { + have_context = decoder_->MakeCurrent(); decoder_->Destroy(); decoder_.reset(); } + group_.Destroy(have_context); + if (context_.get()) { context_->Destroy(); context_.reset(); diff --git a/gpu/command_buffer/service/gpu_processor.h b/gpu/command_buffer/service/gpu_processor.h index 7d5a110..f1b2a5d 100644 --- a/gpu/command_buffer/service/gpu_processor.h +++ b/gpu/command_buffer/service/gpu_processor.h @@ -98,6 +98,8 @@ class GPUProcessor : public CommandBufferEngine { int commands_per_update_; + // TODO(gman): Group needs to be passed in so it can be shared by + // multiple GPUProcessors. gles2::ContextGroup group_; scoped_ptr<gles2::GLES2Decoder> decoder_; scoped_ptr<CommandParser> parser_; diff --git a/gpu/command_buffer/service/gpu_processor_unittest.cc b/gpu/command_buffer/service/gpu_processor_unittest.cc index a91cc4c..da2b9e0 100644 --- a/gpu/command_buffer/service/gpu_processor_unittest.cc +++ b/gpu/command_buffer/service/gpu_processor_unittest.cc @@ -61,6 +61,10 @@ class GPUProcessorTest : public testing::Test { decoder_, parser_, 2)); + + EXPECT_CALL(*decoder_, Destroy()) + .Times(1) + .RetiresOnSaturation(); } virtual void TearDown() { @@ -148,6 +152,7 @@ TEST_F(GPUProcessorTest, ProcessesTwoCommands) { TEST_F(GPUProcessorTest, ProcessorSetsTheGLContext) { EXPECT_CALL(*decoder_, MakeCurrent()) + .WillOnce(Return(true)) .WillOnce(Return(true)); CommandBuffer::State state; diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc index 66605b3..55d1268 100644 --- a/gpu/command_buffer/service/program_manager.cc +++ b/gpu/command_buffer/service/program_manager.cc @@ -307,6 +307,23 @@ bool ProgramManager::ProgramInfo::CanLink() const { return true; } +ProgramManager::~ProgramManager() { + DCHECK(program_infos_.empty()); +} + +void ProgramManager::Destroy(bool have_context) { + while (!program_infos_.empty()) { + if (have_context) { + ProgramInfo* info = program_infos_.begin()->second; + if (!info->IsDeleted()) { + glDeleteProgram(info->service_id()); + info->MarkAsDeleted(); + } + } + program_infos_.erase(program_infos_.begin()); + } +} + void ProgramManager::CreateProgramInfo(GLuint client_id, GLuint service_id) { std::pair<ProgramInfoMap::iterator, bool> result = program_infos_.insert( diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h index 995caa2..66c09f2 100644 --- a/gpu/command_buffer/service/program_manager.h +++ b/gpu/command_buffer/service/program_manager.h @@ -197,6 +197,10 @@ class ProgramManager { }; ProgramManager() { } + ~ProgramManager(); + + // Must call before destruction. + void Destroy(bool have_context); // Creates a new program info. void CreateProgramInfo(GLuint client_id, GLuint service_id); diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc index a3a47d9..3faf14e 100644 --- a/gpu/command_buffer/service/program_manager_unittest.cc +++ b/gpu/command_buffer/service/program_manager_unittest.cc @@ -26,14 +26,23 @@ namespace gles2 { class ProgramManagerTest : public testing::Test { public: ProgramManagerTest() { } + ~ProgramManagerTest() { + manager_.Destroy(false); + } protected: virtual void SetUp() { + gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); + ::gfx::GLInterface::SetGLInterface(gl_.get()); } virtual void TearDown() { + ::gfx::GLInterface::SetGLInterface(NULL); + gl_.reset(); } + // Use StrictMock to make 100% sure we know how GL will be called. + scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; ProgramManager manager_; }; @@ -61,12 +70,34 @@ TEST_F(ProgramManagerTest, Basic) { EXPECT_TRUE(manager_.GetProgramInfo(kClient1Id) == NULL); } +TEST_F(ProgramManagerTest, Destroy) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + // Check we can create program. + manager_.CreateProgramInfo(kClient1Id, kService1Id); + // Check program got created. + ProgramManager::ProgramInfo* info1 = + manager_.GetProgramInfo(kClient1Id); + ASSERT_TRUE(info1 != NULL); + EXPECT_CALL(*gl_, DeleteProgram(kService1Id)) + .Times(1) + .RetiresOnSaturation(); + manager_.Destroy(true); + // Check the resources were released. + info1 = manager_.GetProgramInfo(kClient1Id); + ASSERT_TRUE(info1 == NULL); +} + class ProgramManagerWithShaderTest : public testing::Test { public: ProgramManagerWithShaderTest() : program_info_(NULL) { } + ~ProgramManagerWithShaderTest() { + manager_.Destroy(false); + } + static const GLint kNumVertexAttribs = 16; static const GLuint kClientProgramId = 123; @@ -410,6 +441,7 @@ TEST_F(ProgramManagerWithShaderTest, AttachDetachShader) { EXPECT_FALSE(program_info->CanLink()); fshader->SetStatus(true, ""); EXPECT_TRUE(program_info->CanLink()); + shader_manager.Destroy(false); } TEST_F(ProgramManagerWithShaderTest, GetUniformLocation) { diff --git a/gpu/command_buffer/service/renderbuffer_manager.cc b/gpu/command_buffer/service/renderbuffer_manager.cc index 63aee26..88a2d26 100644 --- a/gpu/command_buffer/service/renderbuffer_manager.cc +++ b/gpu/command_buffer/service/renderbuffer_manager.cc @@ -10,6 +10,24 @@ namespace gpu { namespace gles2 { +RenderbufferManager::~RenderbufferManager() { + DCHECK(renderbuffer_infos_.empty()); +} + +void RenderbufferManager::Destroy(bool have_context) { + while (!renderbuffer_infos_.empty()) { + if (have_context) { + RenderbufferInfo* info = renderbuffer_infos_.begin()->second; + if (!info->IsDeleted()) { + GLuint service_id = info->service_id(); + glDeleteRenderbuffersEXT(1, &service_id); + info->MarkAsDeleted(); + } + } + renderbuffer_infos_.erase(renderbuffer_infos_.begin()); + } +} + void RenderbufferManager::CreateRenderbufferInfo( GLuint client_id, GLuint service_id) { std::pair<RenderbufferInfoMap::iterator, bool> result = diff --git a/gpu/command_buffer/service/renderbuffer_manager.h b/gpu/command_buffer/service/renderbuffer_manager.h index e5f1c0b..50b64a9 100644 --- a/gpu/command_buffer/service/renderbuffer_manager.h +++ b/gpu/command_buffer/service/renderbuffer_manager.h @@ -75,6 +75,10 @@ class RenderbufferManager { }; RenderbufferManager() { } + ~RenderbufferManager(); + + // Must call before destruction. + void Destroy(bool have_context); // Creates a RenderbufferInfo for the given renderbuffer. void CreateRenderbufferInfo(GLuint client_id, GLuint service_id); diff --git a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc index 0cedaea..05c51ce 100644 --- a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc +++ b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "gpu/command_buffer/service/renderbuffer_manager.h" +#include "app/gfx/gl/gl_mock.h" #include "testing/gtest/include/gtest/gtest.h" namespace gpu { @@ -12,14 +13,23 @@ class RenderbufferManagerTest : public testing::Test { public: RenderbufferManagerTest() { } + ~RenderbufferManagerTest() { + manager_.Destroy(false); + } protected: virtual void SetUp() { + gl_.reset(new ::testing::StrictMock<gfx::MockGLInterface>()); + ::gfx::GLInterface::SetGLInterface(gl_.get()); } virtual void TearDown() { + ::gfx::GLInterface::SetGLInterface(NULL); + gl_.reset(); } + // Use StrictMock to make 100% sure we know how GL will be called. + scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; RenderbufferManager manager_; }; @@ -50,6 +60,23 @@ TEST_F(RenderbufferManagerTest, Basic) { EXPECT_TRUE(manager_.GetRenderbufferInfo(kClient1Id) == NULL); } +TEST_F(RenderbufferManagerTest, Destroy) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + // Check we can create renderbuffer. + manager_.CreateRenderbufferInfo(kClient1Id, kService1Id); + // Check renderbuffer got created. + RenderbufferManager::RenderbufferInfo* info1 = + manager_.GetRenderbufferInfo(kClient1Id); + ASSERT_TRUE(info1 != NULL); + EXPECT_CALL(*gl_, DeleteRenderbuffersEXT(1, ::testing::Pointee(kService1Id))) + .Times(1) + .RetiresOnSaturation(); + manager_.Destroy(true); + info1 = manager_.GetRenderbufferInfo(kClient1Id); + ASSERT_TRUE(info1 == NULL); +} + } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc index 36a7b1a..eb4a899 100644 --- a/gpu/command_buffer/service/shader_manager.cc +++ b/gpu/command_buffer/service/shader_manager.cc @@ -8,6 +8,23 @@ namespace gpu { namespace gles2 { +ShaderManager::~ShaderManager() { + DCHECK(shader_infos_.empty()); +} + +void ShaderManager::Destroy(bool have_context) { + while (!shader_infos_.empty()) { + if (have_context) { + ShaderInfo* info = shader_infos_.begin()->second; + if (!info->IsDeleted()) { + glDeleteShader(info->service_id()); + info->MarkAsDeleted(); + } + } + shader_infos_.erase(shader_infos_.begin()); + } +} + void ShaderManager::CreateShaderInfo(GLuint client_id, GLuint service_id, GLenum shader_type) { diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h index b0bcfa2..d9b8c46 100644 --- a/gpu/command_buffer/service/shader_manager.h +++ b/gpu/command_buffer/service/shader_manager.h @@ -91,8 +91,11 @@ class ShaderManager { std::string log_info_; }; - ShaderManager() { - } + ShaderManager() { } + ~ShaderManager(); + + // Must call before destruction. + void Destroy(bool have_context); // Creates a shader info for the given shader ID. void CreateShaderInfo(GLuint client_id, diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc index e93a65ef..ccccb22 100644 --- a/gpu/command_buffer/service/shader_manager_unittest.cc +++ b/gpu/command_buffer/service/shader_manager_unittest.cc @@ -3,6 +3,8 @@ // found in the LICENSE file. #include "gpu/command_buffer/service/shader_manager.h" +#include "base/scoped_ptr.h" +#include "app/gfx/gl/gl_mock.h" #include "testing/gtest/include/gtest/gtest.h" namespace gpu { @@ -13,13 +15,23 @@ class ShaderManagerTest : public testing::Test { ShaderManagerTest() { } + ~ShaderManagerTest() { + manager_.Destroy(false); + } + protected: virtual void SetUp() { + gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); + ::gfx::GLInterface::SetGLInterface(gl_.get()); } virtual void TearDown() { + ::gfx::GLInterface::SetGLInterface(NULL); + gl_.reset(); } + // Use StrictMock to make 100% sure we know how GL will be called. + scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; ShaderManager manager_; }; @@ -55,6 +67,24 @@ TEST_F(ShaderManagerTest, Basic) { EXPECT_TRUE(manager_.GetShaderInfo(kClient1Id) == NULL); } +TEST_F(ShaderManagerTest, Destroy) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + const GLenum kShader1Type = GL_VERTEX_SHADER; + // Check we can create shader. + manager_.CreateShaderInfo(kClient1Id, kService1Id, kShader1Type); + // Check shader got created. + ShaderManager::ShaderInfo* info1 = manager_.GetShaderInfo(kClient1Id); + ASSERT_TRUE(info1 != NULL); + EXPECT_CALL(*gl_, DeleteShader(kService1Id)) + .Times(1) + .RetiresOnSaturation(); + manager_.Destroy(true); + // Check that resources got freed. + info1 = manager_.GetShaderInfo(kClient1Id); + ASSERT_TRUE(info1 == NULL); +} + } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 73c3480..da4b8a561 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc @@ -58,6 +58,24 @@ static size_t FaceIndexToGLTarget(size_t index) { } } +TextureManager::~TextureManager() { + DCHECK(texture_infos_.empty()); +} + +void TextureManager::Destroy(bool have_context) { + while (!texture_infos_.empty()) { + if (have_context) { + TextureInfo* info = texture_infos_.begin()->second; + if (!info->IsDeleted()) { + GLuint service_id = info->service_id(); + glDeleteTextures(1, &service_id); + info->MarkAsDeleted(); + } + } + texture_infos_.erase(texture_infos_.begin()); + } +} + bool TextureManager::TextureInfo::CanRender() const { if (target_ == 0 || IsDeleted()) { return false; diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index a2d70dd..1df58c4 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h @@ -195,6 +195,10 @@ class TextureManager { TextureManager(GLsizei max_texture_size, GLsizei max_cube_map_texture_size); + ~TextureManager(); + + // Must call before destruction. + void Destroy(bool have_context); // Returns the maximum number of levels. GLint MaxLevelsForTarget(GLenum target) const { diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc index 97cfd02..417454b 100644 --- a/gpu/command_buffer/service/texture_manager_unittest.cc +++ b/gpu/command_buffer/service/texture_manager_unittest.cc @@ -3,8 +3,12 @@ // found in the LICENSE file. #include "gpu/command_buffer/service/texture_manager.h" +#include "base/scoped_ptr.h" +#include "app/gfx/gl/gl_mock.h" #include "testing/gtest/include/gtest/gtest.h" +using ::testing::Pointee; + namespace gpu { namespace gles2 { @@ -19,13 +23,23 @@ class TextureManagerTest : public testing::Test { : manager_(kMaxTextureSize, kMaxCubeMapTextureSize) { } + ~TextureManagerTest() { + manager_.Destroy(false); + } + protected: virtual void SetUp() { + gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); + ::gfx::GLInterface::SetGLInterface(gl_.get()); } virtual void TearDown() { + ::gfx::GLInterface::SetGLInterface(NULL); + gl_.reset(); } + // Use StrictMock to make 100% sure we know how GL will be called. + scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; TextureManager manager_; }; @@ -60,6 +74,24 @@ TEST_F(TextureManagerTest, Basic) { EXPECT_TRUE(manager_.GetTextureInfo(kClient1Id) == NULL); } +TEST_F(TextureManagerTest, Destroy) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + EXPECT_FALSE(manager_.HaveUnrenderableTextures()); + // Check we can create texture. + manager_.CreateTextureInfo(kClient1Id, kService1Id); + // Check texture got created. + TextureManager::TextureInfo* info1 = manager_.GetTextureInfo(kClient1Id); + ASSERT_TRUE(info1 != NULL); + EXPECT_CALL(*gl_, DeleteTextures(1, ::testing::Pointee(kService1Id))) + .Times(1) + .RetiresOnSaturation(); + manager_.Destroy(true); + // Check that resources got freed. + info1 = manager_.GetTextureInfo(kClient1Id); + ASSERT_TRUE(info1 == NULL); +} + TEST_F(TextureManagerTest, MaxValues) { // Check we get the right values for the max sizes. EXPECT_EQ(kMax2dLevels, manager_.MaxLevelsForTarget(GL_TEXTURE_2D)); @@ -126,17 +158,26 @@ class TextureInfoTest : public testing::Test { TextureInfoTest() : manager_(kMaxTextureSize, kMaxCubeMapTextureSize) { } + ~TextureInfoTest() { + manager_.Destroy(false); + } protected: virtual void SetUp() { + gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); + ::gfx::GLInterface::SetGLInterface(gl_.get()); manager_.CreateTextureInfo(kClient1Id, kService1Id); info_ = manager_.GetTextureInfo(kClient1Id); ASSERT_TRUE(info_ != NULL); } virtual void TearDown() { + ::gfx::GLInterface::SetGLInterface(NULL); + gl_.reset(); } + // Use StrictMock to make 100% sure we know how GL will be called. + scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; TextureManager manager_; TextureManager::TextureInfo* info_; }; |