summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-08 17:51:46 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-08 17:51:46 +0000
commit9a14ae6185d3f43c6fc30239f16c647abc44b366 (patch)
tree668c2224231e0ba3d5ec41b64479fba5e4d10962 /gpu
parent4e601fcf25223ca20444bcc22c252d84d5a1621e (diff)
downloadchromium_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-xgpu/command_buffer/build_gles2_cmd_buffer.py22
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc150
-rw-r--r--gpu/command_buffer/client/gles2_implementation.h19
-rw-r--r--gpu/command_buffer/client/gles2_implementation_autogen.h54
-rw-r--r--gpu/command_buffer/client/program_info_manager.cc495
-rw-r--r--gpu/command_buffer/client/program_info_manager.h52
-rw-r--r--gpu/command_buffer/client/program_info_manager_unittest.cc32
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc18
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc2
-rw-r--r--gpu/command_buffer/service/program_manager_unittest.cc2
-rw-r--r--gpu/gpu.gyp3
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',