diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-08 17:51:46 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-08 17:51:46 +0000 |
commit | 9a14ae6185d3f43c6fc30239f16c647abc44b366 (patch) | |
tree | 668c2224231e0ba3d5ec41b64479fba5e4d10962 /gpu | |
parent | 4e601fcf25223ca20444bcc22c252d84d5a1621e (diff) | |
download | chromium_src-9a14ae6185d3f43c6fc30239f16c647abc44b366.zip chromium_src-9a14ae6185d3f43c6fc30239f16c647abc44b366.tar.gz chromium_src-9a14ae6185d3f43c6fc30239f16c647abc44b366.tar.bz2 |
Cache OpenGL program info on the client side of the command buffer.
For contexts not sharing resources this means the 3 to 30 calls
to get link status and attrib/uniform locations will go from
3-30 sync calls to 1 sync call.
TEST=unit tests and ran OpenGL ES 2.0 conformance tests
BUG=85966
Review URL: http://codereview.chromium.org/7358006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95836 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rwxr-xr-x | gpu/command_buffer/build_gles2_cmd_buffer.py | 22 | ||||
-rw-r--r-- | gpu/command_buffer/client/gles2_implementation.cc | 150 | ||||
-rw-r--r-- | gpu/command_buffer/client/gles2_implementation.h | 19 | ||||
-rw-r--r-- | gpu/command_buffer/client/gles2_implementation_autogen.h | 54 | ||||
-rw-r--r-- | gpu/command_buffer/client/program_info_manager.cc | 495 | ||||
-rw-r--r-- | gpu/command_buffer/client/program_info_manager.h | 52 | ||||
-rw-r--r-- | gpu/command_buffer/client/program_info_manager_unittest.cc | 32 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 18 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc | 2 | ||||
-rw-r--r-- | gpu/command_buffer/service/program_manager_unittest.cc | 2 | ||||
-rw-r--r-- | gpu/gpu.gyp | 3 |
11 files changed, 753 insertions, 96 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index ee7d6de..c3c023f 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -1489,7 +1489,10 @@ _FUNCTION_INFO = { 'decoder_func': 'DoIsTexture', 'expectation': False, }, - 'LinkProgram': {'decoder_func': 'DoLinkProgram'}, + 'LinkProgram': { + 'decoder_func': 'DoLinkProgram', + 'impl_func': False, + }, 'MapBufferSubDataCHROMIUM': { 'gen_cmd': False, 'extension': True, @@ -3068,7 +3071,7 @@ class DeleteHandler(TypeHandler): arg.WriteClientSideValidationCode(file, func) file.Write( " GPU_CLIENT_DCHECK(%s != 0);\n" % func.GetOriginalArgs()[-1].name) - file.Write(" program_and_shader_id_handler_->FreeIds(1, &%s);\n" % + file.Write(" DeleteProgramOrShaderHelper(%s);\n" % func.GetOriginalArgs()[-1].name) file.Write(" helper_->%s(%s);\n" % (func.name, func.MakeCmdArgString(""))) @@ -4212,19 +4215,20 @@ class STRnHandler(TypeHandler): << static_cast<void*>(%(arg3)s) << ")"); helper_->SetBucketSize(kResultBucketId, 0); helper_->%(func_name)s(%(id_name)s, kResultBucketId); - if (bufsize > 0) { - std::string str; - if (GetBucketAsString(kResultBucketId, &str)) { - GLsizei max_size = + std::string str; + GLsizei max_size = 0; + if (GetBucketAsString(kResultBucketId, &str)) { + if (bufsize > 0) { + max_size = std::min(static_cast<size_t>(%(bufsize_name)s) - 1, str.size()); - if (%(length_name)s != NULL) { - *%(length_name)s = max_size; - } memcpy(%(dest_name)s, str.c_str(), max_size); %(dest_name)s[max_size] = '\\0'; GPU_CLIENT_LOG("------\\n" << %(dest_name)s << "\\n------"); } } + if (%(length_name)s != NULL) { + *%(length_name)s = max_size; + } } """ args = func.GetOriginalArgs() diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index a0f3dd3..d3fcf87 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -9,6 +9,7 @@ #include <GLES2/gl2ext.h> #include <GLES2/gles2_command_buffer.h> #include "../client/mapped_memory.h" +#include "../client/program_info_manager.h" #include "../common/gles2_cmd_utils.h" #include "../common/id_allocator.h" #include "../common/trace_event.h" @@ -514,6 +515,9 @@ GLES2Implementation::GLES2Implementation( texture_units_.reset( new TextureUnit[gl_state_.max_combined_texture_image_units]); + + program_info_manager_.reset(ProgramInfoManager::Create(sharing_resources_)); + #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) buffer_id_handler_->MakeIds( kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]); @@ -949,28 +953,37 @@ void GLES2Implementation::GetVertexAttribPointerv( }); } -GLint GLES2Implementation::GetAttribLocation( +void GLES2Implementation::DeleteProgramOrShaderHelper( + GLuint program_or_shader) { + program_and_shader_id_handler_->FreeIds(1, &program_or_shader); + program_info_manager_->DeleteInfo(program_or_shader); +} + +GLint GLES2Implementation::GetAttribLocationHelper( GLuint program, const char* name) { - GPU_CLIENT_LOG("[" << this << "] glGetAttribLocation(" << program - << ", " << name << ")"); - TRACE_EVENT0("gpu", "GLES2::GetAttribLocation"); typedef GetAttribLocationBucket::Result Result; Result* result = GetResultAs<Result*>(); *result = -1; SetBucketAsCString(kResultBucketId, name); - helper_->GetAttribLocationBucket(program, kResultBucketId, - result_shm_id(), result_shm_offset()); + helper_->GetAttribLocationBucket( + program, kResultBucketId, result_shm_id(), result_shm_offset()); WaitForCmd(); helper_->SetBucketSize(kResultBucketId, 0); - GPU_CLIENT_LOG("returned " << *result); return *result; } -GLint GLES2Implementation::GetUniformLocation( +GLint GLES2Implementation::GetAttribLocation( GLuint program, const char* name) { - GPU_CLIENT_LOG("[" << this << "] glGetUniformLocation(" << program + GPU_CLIENT_LOG("[" << this << "] glGetAttribLocation(" << program << ", " << name << ")"); - TRACE_EVENT0("gpu", "GLES2::GetUniformLocation"); + TRACE_EVENT0("gpu", "GLES2::GetAttribLocation"); + GLint loc = program_info_manager_->GetAttribLocation(this, program, name); + GPU_CLIENT_LOG("returned " << loc); + return loc; +} + +GLint GLES2Implementation::GetUniformLocationHelper( + GLuint program, const char* name) { typedef GetUniformLocationBucket::Result Result; Result* result = GetResultAs<Result*>(); *result = -1; @@ -979,10 +992,29 @@ GLint GLES2Implementation::GetUniformLocation( result_shm_id(), result_shm_offset()); WaitForCmd(); helper_->SetBucketSize(kResultBucketId, 0); - GPU_CLIENT_LOG("returned " << *result); return *result; } +GLint GLES2Implementation::GetUniformLocation( + GLuint program, const char* name) { + GPU_CLIENT_LOG("[" << this << "] glGetUniformLocation(" << program + << ", " << name << ")"); + TRACE_EVENT0("gpu", "GLES2::GetUniformLocation"); + GLint loc = program_info_manager_->GetUniformLocation(this, program, name); + GPU_CLIENT_LOG("returned " << loc); + return loc; +} + +bool GLES2Implementation::GetProgramivHelper( + GLuint program, GLenum pname, GLint* params) { + return program_info_manager_->GetProgramiv(this, program, pname, params); +} + +void GLES2Implementation::LinkProgram(GLuint program) { + GPU_CLIENT_LOG("[" << this << "] glLinkProgram(" << program << ")"); + helper_->LinkProgram(program); + program_info_manager_->CreateInfo(program); +} void GLES2Implementation::ShaderBinary( GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, @@ -1436,21 +1468,10 @@ void GLES2Implementation::TexSubImage2DImpl( } } -void GLES2Implementation::GetActiveAttrib( +bool GLES2Implementation::GetActiveAttribHelper( GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) { - GPU_CLIENT_LOG("[" << this << "] glGetActiveAttrib(" - << program << ", " << index << ", " << bufsize << ", " - << static_cast<const void*>(length) << ", " - << static_cast<const void*>(size) << ", " - << static_cast<const void*>(type) << ", " - << static_cast<const void*>(name) << ", "); - if (bufsize < 0) { - SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib: bufsize < 0"); - return; - } - TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib"); - // Clear the bucket so if we the command fails nothing will be in it. + // Clear the bucket so if the command fails nothing will be in it. helper_->SetBucketSize(kResultBucketId, 0); typedef gles2::GetActiveAttrib::Result Result; Result* result = static_cast<Result*>(result_buffer_); @@ -1462,11 +1483,9 @@ void GLES2Implementation::GetActiveAttrib( if (result->success) { if (size) { *size = result->size; - GPU_CLIENT_LOG(" size: " << *size); } if (type) { *type = result->type; - GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type)); } if (length || name) { std::vector<int8> str; @@ -1480,27 +1499,45 @@ void GLES2Implementation::GetActiveAttrib( if (name && bufsize > 0) { memcpy(name, &str[0], max_size); name[max_size] = '\0'; - GPU_CLIENT_LOG(" name: " << name); } } } + return result->success != 0; } -void GLES2Implementation::GetActiveUniform( +void GLES2Implementation::GetActiveAttrib( GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) { - GPU_CLIENT_LOG("[" << this << "] glGetActiveUniform(" + GPU_CLIENT_LOG("[" << this << "] glGetActiveAttrib(" << program << ", " << index << ", " << bufsize << ", " << static_cast<const void*>(length) << ", " << static_cast<const void*>(size) << ", " << static_cast<const void*>(type) << ", " << static_cast<const void*>(name) << ", "); if (bufsize < 0) { - SetGLError(GL_INVALID_VALUE, "glGetActiveUniform: bufsize < 0"); + SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib: bufsize < 0"); return; } - TRACE_EVENT0("gpu", "GLES2::GetActiveUniform"); - // Clear the bucket so if we the command fails nothing will be in it. + TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib"); + bool success = program_info_manager_->GetActiveAttrib( + this, program, index, bufsize, length, size, type, name); + if (success) { + if (size) { + GPU_CLIENT_LOG(" size: " << *size); + } + if (type) { + GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type)); + } + if (name) { + GPU_CLIENT_LOG(" name: " << name); + } + } +} + +bool GLES2Implementation::GetActiveUniformHelper( + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, + GLenum* type, char* name) { + // Clear the bucket so if the command fails nothing will be in it. helper_->SetBucketSize(kResultBucketId, 0); typedef gles2::GetActiveUniform::Result Result; Result* result = static_cast<Result*>(result_buffer_); @@ -1512,11 +1549,9 @@ void GLES2Implementation::GetActiveUniform( if (result->success) { if (size) { *size = result->size; - GPU_CLIENT_LOG(" size: " << *size); } if (type) { *type = result->type; - GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type)); } if (length || name) { std::vector<int8> str; @@ -1530,10 +1565,39 @@ void GLES2Implementation::GetActiveUniform( if (name && bufsize > 0) { memcpy(name, &str[0], max_size); name[max_size] = '\0'; - GPU_CLIENT_LOG(" name: " << name); } } } + return result->success != 0; +} + +void GLES2Implementation::GetActiveUniform( + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, + GLenum* type, char* name) { + GPU_CLIENT_LOG("[" << this << "] glGetActiveUniform(" + << program << ", " << index << ", " << bufsize << ", " + << static_cast<const void*>(length) << ", " + << static_cast<const void*>(size) << ", " + << static_cast<const void*>(type) << ", " + << static_cast<const void*>(name) << ", "); + if (bufsize < 0) { + SetGLError(GL_INVALID_VALUE, "glGetActiveUniform: bufsize < 0"); + return; + } + TRACE_EVENT0("gpu", "GLES2::GetActiveUniform"); + bool success = program_info_manager_->GetActiveUniform( + this, program, index, bufsize, length, size, type, name); + if (success) { + if (size) { + GPU_CLIENT_LOG(" size: " << *size); + } + if (type) { + GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type)); + } + if (name) { + GPU_CLIENT_LOG(" name: " << name); + } + } } void GLES2Implementation::GetAttachedShaders( @@ -2332,6 +2396,15 @@ void GLES2Implementation::GetMultipleIntegervCHROMIUM( }); } +void GLES2Implementation::GetProgramInfoCHROMIUMHelper( + GLuint program, std::vector<int8>* result) { + GPU_DCHECK(result); + // Clear the bucket so if the command fails nothing will be in it. + helper_->SetBucketSize(kResultBucketId, 0); + helper_->GetProgramInfoCHROMIUM(program, kResultBucketId); + GetBucketContents(kResultBucketId, result); +} + void GLES2Implementation::GetProgramInfoCHROMIUM( GLuint program, GLsizei bufsize, GLsizei* size, void* info) { if (bufsize < 0) { @@ -2345,12 +2418,9 @@ void GLES2Implementation::GetProgramInfoCHROMIUM( // Make sure they've set size to 0 else the value will be undefined on // lost context. GPU_DCHECK(*size == 0); - // Clear the bucket so if the command fails nothing will be in it. - helper_->SetBucketSize(kResultBucketId, 0); - helper_->GetProgramInfoCHROMIUM(program, kResultBucketId); std::vector<int8> result; - GetBucketContents(kResultBucketId, &result); - if (result.size() == 0) { + GetProgramInfoCHROMIUMHelper(program, &result); + if (result.empty()) { return; } *size = result.size(); diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 562910c..9ab625c 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h @@ -75,6 +75,7 @@ class MappedMemoryManager; namespace gles2 { class ClientSideBufferHelper; +class ProgramInfoManager; // Base class for IdHandlers class IdHandlerInterface { @@ -175,6 +176,17 @@ class GLES2Implementation { void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params); void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params); + void GetProgramInfoCHROMIUMHelper(GLuint program, std::vector<int8>* result); + void DeleteProgramOrShaderHelper(GLuint program_or_shader); + GLint GetAttribLocationHelper(GLuint program, const char* name); + GLint GetUniformLocationHelper(GLuint program, const char* name); + bool GetActiveAttribHelper( + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name); + bool GetActiveUniformHelper( + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name); + GLuint MakeTextureId() { GLuint id; texture_id_handler_->MakeIds(0, 1, &id); @@ -479,6 +491,8 @@ class GLES2Implementation { scoped_ptr<MappedMemoryManager> mapped_memory_; + scoped_ptr<ProgramInfoManager> program_info_manager_; + DISALLOW_COPY_AND_ASSIGN(GLES2Implementation); }; @@ -495,11 +509,6 @@ inline bool GLES2Implementation::GetFramebufferAttachmentParameterivHelper( return false; } -inline bool GLES2Implementation::GetProgramivHelper( - GLuint /* program */, GLenum /* pname */, GLint* /* params */) { - return false; -} - inline bool GLES2Implementation::GetRenderbufferParameterivHelper( GLenum /* target */, GLenum /* pname */, GLint* /* params */) { return false; diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 728ef5e..245b726 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -249,7 +249,7 @@ void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { void DeleteProgram(GLuint program) { GPU_CLIENT_LOG("[" << this << "] glDeleteProgram(" << program << ")"); GPU_CLIENT_DCHECK(program != 0); - program_and_shader_id_handler_->FreeIds(1, &program); + DeleteProgramOrShaderHelper(program); helper_->DeleteProgram(program); Flush(); } @@ -278,7 +278,7 @@ void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { void DeleteShader(GLuint shader) { GPU_CLIENT_LOG("[" << this << "] glDeleteShader(" << shader << ")"); GPU_CLIENT_DCHECK(shader != 0); - program_and_shader_id_handler_->FreeIds(1, &shader); + DeleteProgramOrShaderHelper(shader); helper_->DeleteShader(shader); Flush(); } @@ -571,19 +571,20 @@ void GetProgramInfoLog( << static_cast<void*>(infolog) << ")"); helper_->SetBucketSize(kResultBucketId, 0); helper_->GetProgramInfoLog(program, kResultBucketId); - if (bufsize > 0) { - std::string str; - if (GetBucketAsString(kResultBucketId, &str)) { - GLsizei max_size = + std::string str; + GLsizei max_size = 0; + if (GetBucketAsString(kResultBucketId, &str)) { + if (bufsize > 0) { + max_size = std::min(static_cast<size_t>(bufsize) - 1, str.size()); - if (length != NULL) { - *length = max_size; - } memcpy(infolog, str.c_str(), max_size); infolog[max_size] = '\0'; GPU_CLIENT_LOG("------\n" << infolog << "\n------"); } } + if (length != NULL) { + *length = max_size; + } } void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) { GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params); @@ -633,19 +634,20 @@ void GetShaderInfoLog( << static_cast<void*>(infolog) << ")"); helper_->SetBucketSize(kResultBucketId, 0); helper_->GetShaderInfoLog(shader, kResultBucketId); - if (bufsize > 0) { - std::string str; - if (GetBucketAsString(kResultBucketId, &str)) { - GLsizei max_size = + std::string str; + GLsizei max_size = 0; + if (GetBucketAsString(kResultBucketId, &str)) { + if (bufsize > 0) { + max_size = std::min(static_cast<size_t>(bufsize) - 1, str.size()); - if (length != NULL) { - *length = max_size; - } memcpy(infolog, str.c_str(), max_size); infolog[max_size] = '\0'; GPU_CLIENT_LOG("------\n" << infolog << "\n------"); } } + if (length != NULL) { + *length = max_size; + } } void GetShaderPrecisionFormat( GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); @@ -660,19 +662,20 @@ void GetShaderSource( << static_cast<void*>(source) << ")"); helper_->SetBucketSize(kResultBucketId, 0); helper_->GetShaderSource(shader, kResultBucketId); - if (bufsize > 0) { - std::string str; - if (GetBucketAsString(kResultBucketId, &str)) { - GLsizei max_size = + std::string str; + GLsizei max_size = 0; + if (GetBucketAsString(kResultBucketId, &str)) { + if (bufsize > 0) { + max_size = std::min(static_cast<size_t>(bufsize) - 1, str.size()); - if (length != NULL) { - *length = max_size; - } memcpy(source, str.c_str(), max_size); source[max_size] = '\0'; GPU_CLIENT_LOG("------\n" << source << "\n------"); } } + if (length != NULL) { + *length = max_size; + } } const GLubyte* GetString(GLenum name); @@ -809,10 +812,7 @@ void LineWidth(GLfloat width) { helper_->LineWidth(width); } -void LinkProgram(GLuint program) { - GPU_CLIENT_LOG("[" << this << "] glLinkProgram(" << program << ")"); - helper_->LinkProgram(program); -} +void LinkProgram(GLuint program); void PixelStorei(GLenum pname, GLint param); diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc index 8b13789..57a037d 100644 --- a/gpu/command_buffer/client/program_info_manager.cc +++ b/gpu/command_buffer/client/program_info_manager.cc @@ -1 +1,496 @@ +// Copyright (c) 2011 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 "../client/program_info_manager.h" +#include "../client/gles2_implementation.h" + +#include <map> + +namespace gpu { +namespace gles2 { + +class NonCachedProgramInfoManager : public ProgramInfoManager { + public: + NonCachedProgramInfoManager(); + virtual ~NonCachedProgramInfoManager(); + + virtual void CreateInfo(GLuint program); + + virtual void DeleteInfo(GLuint program); + + virtual bool GetProgramiv( + GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params); + + virtual GLint GetAttribLocation( + GLES2Implementation* gl, GLuint program, const char* name); + + virtual GLint GetUniformLocation( + GLES2Implementation* gl, GLuint program, const char* name); + + virtual bool GetActiveAttrib( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name); + + virtual bool GetActiveUniform( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name); + +}; + +NonCachedProgramInfoManager::NonCachedProgramInfoManager() { +} + +NonCachedProgramInfoManager::~NonCachedProgramInfoManager() { +} + +void NonCachedProgramInfoManager::CreateInfo(GLuint /* program */) { +} + +void NonCachedProgramInfoManager::DeleteInfo(GLuint /* program */) { +} + +bool NonCachedProgramInfoManager::GetProgramiv( + GLES2Implementation* /* gl */, + GLuint /* program */, + GLenum /* pname */, + GLint* /* params */) { + return false; +} + +GLint NonCachedProgramInfoManager::GetAttribLocation( + GLES2Implementation* gl, GLuint program, const char* name) { + return gl->GetAttribLocationHelper(program, name); +} + +GLint NonCachedProgramInfoManager::GetUniformLocation( + GLES2Implementation* gl, GLuint program, const char* name) { + return gl->GetUniformLocationHelper(program, name); +} + +bool NonCachedProgramInfoManager::GetActiveAttrib( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name) { + return gl->GetActiveAttribHelper( + program, index, bufsize, length, size, type, name); +} + +bool NonCachedProgramInfoManager::GetActiveUniform( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name) { + return gl->GetActiveUniformHelper( + program, index, bufsize, length, size, type, name); +} + +class CachedProgramInfoManager : public ProgramInfoManager { + public: + CachedProgramInfoManager(); + virtual ~CachedProgramInfoManager(); + + virtual void CreateInfo(GLuint program); + + virtual void DeleteInfo(GLuint program); + + virtual bool GetProgramiv( + GLES2Implementation* gl, + GLuint program, GLenum pname, GLint* params); + + virtual GLint GetAttribLocation( + GLES2Implementation* gl, GLuint program, const char* name); + + virtual GLint GetUniformLocation( + GLES2Implementation* gl, GLuint program, const char* name); + + virtual bool GetActiveAttrib( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name); + + virtual bool GetActiveUniform( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name); + + private: + class ProgramInfo { + public: + struct UniformInfo { + UniformInfo(GLsizei _size, GLenum _type, const std::string& _name); + + GLsizei size; + GLenum type; + bool is_array; + std::string name; + std::vector<GLint> element_locations; + }; + struct VertexAttribInfo { + VertexAttribInfo(GLsizei _size, GLenum _type, const std::string& _name, + GLint _location) + : size(_size), + type(_type), + location(_location), + name(_name) { + } + GLsizei size; + GLenum type; + GLint location; + std::string name; + }; + + typedef std::vector<UniformInfo> UniformInfoVector; + typedef std::vector<VertexAttribInfo> AttribInfoVector; + + ProgramInfo(); + + const AttribInfoVector& GetAttribInfos() const { + return attrib_infos_; + } + + const VertexAttribInfo* GetAttribInfo(GLint index) const { + return (static_cast<size_t>(index) < attrib_infos_.size()) ? + &attrib_infos_[index] : NULL; + } + + GLint GetAttribLocation(const std::string& name) const; + + const UniformInfo* GetUniformInfo(GLint index) const { + return (static_cast<size_t>(index) < uniform_infos_.size()) ? + &uniform_infos_[index] : NULL; + } + + // Gets the location of a uniform by name. + GLint GetUniformLocation(const std::string& name) const; + + bool GetProgramiv(GLenum pname, GLint* params); + + // Updates the program info after a successful link. + void Update(GLES2Implementation* gl, GLuint program); + + private: + bool cached_; + + GLsizei max_attrib_name_length_; + + // Attrib by index. + AttribInfoVector attrib_infos_; + + GLsizei max_uniform_name_length_; + + // Uniform info by index. + UniformInfoVector uniform_infos_; + + // This is true if glLinkProgram was successful last time it was called. + bool link_status_; + }; + + ProgramInfo* GetProgramInfo(GLES2Implementation* gl, GLuint program); + + // TODO(gman): Switch to a faster container. + typedef std::map<GLuint, ProgramInfo> ProgramInfoMap; + + ProgramInfoMap program_infos_; +}; + +CachedProgramInfoManager::ProgramInfo::UniformInfo::UniformInfo( + GLsizei _size, GLenum _type, const std::string& _name) + : size(_size), + type(_type), + name(_name) { + is_array = (!name.empty() && name[name.size() - 1] == ']'); + GPU_DCHECK(!(size > 1 && !is_array)); +} + +CachedProgramInfoManager::ProgramInfo::ProgramInfo() + : cached_(false), + max_attrib_name_length_(0), + max_uniform_name_length_(0), + link_status_(false) { +} + +// TODO(gman): Add a faster lookup. +GLint CachedProgramInfoManager::ProgramInfo::GetAttribLocation( + const std::string& name) const { + for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) { + const VertexAttribInfo& info = attrib_infos_[ii]; + if (info.name == name) { + return info.location; + } + } + return -1; +} + +// TODO(gman): Add a faster lookup. +GLint CachedProgramInfoManager::ProgramInfo::GetUniformLocation( + const std::string& name) const { + for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) { + const UniformInfo& info = uniform_infos_[ii]; + if (info.name == name || + (info.is_array && + info.name.compare(0, info.name.size() - 3, name) == 0)) { + return info.element_locations[0]; + } else if (info.is_array && + name.size() >= 3 && name[name.size() - 1] == ']') { + // Look for an array specification. + size_t open_pos = name.find_last_of('['); + if (open_pos != std::string::npos && + open_pos < name.size() - 2 && + info.name.size() > open_pos && + name.compare(0, open_pos, info.name, 0, open_pos) == 0) { + GLint index = 0; + size_t last = name.size() - 1; + bool bad = false; + for (size_t pos = open_pos + 1; pos < last; ++pos) { + int8 digit = name[pos] - '0'; + if (digit < 0 || digit > 9) { + bad = true; + break; + } + index = index * 10 + digit; + } + if (!bad && index >= 0 && index < info.size) { + return info.element_locations[index]; + } + } + } + } + return -1; +} + +bool CachedProgramInfoManager::ProgramInfo::GetProgramiv( + GLenum pname, GLint* params) { + switch (pname) { + case GL_LINK_STATUS: + *params = link_status_; + return true; + case GL_ACTIVE_ATTRIBUTES: + *params = attrib_infos_.size(); + return true; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = max_attrib_name_length_; + return true; + case GL_ACTIVE_UNIFORMS: + *params = uniform_infos_.size(); + return true; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = max_uniform_name_length_; + return true; + default: + break; + } + return false; +} + +template<typename T> static T LocalGetAs( + const std::vector<int8>& data, uint32 offset, size_t size) { + const int8* p = &data[0] + offset; + if (offset + size > data.size()) { + GPU_NOTREACHED(); + return NULL; + } + return static_cast<T>(static_cast<const void*>(p)); +} + +void CachedProgramInfoManager::ProgramInfo::Update( + GLES2Implementation* gl, GLuint program) { + if (cached_) { + return; + } + std::vector<int8> result; + gl->GetProgramInfoCHROMIUMHelper(program, &result); + if (result.empty()) { + // This should only happen on a lost context. + return; + } + GPU_DCHECK_GE(result.size(), sizeof(ProgramInfoHeader)); + const ProgramInfoHeader* header = LocalGetAs<const ProgramInfoHeader*>( + result, 0, sizeof(header)); + link_status_ = header->link_status != 0; + if (!link_status_) { + return; + } + attrib_infos_.clear(); + uniform_infos_.clear(); + max_attrib_name_length_ = 0; + max_uniform_name_length_ = 0; + const ProgramInput* inputs = LocalGetAs<const ProgramInput*>( + result, sizeof(*header), + sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms)); + const ProgramInput* input = inputs; + for (uint32 ii = 0; ii < header->num_attribs; ++ii) { + const int32* location = LocalGetAs<const int32*>( + result, input->location_offset, sizeof(int32)); + const char* name_buf = LocalGetAs<const char*>( + result, input->name_offset, input->name_length); + std::string name(name_buf, input->name_length); + attrib_infos_.push_back( + VertexAttribInfo(input->size, input->type, name, *location)); + max_attrib_name_length_ = std::max( + static_cast<GLsizei>(name.size() + 1), max_attrib_name_length_); + ++input; + } + for (uint32 ii = 0; ii < header->num_uniforms; ++ii) { + const int32* locations = LocalGetAs<const int32*>( + result, input->location_offset, sizeof(int32) * input->size); + const char* name_buf = LocalGetAs<const char*>( + result, input->name_offset, input->name_length); + std::string name(name_buf, input->name_length); + UniformInfo info(input->size, input->type, name); + max_uniform_name_length_ = std::max( + static_cast<GLsizei>(name.size() + 1), max_uniform_name_length_); + for (int32 jj = 0; jj < input->size; ++jj) { + info.element_locations.push_back(locations[jj]); + } + uniform_infos_.push_back(info); + ++input; + } + GPU_DCHECK_EQ(header->num_attribs + header->num_uniforms, + static_cast<uint32>(input - inputs)); + cached_ = true; +} + +CachedProgramInfoManager::CachedProgramInfoManager() { +} + +CachedProgramInfoManager::~CachedProgramInfoManager() { + +} + +CachedProgramInfoManager::ProgramInfo* + CachedProgramInfoManager::GetProgramInfo( + GLES2Implementation* gl, GLuint program) { + ProgramInfoMap::iterator it = program_infos_.find(program); + if (it == program_infos_.end()) { + return NULL; + } + ProgramInfo* info = &it->second; + info->Update(gl, program); + return info; +} + +void CachedProgramInfoManager::CreateInfo(GLuint program) { + DeleteInfo(program); + std::pair<ProgramInfoMap::iterator, bool> result = + program_infos_.insert(std::make_pair(program, ProgramInfo())); + + GPU_DCHECK(result.second); +} + +void CachedProgramInfoManager::DeleteInfo(GLuint program) { + program_infos_.erase(program); +} + +bool CachedProgramInfoManager::GetProgramiv( + GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) { + ProgramInfo* info = GetProgramInfo(gl, program); + if (!info) { + return false; + } + return info->GetProgramiv(pname, params); +} + +GLint CachedProgramInfoManager::GetAttribLocation( + GLES2Implementation* gl, GLuint program, const char* name) { + ProgramInfo* info = GetProgramInfo(gl, program); + if (info) { + return info->GetAttribLocation(name); + } + return gl->GetAttribLocationHelper(program, name); +} + +GLint CachedProgramInfoManager::GetUniformLocation( + GLES2Implementation* gl, GLuint program, const char* name) { + ProgramInfo* info = GetProgramInfo(gl, program); + if (info) { + return info->GetUniformLocation(name); + } + return gl->GetUniformLocationHelper(program, name); +} + +bool CachedProgramInfoManager::GetActiveAttrib( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name) { + ProgramInfo* info = GetProgramInfo(gl, program); + if (info) { + const ProgramInfo::VertexAttribInfo* attrib_info = + info->GetAttribInfo(index); + if (attrib_info) { + if (size) { + *size = attrib_info->size; + } + if (type) { + *type = attrib_info->type; + } + if (length || name) { + GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1, + std::max(static_cast<size_t>(0), + attrib_info->name.size())); + if (length) { + *length = max_size; + } + if (name && bufsize > 0) { + memcpy(name, attrib_info->name.c_str(), max_size); + name[max_size] = '\0'; + } + } + return true; + } + } + return gl->GetActiveAttribHelper( + program, index, bufsize, length, size, type, name); +} + +bool CachedProgramInfoManager::GetActiveUniform( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name) { + ProgramInfo* info = GetProgramInfo(gl, program); + if (info) { + const ProgramInfo::UniformInfo* uniform_info = info->GetUniformInfo(index); + if (uniform_info) { + if (size) { + *size = uniform_info->size; + } + if (type) { + *type = uniform_info->type; + } + if (length || name) { + GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1, + std::max(static_cast<size_t>(0), + uniform_info->name.size())); + if (length) { + *length = max_size; + } + if (name && bufsize > 0) { + memcpy(name, uniform_info->name.c_str(), max_size); + name[max_size] = '\0'; + } + } + return true; + } + } + return gl->GetActiveUniformHelper( + program, index, bufsize, length, size, type, name); +} + +ProgramInfoManager::ProgramInfoManager() { +} + +ProgramInfoManager::~ProgramInfoManager() { +} + +ProgramInfoManager* ProgramInfoManager::Create(bool shared_resources) { + if (shared_resources) { + return new NonCachedProgramInfoManager(); + } else { + return new CachedProgramInfoManager(); + } +} + +} // namespace gles2 +} // namespace gpu diff --git a/gpu/command_buffer/client/program_info_manager.h b/gpu/command_buffer/client/program_info_manager.h new file mode 100644 index 0000000..5b3e559 --- /dev/null +++ b/gpu/command_buffer/client/program_info_manager.h @@ -0,0 +1,52 @@ +// Copyright (c) 2011 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_CLIENT_PROGRAM_INFO_MANAGER_H_ +#define GPU_COMMAND_BUFFER_CLIENT_PROGRAM_INFO_MANAGER_H_ + +#include <GLES2/gl2.h> + +namespace gpu { +namespace gles2 { + +class GLES2Implementation; + +// Manages info about OpenGL ES Programs. +class ProgramInfoManager { + public: + virtual ~ProgramInfoManager(); + + static ProgramInfoManager* Create(bool shared_resources); + + virtual void CreateInfo(GLuint program) = 0; + + virtual void DeleteInfo(GLuint program) = 0; + + virtual bool GetProgramiv( + GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) = 0; + + virtual GLint GetAttribLocation( + GLES2Implementation* gl, GLuint program, const char* name) = 0; + + virtual GLint GetUniformLocation( + GLES2Implementation* gl, GLuint program, const char* name) = 0; + + virtual bool GetActiveAttrib( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name) = 0; + + virtual bool GetActiveUniform( + GLES2Implementation* gl, + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, + GLint* size, GLenum* type, char* name) = 0; + + protected: + ProgramInfoManager(); +}; + +} // namespace gles2 +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_CLIENT_PROGRAM_INFO_MANAGER_H_ diff --git a/gpu/command_buffer/client/program_info_manager_unittest.cc b/gpu/command_buffer/client/program_info_manager_unittest.cc new file mode 100644 index 0000000..e5002fd --- /dev/null +++ b/gpu/command_buffer/client/program_info_manager_unittest.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2011 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. + +// Tests for the Command Buffer Helper. + +#include "gpu/command_buffer/client/program_info_manager.h" +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace gpu { +namespace gles2 { + +class ProgramInfoManagerTest : public testing::Test { + protected: + virtual void SetUp() { + } + + virtual void TearDown() { + } + + scoped_ptr<ProgramInfoManager> program_info_manager_; +}; + +TEST_F(ProgramInfoManagerTest, Basic) { +} + +} // namespace gles2 +} // namespace gpu + + diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 1dd1bfd..b7477c5 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -4727,7 +4727,7 @@ error::Error GLES2DecoderImpl::HandleGetProgramInfoLog( ProgramManager::ProgramInfo* info = GetProgramInfoNotShader( program, "glGetProgramInfoLog"); if (!info || !info->log_info()) { - bucket->SetSize(0); + bucket->SetFromString(""); return error::kNoError; } bucket->SetFromString(info->log_info()->c_str()); @@ -4742,7 +4742,7 @@ error::Error GLES2DecoderImpl::HandleGetShaderInfoLog( ShaderManager::ShaderInfo* info = GetShaderInfoNotProgram( shader, "glGetShaderInfoLog"); if (!info || !info->log_info()) { - bucket->SetSize(0); + bucket->SetFromString(""); return error::kNoError; } bucket->SetFromString(info->log_info()->c_str()); @@ -6792,17 +6792,9 @@ error::Error GLES2DecoderImpl::HandleGetProgramInfoCHROMIUM( Bucket* bucket = CreateBucket(bucket_id); bucket->SetSize(sizeof(ProgramInfoHeader)); // in case we fail. ProgramManager::ProgramInfo* info = NULL; - if (program) { - info = GetProgramInfoNotShader(program, "glGetProgramInfoCHROMIUM"); - if (!info) { - return error::kNoError; - } - if (!info->IsValid()) { - // Program was not linked successfully. (ie, glLinkProgram) - SetGLError(GL_INVALID_OPERATION, - "glGetProgramInfoCHROMIUM: program not linked"); - return error::kNoError; - } + info = GetProgramInfo(program); + if (!info || !info->IsValid()) { + return error::kNoError; } info->GetProgramInfo(bucket); return error::kNoError; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index e145a79..d619b12 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -4276,7 +4276,7 @@ TEST_F(GLES2DecoderWithShaderTest, GetProgramInfoCHROMIUMInvalidArgs) { GetProgramInfoCHROMIUM cmd; cmd.Init(kInvalidClientId, kBucketId); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); bucket = decoder_->GetBucket(kBucketId); ASSERT_TRUE(bucket != NULL); EXPECT_EQ(sizeof(ProgramInfoHeader), bucket->size()); diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc index 60f652f4..c58cda1 100644 --- a/gpu/command_buffer/service/program_manager_unittest.cc +++ b/gpu/command_buffer/service/program_manager_unittest.cc @@ -857,7 +857,7 @@ TEST_F(ProgramManagerWithShaderTest, ProgramInfoGetProgramInfo) { EXPECT_EQ(arraysize(kUniforms), header->num_uniforms); const ProgramInput* inputs = bucket.GetDataAs<const ProgramInput*>( sizeof(*header), - sizeof(ProgramInput) * (header->num_attribs + header->num_attribs)); + sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms)); ASSERT_TRUE(inputs != NULL); const ProgramInput* input = inputs; // TODO(gman): Don't assume these are in order. diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index 2c4bbfd..6acbc8a 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -21,6 +21,8 @@ 'command_buffer/client/gles2_implementation_autogen.h', 'command_buffer/client/gles2_implementation.cc', 'command_buffer/client/gles2_implementation.h', + 'command_buffer/client/program_info_manager.cc', + 'command_buffer/client/program_info_manager.h', ] }, 'targets': [ @@ -271,6 +273,7 @@ 'command_buffer/client/fenced_allocator_test.cc', 'command_buffer/client/gles2_implementation_unittest.cc', 'command_buffer/client/mapped_memory_unittest.cc', + 'command_buffer/client/program_info_manager_unittest.cc', 'command_buffer/client/ring_buffer_test.cc', 'command_buffer/common/bitfield_helpers_test.cc', 'command_buffer/common/command_buffer_mock.cc', |