Index: gpu/command_buffer/client/program_info_manager.cc |
diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc |
index 04121aa7346ba275391dc30102909c31d47cf304..779d914ac4c441a6fc40d0a00a958281a7df7c83 100644 |
--- a/gpu/command_buffer/client/program_info_manager.cc |
+++ b/gpu/command_buffer/client/program_info_manager.cc |
@@ -44,6 +44,17 @@ ProgramInfoManager::Program::UniformInfo::UniformInfo( |
ProgramInfoManager::Program::UniformInfo::~UniformInfo() { |
} |
+ProgramInfoManager::Program::UniformES3::UniformES3() |
+ : block_index(-1), |
+ offset(-1), |
+ array_stride(-1), |
+ matrix_stride(-1), |
+ is_row_major(0) { |
+} |
+ |
+ProgramInfoManager::Program::UniformES3::~UniformES3() { |
+} |
+ |
ProgramInfoManager::Program::UniformBlock::UniformBlock() |
: binding(0), |
data_size(0), |
@@ -54,13 +65,26 @@ ProgramInfoManager::Program::UniformBlock::UniformBlock() |
ProgramInfoManager::Program::UniformBlock::~UniformBlock() { |
} |
+ProgramInfoManager::Program::TransformFeedbackVarying:: |
+TransformFeedbackVarying() |
+ : size(0), |
+ type(0) { |
+} |
+ |
+ProgramInfoManager::Program::TransformFeedbackVarying:: |
+~TransformFeedbackVarying() { |
+} |
+ |
ProgramInfoManager::Program::Program() |
: cached_es2_(false), |
max_attrib_name_length_(0), |
max_uniform_name_length_(0), |
link_status_(false), |
cached_es3_uniform_blocks_(false), |
- active_uniform_block_max_name_length_(0) { |
+ active_uniform_block_max_name_length_(0), |
+ cached_es3_transform_feedback_varyings_(false), |
+ transform_feedback_varying_max_length_(0), |
+ cached_es3_uniformsiv_(false) { |
} |
ProgramInfoManager::Program::~Program() { |
@@ -124,6 +148,22 @@ GLint ProgramInfoManager::Program::GetUniformLocation( |
return -1; |
} |
+GLuint ProgramInfoManager::Program::GetUniformIndex( |
+ const std::string& name) const { |
+ // TODO(zmo): Maybe build a hashed_map for faster lookup. |
+ for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) { |
+ const UniformInfo& info = uniform_infos_[ii]; |
+ // For an array, either "var" or "var[0]" is considered as a match. |
+ // See "OpenGL ES 3.0.0, Section 2.11.3 Program Objects." |
+ if (info.name == name || |
+ (info.is_array && |
+ info.name.compare(0, info.name.size() - 3, name) == 0)) { |
+ return ii; |
+ } |
+ } |
+ return GL_INVALID_INDEX; |
+} |
+ |
GLint ProgramInfoManager::Program::GetFragDataLocation( |
const std::string& name) const { |
base::hash_map<std::string, GLint>::const_iterator iter = |
@@ -162,6 +202,12 @@ bool ProgramInfoManager::Program::GetProgramiv( |
case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: |
*params = static_cast<GLint>(active_uniform_block_max_name_length_); |
return true; |
+ case GL_TRANSFORM_FEEDBACK_VARYINGS: |
+ *params = static_cast<GLint>(transform_feedback_varyings_.size()); |
+ return true; |
+ case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: |
+ *params = static_cast<GLint>(transform_feedback_varying_max_length_); |
+ return true; |
default: |
NOTREACHED(); |
break; |
@@ -179,6 +225,98 @@ GLuint ProgramInfoManager::Program::GetUniformBlockIndex( |
return GL_INVALID_INDEX; |
} |
+void ProgramInfoManager::Program::UniformBlockBinding( |
+ GLuint index , GLuint binding) { |
+ if (index < uniform_blocks_.size()) { |
+ uniform_blocks_[index].binding = binding; |
+ } |
+} |
+ |
+const ProgramInfoManager::Program::TransformFeedbackVarying* |
+ProgramInfoManager::Program::GetTransformFeedbackVarying(GLuint index) const { |
+ return (index < transform_feedback_varyings_.size()) ? |
+ &transform_feedback_varyings_[index] : NULL; |
+} |
+ |
+bool ProgramInfoManager::Program::GetUniformsiv( |
+ GLsizei count, const GLuint* indices, GLenum pname, GLint* params) { |
+ if (count == 0) { |
+ // At this point, pname has already been validated. |
+ return true; |
+ } |
+ DCHECK(count > 0 && indices); |
+ size_t num_uniforms = uniform_infos_.size(); |
+ if (num_uniforms == 0) { |
+ num_uniforms = uniforms_es3_.size(); |
+ } |
+ if (static_cast<size_t>(count) > num_uniforms) { |
+ return false; |
+ } |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ if (indices[ii] >= num_uniforms) { |
+ return false; |
+ } |
+ } |
+ if (!params) { |
+ return true; |
+ } |
+ switch (pname) { |
+ case GL_UNIFORM_SIZE: |
+ DCHECK_EQ(num_uniforms, uniform_infos_.size()); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ params[ii] = static_cast<GLint>(uniform_infos_[indices[ii]].size); |
+ } |
+ return true; |
+ case GL_UNIFORM_TYPE: |
+ DCHECK_EQ(num_uniforms, uniform_infos_.size()); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ params[ii] = static_cast<GLint>(uniform_infos_[indices[ii]].type); |
+ } |
+ return true; |
+ case GL_UNIFORM_NAME_LENGTH: |
+ DCHECK_EQ(num_uniforms, uniform_infos_.size()); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ params[ii] = static_cast<GLint>( |
+ uniform_infos_[indices[ii]].name.length() + 1); |
+ } |
+ return true; |
+ case GL_UNIFORM_BLOCK_INDEX: |
+ DCHECK_EQ(num_uniforms, uniforms_es3_.size()); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ params[ii] = uniforms_es3_[indices[ii]].block_index; |
+ } |
+ return true; |
+ case GL_UNIFORM_OFFSET: |
+ DCHECK_EQ(num_uniforms, uniforms_es3_.size()); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ params[ii] = uniforms_es3_[indices[ii]].offset; |
+ } |
+ return true; |
+ case GL_UNIFORM_ARRAY_STRIDE: |
+ DCHECK_EQ(num_uniforms, uniforms_es3_.size()); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ params[ii] = uniforms_es3_[indices[ii]].array_stride; |
+ } |
+ return true; |
+ case GL_UNIFORM_MATRIX_STRIDE: |
+ DCHECK_EQ(num_uniforms, uniforms_es3_.size()); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ params[ii] = uniforms_es3_[indices[ii]].matrix_stride; |
+ } |
+ return true; |
+ case GL_UNIFORM_IS_ROW_MAJOR: |
+ DCHECK_EQ(num_uniforms, uniforms_es3_.size()); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ params[ii] = uniforms_es3_[indices[ii]].is_row_major; |
+ } |
+ return true; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ return false; |
+} |
+ |
void ProgramInfoManager::Program::UpdateES2(const std::vector<int8>& result) { |
if (cached_es2_) { |
return; |
@@ -306,12 +444,119 @@ void ProgramInfoManager::Program::UpdateES3UniformBlocks( |
cached_es3_uniform_blocks_ = true; |
} |
+void ProgramInfoManager::Program::UpdateES3Uniformsiv( |
+ const std::vector<int8>& result) { |
+ if (cached_es3_uniformsiv_) { |
+ return; |
+ } |
+ if (result.empty()) { |
+ // This should only happen on a lost context. |
+ return; |
+ } |
+ uniforms_es3_.clear(); |
+ |
+ // |result| comes from GPU process. We consider it trusted data. Therefore, |
+ // no need to check for overflows as the GPU side did the checks already. |
+ uint32_t header_size = sizeof(UniformsES3Header); |
+ DCHECK_GE(result.size(), header_size); |
+ const UniformsES3Header* header = LocalGetAs<const UniformsES3Header*>( |
+ result, 0, header_size); |
+ DCHECK(header); |
+ if (header->num_uniforms == 0) { |
+ DCHECK_EQ(result.size(), header_size); |
+ // TODO(zmo): Here we can't tell if no uniforms are defined, or |
+ // the previous link failed. |
+ return; |
+ } |
+ uniforms_es3_.resize(header->num_uniforms); |
+ |
+ uint32_t entry_size = sizeof(UniformES3Info) * header->num_uniforms; |
+ DCHECK_EQ(result.size(), header_size + entry_size); |
+ const UniformES3Info* entries = LocalGetAs<const UniformES3Info*>( |
+ result, header_size, entry_size); |
+ DCHECK(entries); |
+ |
+ for (uint32_t ii = 0; ii < header->num_uniforms; ++ii) { |
+ uniforms_es3_[ii].block_index = entries[ii].block_index; |
+ uniforms_es3_[ii].offset = entries[ii].offset; |
+ uniforms_es3_[ii].array_stride = entries[ii].array_stride; |
+ uniforms_es3_[ii].matrix_stride = entries[ii].matrix_stride; |
+ uniforms_es3_[ii].is_row_major = entries[ii].is_row_major; |
+ } |
+ cached_es3_uniformsiv_ = true; |
+} |
+ |
+void ProgramInfoManager::Program::UpdateES3TransformFeedbackVaryings( |
+ const std::vector<int8>& result) { |
+ if (cached_es3_transform_feedback_varyings_) { |
+ return; |
+ } |
+ if (result.empty()) { |
+ // This should only happen on a lost context. |
+ return; |
+ } |
+ transform_feedback_varyings_.clear(); |
+ transform_feedback_varying_max_length_ = 0; |
+ |
+ // |result| comes from GPU process. We consider it trusted data. Therefore, |
+ // no need to check for overflows as the GPU side did the checks already. |
+ uint32_t header_size = sizeof(TransformFeedbackVaryingsHeader); |
+ DCHECK_GE(result.size(), header_size); |
+ const TransformFeedbackVaryingsHeader* header = |
+ LocalGetAs<const TransformFeedbackVaryingsHeader*>( |
+ result, 0, header_size); |
+ DCHECK(header); |
+ if (header->num_transform_feedback_varyings == 0) { |
+ DCHECK_EQ(result.size(), header_size); |
+ // TODO(zmo): Here we can't tell if no TransformFeedback varyings are |
+ // defined, or the previous link failed. |
+ return; |
+ } |
+ transform_feedback_varyings_.resize(header->num_transform_feedback_varyings); |
+ |
+ uint32_t entry_size = sizeof(TransformFeedbackVaryingInfo) * |
+ header->num_transform_feedback_varyings; |
+ DCHECK_GE(result.size(), header_size + entry_size); |
+ uint32_t data_size = result.size() - header_size - entry_size; |
+ DCHECK_LT(0u, data_size); |
+ const TransformFeedbackVaryingInfo* entries = |
+ LocalGetAs<const TransformFeedbackVaryingInfo*>( |
+ result, header_size, entry_size); |
+ DCHECK(entries); |
+ const char* data = LocalGetAs<const char*>( |
+ result, header_size + entry_size, data_size); |
+ DCHECK(data); |
+ |
+ uint32_t size = 0; |
+ for (uint32_t ii = 0; ii < header->num_transform_feedback_varyings; ++ii) { |
+ transform_feedback_varyings_[ii].size = |
+ static_cast<GLsizei>(entries[ii].size); |
+ transform_feedback_varyings_[ii].type = |
+ static_cast<GLenum>(entries[ii].type); |
+ DCHECK_LE(1u, entries[ii].name_length); |
+ if (entries[ii].name_length > transform_feedback_varying_max_length_) { |
+ transform_feedback_varying_max_length_ = entries[ii].name_length; |
+ } |
+ size += entries[ii].name_length; |
+ DCHECK_GE(data_size, size); |
+ transform_feedback_varyings_[ii].name = |
+ std::string(data, entries[ii].name_length - 1); |
+ data += entries[ii].name_length; |
+ } |
+ DCHECK_EQ(data_size, size); |
+ cached_es3_transform_feedback_varyings_ = true; |
+} |
+ |
bool ProgramInfoManager::Program::IsCached(ProgramInfoType type) const { |
switch (type) { |
case kES2: |
return cached_es2_; |
case kES3UniformBlocks: |
return cached_es3_uniform_blocks_; |
+ case kES3TransformFeedbackVaryings: |
+ return cached_es3_transform_feedback_varyings_; |
+ case kES3Uniformsiv: |
+ return cached_es3_uniformsiv_; |
case kNone: |
return true; |
default: |
@@ -354,12 +599,26 @@ ProgramInfoManager::Program* ProgramInfoManager::GetProgramInfo( |
base::AutoUnlock unlock(lock_); |
// lock_ can't be held across IPC call or else it may deadlock in |
// pepper. http://crbug.com/418651 |
- |
- // TODO(zmo): Uncomment the below line once GetUniformBlocksCHROMIUM |
- // command is implemented. |
- // gl->GetUniformBlocksCHROMIUMHeler(program, &result); |
+ gl->GetUniformBlocksCHROMIUMHelper(program, &result); |
} |
info->UpdateES3UniformBlocks(result); |
+ break; |
+ case kES3TransformFeedbackVaryings: |
+ { |
+ base::AutoUnlock unlock(lock_); |
+ // lock_ can't be held across IPC call or else it may deadlock in |
+ // pepper. http://crbug.com/418651 |
+ gl->GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result); |
+ } |
+ info->UpdateES3TransformFeedbackVaryings(result); |
+ case kES3Uniformsiv: |
+ { |
+ base::AutoUnlock unlock(lock_); |
+ // lock_ can't be held across IPC call or else it may deadlock in |
+ // pepper. http://crbug.com/418651 |
+ gl->GetUniformsES3CHROMIUMHelper(program, &result); |
+ } |
+ info->UpdateES3Uniformsiv(result); |
default: |
NOTREACHED(); |
return NULL; |
@@ -397,6 +656,10 @@ bool ProgramInfoManager::GetProgramiv( |
case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: |
type = kES3UniformBlocks; |
break; |
+ case GL_TRANSFORM_FEEDBACK_VARYINGS: |
+ case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: |
+ type = kES3TransformFeedbackVaryings; |
+ break; |
default: |
return false; |
} |
@@ -407,6 +670,34 @@ bool ProgramInfoManager::GetProgramiv( |
return info->GetProgramiv(pname, params); |
} |
+bool ProgramInfoManager::GetActiveUniformsiv( |
+ GLES2Implementation* gl, GLuint program, GLsizei count, |
+ const GLuint* indices, GLenum pname, GLint* params) { |
+ base::AutoLock auto_lock(lock_); |
+ ProgramInfoType type = kNone; |
+ switch (pname) { |
+ case GL_UNIFORM_SIZE: |
+ case GL_UNIFORM_TYPE: |
+ case GL_UNIFORM_NAME_LENGTH: |
+ type = kES2; |
+ break; |
+ case GL_UNIFORM_BLOCK_INDEX: |
+ case GL_UNIFORM_OFFSET: |
+ case GL_UNIFORM_ARRAY_STRIDE: |
+ case GL_UNIFORM_MATRIX_STRIDE: |
+ case GL_UNIFORM_IS_ROW_MAJOR: |
+ type = kES3Uniformsiv; |
+ break; |
+ default: |
+ return false; |
+ } |
+ Program* info = GetProgramInfo(gl, program, type); |
+ if (info) { |
+ return info->GetUniformsiv(count, indices, pname, params); |
+ } |
+ return gl->GetActiveUniformsivHelper(program, count, indices, pname, params); |
+} |
+ |
GLint ProgramInfoManager::GetAttribLocation( |
GLES2Implementation* gl, GLuint program, const char* name) { |
{ |
@@ -635,9 +926,73 @@ bool ProgramInfoManager::GetActiveUniformBlockiv( |
} |
} |
} |
- return false; |
- // TODO(zmo): return gl->GetActiveUniformBlockivHelper( |
- // program, index, pname, params); |
+ return gl->GetActiveUniformBlockivHelper(program, index, pname, params); |
+} |
+ |
+void ProgramInfoManager::UniformBlockBinding( |
+ GLES2Implementation* gl, GLuint program, GLuint index, GLuint binding) { |
+ GLuint max_bindings = |
+ static_cast<GLuint>(gl->capabilities().max_uniform_buffer_bindings); |
+ if (binding < max_bindings) { |
+ base::AutoLock auto_lock(lock_); |
+ // If UniformBlock info haven't been cached yet, skip updating the binding. |
+ Program* info = GetProgramInfo(gl, program, kNone); |
+ if (info) { |
+ info->UniformBlockBinding(index, binding); |
+ } |
+ } |
+} |
+ |
+bool ProgramInfoManager::GetTransformFeedbackVarying( |
+ GLES2Implementation* gl, GLuint program, GLuint index, GLsizei bufsize, |
+ GLsizei* length, GLsizei* size, GLenum* type, char* name) { |
+ { |
+ base::AutoLock auto_lock(lock_); |
+ Program* info = GetProgramInfo(gl, program, kES3TransformFeedbackVaryings); |
+ if (info) { |
+ const Program::TransformFeedbackVarying* varying = |
+ info->GetTransformFeedbackVarying(index); |
+ if (varying) { |
+ if (size) { |
+ *size = varying->size; |
+ } |
+ if (type) { |
+ *type = varying->type; |
+ } |
+ if (length || name) { |
+ GLsizei max_size = std::min( |
+ bufsize - 1, static_cast<GLsizei>(varying->name.size())); |
+ if (length) { |
+ *length = static_cast<GLsizei>(max_size); |
+ } |
+ if (name && bufsize > 0) { |
+ memcpy(name, varying->name.c_str(), max_size); |
+ name[max_size] = '\0'; |
+ } |
+ } |
+ return true; |
+ } |
+ } |
+ } |
+ return gl->GetTransformFeedbackVaryingHelper( |
+ program, index, bufsize, length, size, type, name); |
+} |
+ |
+bool ProgramInfoManager::GetUniformIndices(GLES2Implementation* gl, |
+ GLuint program, GLsizei count, const char* const* names, GLuint* indices) { |
+ { |
+ base::AutoLock auto_lock(lock_); |
+ Program* info = GetProgramInfo(gl, program, kES2); |
+ if (info) { |
+ DCHECK_LT(0, count); |
+ DCHECK(names && indices); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ indices[ii] = info->GetUniformIndex(names[ii]); |
+ } |
+ return true; |
+ } |
+ } |
+ return gl->GetUniformIndicesHelper(program, count, names, indices); |
} |
} // namespace gles2 |