summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-13 20:06:14 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-13 20:06:14 +0000
commitca488e19c17583ada1af51e2e27393981e4be772 (patch)
tree9dc186beeffea7cb3d5e35a868fb92fc76f62820
parent1ad2a1dbcde42412bb92c83fe5e0d6999ed00311 (diff)
downloadchromium_src-ca488e19c17583ada1af51e2e27393981e4be772.zip
chromium_src-ca488e19c17583ada1af51e2e27393981e4be772.tar.gz
chromium_src-ca488e19c17583ada1af51e2e27393981e4be772.tar.bz2
Make shader and program object lifetimes match OpenGL ES spec.
TEST=unit tests BUG=65705 Review URL: http://codereview.chromium.org/5676003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69039 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc30
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc53
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc18
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc16
-rw-r--r--gpu/command_buffer/service/program_manager.cc68
-rw-r--r--gpu/command_buffer/service/program_manager.h39
-rw-r--r--gpu/command_buffer/service/program_manager_unittest.cc142
-rw-r--r--gpu/command_buffer/service/shader_manager.cc39
-rw-r--r--gpu/command_buffer/service/shader_manager.h35
-rw-r--r--gpu/command_buffer/service/shader_manager_unittest.cc86
10 files changed, 429 insertions, 97 deletions
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 4e75be9..aa7f69d 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -59,6 +59,34 @@ class NonSharedIdHandler : public IdHandlerInterface {
IdAllocator id_allocator_;
};
+// An id handler for non-shared ids that are never reused.
+class NonSharedNonReusedIdHandler : public IdHandlerInterface {
+ public:
+ NonSharedNonReusedIdHandler() : last_id_(0) { }
+ virtual ~NonSharedNonReusedIdHandler() { }
+
+ // Overridden from IdHandlerInterface.
+ virtual void MakeIds(GLuint id_offset, GLsizei n, GLuint* ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ ids[ii] = ++last_id_ + id_offset;
+ }
+ }
+
+ // Overridden from IdHandlerInterface.
+ virtual void FreeIds(GLsizei /* n */, const GLuint* /* ids */) {
+ // Ids are never freed.
+ }
+
+ // Overridden from IdHandlerInterface.
+ virtual bool MarkAsUsedForBind(GLuint /* id */) {
+ // This is only used for Shaders and Programs which have no bind.
+ return false;
+ }
+
+ private:
+ GLuint last_id_;
+};
+
// An id handler for shared ids.
class SharedIdHandler : public IdHandlerInterface {
public:
@@ -439,7 +467,7 @@ GLES2Implementation::GLES2Implementation(
buffer_id_handler_.reset(new NonSharedIdHandler());
framebuffer_id_handler_.reset(new NonSharedIdHandler());
renderbuffer_id_handler_.reset(new NonSharedIdHandler());
- program_and_shader_id_handler_.reset(new NonSharedIdHandler());
+ program_and_shader_id_handler_.reset(new NonSharedNonReusedIdHandler());
texture_id_handler_.reset(new NonSharedIdHandler());
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 4d13583..73cc483 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -850,9 +850,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// Gets the program info for the given program. Returns NULL if none exists.
ProgramManager::ProgramInfo* GetProgramInfo(GLuint client_id) {
- ProgramManager::ProgramInfo* info =
- program_manager()->GetProgramInfo(client_id);
- return (info && !info->IsDeleted()) ? info : NULL;
+ return program_manager()->GetProgramInfo(client_id);
}
// Gets the program info for the given program. If it's not a program
@@ -874,11 +872,6 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
}
- // Deletes the program info for the given program.
- void RemoveProgramInfo(GLuint client_id) {
- program_manager()->RemoveProgramInfo(client_id);
- }
-
// Creates a ShaderInfo for the given shader.
void CreateShaderInfo(GLuint client_id,
GLuint service_id,
@@ -888,9 +881,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// Gets the shader info for the given shader. Returns NULL if none exists.
ShaderManager::ShaderInfo* GetShaderInfo(GLuint client_id) {
- ShaderManager::ShaderInfo* info =
- shader_manager()->GetShaderInfo(client_id);
- return (info && !info->IsDeleted()) ? info : NULL;
+ return shader_manager()->GetShaderInfo(client_id);
}
// Gets the shader info for the given shader. If it's not a shader generates a
@@ -912,11 +903,6 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
return info;
}
- // Deletes the shader info for the given shader.
- void RemoveShaderInfo(GLuint client_id) {
- shader_manager()->RemoveShaderInfo(client_id);
- }
-
// Creates a buffer info for the given buffer.
void CreateBufferInfo(GLuint client_id, GLuint service_id) {
return buffer_manager()->CreateBufferInfo(client_id, service_id);
@@ -2474,6 +2460,11 @@ void GLES2DecoderImpl::Destroy() {
group_->set_have_context(have_context);
if (have_context) {
+ if (current_program_) {
+ program_manager()->UnuseProgram(shader_manager(), current_program_);
+ current_program_ = NULL;
+ }
+
if (attrib_0_buffer_id_) {
glDeleteBuffersARB(1, &attrib_0_buffer_id_);
}
@@ -3157,8 +3148,10 @@ error::Error GLES2DecoderImpl::HandleDeleteShader(
if (client_id) {
ShaderManager::ShaderInfo* info = GetShaderInfo(client_id);
if (info) {
- glDeleteShader(info->service_id());
- RemoveShaderInfo(client_id);
+ if (!info->IsDeleted()) {
+ glDeleteShader(info->service_id());
+ shader_manager()->MarkAsDeleted(info);
+ }
} else {
SetGLError(GL_INVALID_VALUE, "glDeleteShader: unknown shader");
}
@@ -3172,8 +3165,10 @@ error::Error GLES2DecoderImpl::HandleDeleteProgram(
if (client_id) {
ProgramManager::ProgramInfo* info = GetProgramInfo(client_id);
if (info) {
- glDeleteProgram(info->service_id());
- RemoveProgramInfo(client_id);
+ if (!info->IsDeleted()) {
+ glDeleteProgram(info->service_id());
+ program_manager()->MarkAsDeleted(shader_manager(), info);
+ }
} else {
SetGLError(GL_INVALID_VALUE, "glDeleteProgram: unknown program");
}
@@ -3695,13 +3690,13 @@ void GLES2DecoderImpl::DoTexParameteriv(
}
bool GLES2DecoderImpl::CheckCurrentProgram(const char* function_name) {
- if (!current_program_ || current_program_->IsDeleted()) {
+ if (!current_program_) {
// The program does not exist.
SetGLError(GL_INVALID_OPERATION,
(std::string(function_name) + ": no program in use").c_str());
return false;
}
- if (!current_program_->IsValid()) {
+ if (!current_program_->InUse()) {
SetGLError(GL_INVALID_OPERATION,
(std::string(function_name) + ": program not linked").c_str());
return false;
@@ -3834,7 +3829,13 @@ void GLES2DecoderImpl::DoUseProgram(GLuint program) {
}
service_id = info->service_id();
}
+ if (current_program_) {
+ program_manager()->UnuseProgram(shader_manager(), current_program_);
+ }
current_program_ = info;
+ if (current_program_) {
+ program_manager()->UseProgram(current_program_);
+ }
glUseProgram(service_id);
}
@@ -3881,7 +3882,6 @@ void GLES2DecoderImpl::ClearRealGLErrors() {
bool GLES2DecoderImpl::SetBlackTextureForNonRenderableTextures() {
DCHECK(current_program_);
- DCHECK(!current_program_->IsDeleted());
// Only check if there are some unrenderable textures.
if (!texture_manager()->HaveUnrenderableTextures()) {
return false;
@@ -3918,7 +3918,6 @@ bool GLES2DecoderImpl::SetBlackTextureForNonRenderableTextures() {
void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() {
DCHECK(current_program_);
- DCHECK(!current_program_->IsDeleted());
const ProgramManager::ProgramInfo::SamplerIndices& sampler_indices =
current_program_->sampler_indices();
for (size_t ii = 0; ii < sampler_indices.size(); ++ii) {
@@ -3954,7 +3953,7 @@ bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) {
// it could never be invalid since glUseProgram would have failed. While
// glLinkProgram could later mark the program as invalid the previous
// valid program will still function if it is still the current program.
- if (!current_program_ || current_program_->IsDeleted()) {
+ if (!current_program_) {
// The program does not exist.
// But GL says no ERROR.
return false;
@@ -4418,7 +4417,7 @@ void GLES2DecoderImpl::DoAttachShader(
if (!shader_info) {
return;
}
- if (!program_info->AttachShader(shader_info)) {
+ if (!program_info->AttachShader(shader_manager(), shader_info)) {
SetGLError(GL_INVALID_OPERATION,
"glAttachShader: can not attach more than"
" one shader of the same type.");
@@ -4439,8 +4438,8 @@ void GLES2DecoderImpl::DoDetachShader(
if (!shader_info) {
return;
}
- program_info->DetachShader(shader_info);
glDetachShader(program_info->service_id(), shader_info->service_id());
+ program_info->DetachShader(shader_manager(), shader_info);
}
void GLES2DecoderImpl::DoValidateProgram(GLuint program_client_id) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 6129525..46a70ae 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -172,14 +172,14 @@ TEST_F(GLES2DecoderWithShaderTest, DrawArraysDeletedBufferFails) {
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
-TEST_F(GLES2DecoderWithShaderTest,
- DrawArraysDeletedProgramSucceedsWithoutGLCall) {
- SetupVertexBuffer();
- DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysDeletedProgramSucceeds) {
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
DoDeleteProgram(client_program_id_, kServiceProgramId);
EXPECT_CALL(*gl_, DrawArrays(_, _, _))
- .Times(0);
+ .Times(1)
+ .RetiresOnSaturation();
DrawArrays cmd;
cmd.Init(GL_TRIANGLES, 0, kNumVertices);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
@@ -330,14 +330,14 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedBufferFails) {
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
-TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedProgramSucceedsNoGLCall) {
- SetupVertexBuffer();
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedProgramSucceeds) {
+ SetupTexture();
SetupIndexBuffer();
- DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+ AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0);
DoDeleteProgram(client_program_id_, kServiceProgramId);
EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
- .Times(0);
+ .Times(1);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
index 75597fa..e589e6d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
@@ -60,8 +60,7 @@ void GLES2DecoderTestBase::SpecializedSetup<CopyTexImage2D, 0>(
};
template <>
-void GLES2DecoderTestBase::SpecializedSetup<CopyTexSubImage2D, 0>(
- bool valid) {
+void GLES2DecoderTestBase::SpecializedSetup<CopyTexSubImage2D, 0>(bool valid) {
if (valid) {
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(
@@ -71,6 +70,19 @@ void GLES2DecoderTestBase::SpecializedSetup<CopyTexSubImage2D, 0>(
};
template <>
+void GLES2DecoderTestBase::SpecializedSetup<DetachShader, 0>(bool valid) {
+ if (valid) {
+ EXPECT_CALL(*gl_,
+ AttachShader(kServiceProgramId, kServiceShaderId))
+ .Times(1)
+ .RetiresOnSaturation();
+ AttachShader attach_cmd;
+ attach_cmd.Init(client_program_id_, client_shader_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
+ }
+};
+
+template <>
void GLES2DecoderTestBase::SpecializedSetup<FramebufferRenderbuffer, 0>(
bool valid) {
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 596c8c9..339aff5 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -44,7 +44,8 @@ bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) {
}
ProgramManager::ProgramInfo::ProgramInfo(GLuint service_id)
- : max_attrib_name_length_(0),
+ : use_count_(0),
+ max_attrib_name_length_(0),
max_uniform_name_length_(0),
service_id_(service_id),
valid_(false) {
@@ -356,18 +357,35 @@ void ProgramManager::ProgramInfo::GetProgramiv(GLenum pname, GLint* params) {
}
bool ProgramManager::ProgramInfo::AttachShader(
+ ShaderManager* shader_manager,
ShaderManager::ShaderInfo* info) {
+ DCHECK(shader_manager);
+ DCHECK(info);
int index = ShaderTypeToIndex(info->shader_type());
if (attached_shaders_[index] != NULL) {
return false;
}
attached_shaders_[index] = ShaderManager::ShaderInfo::Ref(info);
+ shader_manager->UseShader(info);
return true;
}
void ProgramManager::ProgramInfo::DetachShader(
+ ShaderManager* shader_manager,
ShaderManager::ShaderInfo* info) {
+ DCHECK(shader_manager);
+ DCHECK(info);
attached_shaders_[ShaderTypeToIndex(info->shader_type())] = NULL;
+ shader_manager->UnuseShader(info);
+}
+
+void ProgramManager::ProgramInfo::DetachShaders(ShaderManager* shader_manager) {
+ DCHECK(shader_manager);
+ for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+ if (attached_shaders_[ii]) {
+ DetachShader(shader_manager, attached_shaders_[ii]);
+ }
+ }
}
bool ProgramManager::ProgramInfo::CanLink() const {
@@ -413,14 +431,6 @@ ProgramManager::ProgramInfo* ProgramManager::GetProgramInfo(GLuint client_id) {
return it != program_infos_.end() ? it->second : NULL;
}
-void ProgramManager::RemoveProgramInfo(GLuint client_id) {
- ProgramInfoMap::iterator it = program_infos_.find(client_id);
- if (it != program_infos_.end()) {
- it->second->MarkAsDeleted();
- program_infos_.erase(it);
- }
-}
-
bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
// This doesn't need to be fast. It's only used during slow queries.
for (ProgramInfoMap::const_iterator it = program_infos_.begin();
@@ -433,6 +443,46 @@ bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
return false;
}
+void ProgramManager::RemoveProgramInfoIfUnused(
+ ShaderManager* shader_manager, ProgramInfo* info) {
+ DCHECK(shader_manager);
+ DCHECK(info);
+ if (info->IsDeleted() && !info->InUse()) {
+ info->DetachShaders(shader_manager);
+ for (ProgramInfoMap::iterator it = program_infos_.begin();
+ it != program_infos_.end(); ++it) {
+ if (it->second->service_id() == info->service_id()) {
+ program_infos_.erase(it);
+ return;
+ }
+ }
+ NOTREACHED();
+ }
+}
+
+void ProgramManager::MarkAsDeleted(
+ ShaderManager* shader_manager,
+ ProgramManager::ProgramInfo* info) {
+ DCHECK(shader_manager);
+ DCHECK(info);
+ info->MarkAsDeleted();
+ RemoveProgramInfoIfUnused(shader_manager, info);
+}
+
+void ProgramManager::UseProgram(ProgramManager::ProgramInfo* info) {
+ DCHECK(info);
+ info->IncUseCount();
+}
+
+void ProgramManager::UnuseProgram(
+ ShaderManager* shader_manager,
+ ProgramManager::ProgramInfo* info) {
+ DCHECK(shader_manager);
+ DCHECK(info);
+ info->DecUseCount();
+ RemoveProgramInfoIfUnused(shader_manager, info);
+}
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index 53893b3..b7229d9 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
#include "base/basictypes.h"
+#include "base/logging.h"
#include "base/ref_counted.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/shader_manager.h"
@@ -130,8 +131,8 @@ class ProgramManager {
return valid_;
}
- bool AttachShader(ShaderManager::ShaderInfo* info);
- void DetachShader(ShaderManager::ShaderInfo* info);
+ bool AttachShader(ShaderManager* manager, ShaderManager::ShaderInfo* info);
+ void DetachShader(ShaderManager* manager, ShaderManager::ShaderInfo* info);
bool CanLink() const;
@@ -143,13 +144,28 @@ class ProgramManager {
log_info_ = str;
}
+ bool InUse() const {
+ DCHECK_GE(use_count_, 0);
+ return use_count_ != 0;
+ }
+
private:
friend class base::RefCounted<ProgramInfo>;
friend class ProgramManager;
~ProgramInfo();
+ void IncUseCount() {
+ ++use_count_;
+ }
+
+ void DecUseCount() {
+ --use_count_;
+ DCHECK_GE(use_count_, 0);
+ }
+
void MarkAsDeleted() {
+ DCHECK_NE(service_id_, 0u);
service_id_ = 0;
}
@@ -160,6 +176,10 @@ class ProgramManager {
bool use_uniforms, const std::string& name, std::string* corrected_name,
GLsizei* size, GLenum* type) const;
+ void DetachShaders(ShaderManager* manager);
+
+ int use_count_;
+
GLsizei max_attrib_name_length_;
// Attrib by index.
@@ -204,12 +224,18 @@ class ProgramManager {
// Gets a program info
ProgramInfo* GetProgramInfo(GLuint client_id);
- // Deletes the program info for the given program.
- void RemoveProgramInfo(GLuint client_id);
-
// Gets a client id for a given service id.
bool GetClientId(GLuint service_id, GLuint* client_id) const;
+ // Marks a program as deleted. If it is not used the info will be deleted.
+ void MarkAsDeleted(ShaderManager* shader_manager, ProgramInfo* info);
+
+ // Marks a program as used.
+ void UseProgram(ProgramInfo* info);
+
+ // Makes a program as unused. If deleted the program info will be removed.
+ void UnuseProgram(ShaderManager* shader_manager, ProgramInfo* info);
+
// Returns true if prefix is invalid for gl.
static bool IsInvalidPrefix(const char* name, size_t length);
@@ -219,6 +245,9 @@ class ProgramManager {
typedef std::map<GLuint, ProgramInfo::Ref> ProgramInfoMap;
ProgramInfoMap program_infos_;
+ void RemoveProgramInfoIfUnused(
+ ShaderManager* shader_manager, ProgramInfo* info);
+
DISALLOW_COPY_AND_ASSIGN(ProgramManager);
};
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 7f4fa21..788e18c 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -61,19 +61,11 @@ TEST_F(ProgramManagerTest, Basic) {
// Check program got created.
ProgramManager::ProgramInfo* info1 = manager_.GetProgramInfo(kClient1Id);
ASSERT_TRUE(info1 != NULL);
- EXPECT_EQ(kService1Id, info1->service_id());
- EXPECT_FALSE(info1->CanLink());
- EXPECT_STREQ("", info1->log_info().c_str());
GLuint client_id = 0;
EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id));
EXPECT_EQ(kClient1Id, client_id);
// Check we get nothing for a non-existent program.
EXPECT_TRUE(manager_.GetProgramInfo(kClient2Id) == NULL);
- // Check trying to a remove non-existent programs does not crash.
- manager_.RemoveProgramInfo(kClient2Id);
- // Check we can't get the program after we remove it.
- manager_.RemoveProgramInfo(kClient1Id);
- EXPECT_TRUE(manager_.GetProgramInfo(kClient1Id) == NULL);
}
TEST_F(ProgramManagerTest, Destroy) {
@@ -94,6 +86,22 @@ TEST_F(ProgramManagerTest, Destroy) {
ASSERT_TRUE(info1 == NULL);
}
+TEST_F(ProgramManagerTest, ProgramInfo) {
+ 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_EQ(kService1Id, info1->service_id());
+ EXPECT_FALSE(info1->InUse());
+ EXPECT_FALSE(info1->IsValid());
+ EXPECT_FALSE(info1->IsDeleted());
+ EXPECT_FALSE(info1->CanLink());
+ EXPECT_STREQ("", info1->log_info().c_str());
+}
+
class ProgramManagerWithShaderTest : public testing::Test {
public:
ProgramManagerWithShaderTest()
@@ -431,19 +439,19 @@ TEST_F(ProgramManagerWithShaderTest, AttachDetachShader) {
ShaderManager::ShaderInfo* fshader = shader_manager.GetShaderInfo(
kFShaderClientId);
fshader->SetStatus(true, "", NULL);
- EXPECT_TRUE(program_info->AttachShader(vshader));
+ EXPECT_TRUE(program_info->AttachShader(&shader_manager, vshader));
EXPECT_FALSE(program_info->CanLink());
- EXPECT_TRUE(program_info->AttachShader(fshader));
+ EXPECT_TRUE(program_info->AttachShader(&shader_manager, fshader));
EXPECT_TRUE(program_info->CanLink());
- program_info->DetachShader(vshader);
+ program_info->DetachShader(&shader_manager, vshader);
EXPECT_FALSE(program_info->CanLink());
- EXPECT_TRUE(program_info->AttachShader(vshader));
+ EXPECT_TRUE(program_info->AttachShader(&shader_manager, vshader));
EXPECT_TRUE(program_info->CanLink());
- program_info->DetachShader(fshader);
+ program_info->DetachShader(&shader_manager, fshader);
EXPECT_FALSE(program_info->CanLink());
- EXPECT_FALSE(program_info->AttachShader(vshader));
+ EXPECT_FALSE(program_info->AttachShader(&shader_manager, vshader));
EXPECT_FALSE(program_info->CanLink());
- EXPECT_TRUE(program_info->AttachShader(fshader));
+ EXPECT_TRUE(program_info->AttachShader(&shader_manager, fshader));
EXPECT_TRUE(program_info->CanLink());
vshader->SetStatus(false, "", NULL);
EXPECT_FALSE(program_info->CanLink());
@@ -585,7 +593,7 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsWrongTypeInfo) {
ProgramManager::ProgramInfo* program_info =
manager_.GetProgramInfo(kClientProgramId);
ASSERT_TRUE(program_info != NULL);
- EXPECT_TRUE(program_info->AttachShader(shader_info));
+ EXPECT_TRUE(program_info->AttachShader(&shader_manager, shader_info));
program_info->Update();
// Check that we got the good type, not the bad.
// Check Attribs
@@ -615,6 +623,108 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsWrongTypeInfo) {
shader_manager.Destroy(false);
}
+TEST_F(ProgramManagerWithShaderTest, ProgramInfoUseCount) {
+ ShaderManager shader_manager;
+ ProgramManager::ProgramInfo* program_info =
+ manager_.GetProgramInfo(kClientProgramId);
+ ASSERT_TRUE(program_info != NULL);
+ EXPECT_FALSE(program_info->CanLink());
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+ shader_manager.CreateShaderInfo(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ShaderManager::ShaderInfo* vshader = shader_manager.GetShaderInfo(
+ kVShaderClientId);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, "", NULL);
+ shader_manager.CreateShaderInfo(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ShaderManager::ShaderInfo* fshader = shader_manager.GetShaderInfo(
+ kFShaderClientId);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, "", NULL);
+ EXPECT_FALSE(vshader->InUse());
+ EXPECT_FALSE(fshader->InUse());
+ EXPECT_TRUE(program_info->AttachShader(&shader_manager, vshader));
+ EXPECT_TRUE(vshader->InUse());
+ EXPECT_TRUE(program_info->AttachShader(&shader_manager, fshader));
+ EXPECT_TRUE(fshader->InUse());
+ EXPECT_TRUE(program_info->CanLink());
+ EXPECT_FALSE(program_info->InUse());
+ EXPECT_FALSE(program_info->IsDeleted());
+ manager_.UseProgram(program_info);
+ EXPECT_TRUE(program_info->InUse());
+ manager_.UseProgram(program_info);
+ EXPECT_TRUE(program_info->InUse());
+ manager_.MarkAsDeleted(&shader_manager, program_info);
+ EXPECT_TRUE(program_info->IsDeleted());
+ ProgramManager::ProgramInfo* info2 =
+ manager_.GetProgramInfo(kClientProgramId);
+ EXPECT_EQ(program_info, info2);
+ manager_.UnuseProgram(&shader_manager, program_info);
+ EXPECT_TRUE(program_info->InUse());
+ // this should delete the info.
+ manager_.UnuseProgram(&shader_manager, program_info);
+ info2 = manager_.GetProgramInfo(kClientProgramId);
+ EXPECT_TRUE(info2 == NULL);
+ EXPECT_FALSE(vshader->InUse());
+ EXPECT_FALSE(fshader->InUse());
+ shader_manager.Destroy(false);
+}
+
+TEST_F(ProgramManagerWithShaderTest, ProgramInfoUseCount2) {
+ ShaderManager shader_manager;
+ ProgramManager::ProgramInfo* program_info =
+ manager_.GetProgramInfo(kClientProgramId);
+ ASSERT_TRUE(program_info != NULL);
+ EXPECT_FALSE(program_info->CanLink());
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+ shader_manager.CreateShaderInfo(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ShaderManager::ShaderInfo* vshader = shader_manager.GetShaderInfo(
+ kVShaderClientId);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, "", NULL);
+ shader_manager.CreateShaderInfo(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ShaderManager::ShaderInfo* fshader = shader_manager.GetShaderInfo(
+ kFShaderClientId);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, "", NULL);
+ EXPECT_FALSE(vshader->InUse());
+ EXPECT_FALSE(fshader->InUse());
+ EXPECT_TRUE(program_info->AttachShader(&shader_manager, vshader));
+ EXPECT_TRUE(vshader->InUse());
+ EXPECT_TRUE(program_info->AttachShader(&shader_manager, fshader));
+ EXPECT_TRUE(fshader->InUse());
+ EXPECT_TRUE(program_info->CanLink());
+ EXPECT_FALSE(program_info->InUse());
+ EXPECT_FALSE(program_info->IsDeleted());
+ manager_.UseProgram(program_info);
+ EXPECT_TRUE(program_info->InUse());
+ manager_.UseProgram(program_info);
+ EXPECT_TRUE(program_info->InUse());
+ manager_.UnuseProgram(&shader_manager, program_info);
+ EXPECT_TRUE(program_info->InUse());
+ manager_.UnuseProgram(&shader_manager, program_info);
+ EXPECT_FALSE(program_info->InUse());
+ ProgramManager::ProgramInfo* info2 =
+ manager_.GetProgramInfo(kClientProgramId);
+ EXPECT_EQ(program_info, info2);
+ // this should delete the program.
+ manager_.MarkAsDeleted(&shader_manager, program_info);
+ info2 = manager_.GetProgramInfo(kClientProgramId);
+ EXPECT_TRUE(info2 == NULL);
+ EXPECT_FALSE(vshader->InUse());
+ EXPECT_FALSE(fshader->InUse());
+ shader_manager.Destroy(false);
+}
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc
index 794c75e..59fad72 100644
--- a/gpu/command_buffer/service/shader_manager.cc
+++ b/gpu/command_buffer/service/shader_manager.cc
@@ -68,14 +68,6 @@ ShaderManager::ShaderInfo* ShaderManager::GetShaderInfo(GLuint client_id) {
return it != shader_infos_.end() ? it->second : NULL;
}
-void ShaderManager::RemoveShaderInfo(GLuint client_id) {
- ShaderInfoMap::iterator it = shader_infos_.find(client_id);
- if (it != shader_infos_.end()) {
- it->second->MarkAsDeleted();
- shader_infos_.erase(it);
- }
-}
-
bool ShaderManager::GetClientId(GLuint service_id, GLuint* client_id) const {
// This doesn't need to be fast. It's only used during slow queries.
for (ShaderInfoMap::const_iterator it = shader_infos_.begin();
@@ -88,6 +80,37 @@ bool ShaderManager::GetClientId(GLuint service_id, GLuint* client_id) const {
return false;
}
+void ShaderManager::RemoveShaderInfoIfUnused(ShaderManager::ShaderInfo* info) {
+ DCHECK(info);
+ if (info->IsDeleted() && !info->InUse()) {
+ for (ShaderInfoMap::iterator it = shader_infos_.begin();
+ it != shader_infos_.end(); ++it) {
+ if (it->second->service_id() == info->service_id()) {
+ shader_infos_.erase(it);
+ return;
+ }
+ }
+ NOTREACHED();
+ }
+}
+
+void ShaderManager::MarkAsDeleted(ShaderManager::ShaderInfo* info) {
+ DCHECK(info);
+ info->MarkAsDeleted();
+ RemoveShaderInfoIfUnused(info);
+}
+
+void ShaderManager::UseShader(ShaderManager::ShaderInfo* info) {
+ DCHECK(info);
+ info->IncUseCount();
+}
+
+void ShaderManager::UnuseShader(ShaderManager::ShaderInfo* info) {
+ DCHECK(info);
+ info->DecUseCount();
+ RemoveShaderInfoIfUnused(info);
+}
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h
index 0b173c3..60aca6c 100644
--- a/gpu/command_buffer/service/shader_manager.h
+++ b/gpu/command_buffer/service/shader_manager.h
@@ -8,6 +8,7 @@
#include <map>
#include <string>
#include "base/basictypes.h"
+#include "base/logging.h"
#include "base/ref_counted.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/shader_translator.h"
@@ -31,7 +32,8 @@ class ShaderManager {
typedef ShaderTranslator::VariableInfo VariableInfo;
explicit ShaderInfo(GLuint service_id, GLenum shader_type)
- : service_id_(service_id),
+ : use_count_(0),
+ service_id_(service_id),
shader_type_(shader_type),
valid_(false) {
}
@@ -71,6 +73,11 @@ class ShaderManager {
return service_id_ == 0;
}
+ bool InUse() const {
+ DCHECK_GE(use_count_, 0);
+ return use_count_ != 0;
+ }
+
private:
typedef ShaderTranslator::VariableMap VariableMap;
@@ -78,10 +85,22 @@ class ShaderManager {
friend class ShaderManager;
~ShaderInfo() { }
+ void IncUseCount() {
+ ++use_count_;
+ }
+
+ void DecUseCount() {
+ --use_count_;
+ DCHECK_GE(use_count_, 0);
+ }
+
void MarkAsDeleted() {
+ DCHECK_NE(service_id_, 0u);
service_id_ = 0;
}
+ int use_count_;
+
// The shader this ShaderInfo is tracking.
GLuint service_id_;
// Type of shader - GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
@@ -116,17 +135,25 @@ class ShaderManager {
// exists.
ShaderInfo* GetShaderInfo(GLuint client_id);
- // Deletes the shader info for the given shader.
- void RemoveShaderInfo(GLuint client_id);
-
// Gets a client id for a given service id.
bool GetClientId(GLuint service_id, GLuint* client_id) const;
+ void MarkAsDeleted(ShaderInfo* info);
+
+ // Mark a shader as used
+ void UseShader(ShaderInfo* info);
+
+ // Unmark a shader as used. If it has been deleted and is not used
+ // then we free the info.
+ void UnuseShader(ShaderInfo* info);
+
private:
// Info for each shader by service side shader Id.
typedef std::map<GLuint, ShaderInfo::Ref> ShaderInfoMap;
ShaderInfoMap shader_infos_;
+ void RemoveShaderInfoIfUnused(ShaderInfo* info);
+
DISALLOW_COPY_AND_ASSIGN(ShaderManager);
};
diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc
index c069257..344cefd 100644
--- a/gpu/command_buffer/service/shader_manager_unittest.cc
+++ b/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -44,31 +44,16 @@ TEST_F(ShaderManagerTest, Basic) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
const GLenum kShader1Type = GL_VERTEX_SHADER;
- const std::string kClient1Source("hello world");
const GLuint kClient2Id = 2;
// 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_EQ(kService1Id, info1->service_id());
- // Check if the shader has correct type.
- EXPECT_EQ(kShader1Type, info1->shader_type());
- EXPECT_FALSE(info1->IsValid());
- EXPECT_STREQ("", info1->log_info().c_str());
- const char* kLog = "foo";
- info1->SetStatus(true, kLog, NULL);
- EXPECT_TRUE(info1->IsValid());
- EXPECT_STREQ(kLog, info1->log_info().c_str());
- // Check we can set its source.
- info1->Update(kClient1Source);
- EXPECT_STREQ(kClient1Source.c_str(), info1->source().c_str());
// Check we get nothing for a non-existent shader.
EXPECT_TRUE(manager_.GetShaderInfo(kClient2Id) == NULL);
- // Check trying to a remove non-existent shaders does not crash.
- manager_.RemoveShaderInfo(kClient2Id);
// Check we can't get the shader after we remove it.
- manager_.RemoveShaderInfo(kClient1Id);
+ manager_.MarkAsDeleted(info1);
EXPECT_TRUE(manager_.GetShaderInfo(kClient1Id) == NULL);
}
@@ -90,6 +75,31 @@ TEST_F(ShaderManagerTest, Destroy) {
ASSERT_TRUE(info1 == NULL);
}
+TEST_F(ShaderManagerTest, ShaderInfo) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kShader1Type = GL_VERTEX_SHADER;
+ const std::string kClient1Source("hello world");
+ // 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_EQ(kService1Id, info1->service_id());
+ // Check if the shader has correct type.
+ EXPECT_EQ(kShader1Type, info1->shader_type());
+ EXPECT_FALSE(info1->IsValid());
+ EXPECT_FALSE(info1->InUse());
+ EXPECT_STREQ("", info1->log_info().c_str());
+ const char* kLog = "foo";
+ info1->SetStatus(true, kLog, NULL);
+ EXPECT_TRUE(info1->IsValid());
+ EXPECT_STREQ(kLog, info1->log_info().c_str());
+ // Check we can set its source.
+ info1->Update(kClient1Source);
+ EXPECT_STREQ(kClient1Source.c_str(), info1->source().c_str());
+}
+
TEST_F(ShaderManagerTest, GetInfo) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
@@ -160,6 +170,50 @@ TEST_F(ShaderManagerTest, GetInfo) {
}
}
+TEST_F(ShaderManagerTest, ShaderInfoUseCount) {
+ 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_FALSE(info1->InUse());
+ EXPECT_FALSE(info1->IsDeleted());
+ manager_.UseShader(info1);
+ EXPECT_TRUE(info1->InUse());
+ manager_.UseShader(info1);
+ EXPECT_TRUE(info1->InUse());
+ manager_.MarkAsDeleted(info1);
+ EXPECT_TRUE(info1->IsDeleted());
+ ShaderManager::ShaderInfo* info2 = manager_.GetShaderInfo(kClient1Id);
+ EXPECT_EQ(info1, info2);
+ manager_.UnuseShader(info1);
+ EXPECT_TRUE(info1->InUse());
+ manager_.UnuseShader(info1); // this should delete the info.
+ info2 = manager_.GetShaderInfo(kClient1Id);
+ EXPECT_TRUE(info2 == NULL);
+
+ manager_.CreateShaderInfo(kClient1Id, kService1Id, kShader1Type);
+ info1 = manager_.GetShaderInfo(kClient1Id);
+ ASSERT_TRUE(info1 != NULL);
+ EXPECT_FALSE(info1->InUse());
+ manager_.UseShader(info1);
+ EXPECT_TRUE(info1->InUse());
+ manager_.UseShader(info1);
+ EXPECT_TRUE(info1->InUse());
+ manager_.UnuseShader(info1);
+ EXPECT_TRUE(info1->InUse());
+ manager_.UnuseShader(info1);
+ EXPECT_FALSE(info1->InUse());
+ info2 = manager_.GetShaderInfo(kClient1Id);
+ EXPECT_EQ(info1, info2);
+ manager_.MarkAsDeleted(info1); // this should delete the shader.
+ info2 = manager_.GetShaderInfo(kClient1Id);
+ EXPECT_TRUE(info2 == NULL);
+}
+
} // namespace gles2
} // namespace gpu