Index: gpu/command_buffer/service/gles2_cmd_decoder.cc |
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
index fbc923f2dd80355732042450e7138640512206c5..c6ee2b886bb338416d22af49fad3ff53d92090ba 100644 |
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
@@ -1374,6 +1374,12 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { |
// NONE through DrawBuffers, to be on the safe side. Return true. |
bool ValidateAndAdjustDrawBuffers(const char* function_name); |
+ // Checks if all active uniform blocks in the current program are backed by |
+ // a buffer of sufficient size. |
+ // If not, generates an INVALID_OPERATION to avoid undefined behavior in |
+ // shader execution and return false. |
+ bool ValidateUniformBlockBackings(const char* function_name); |
+ |
// Checks if |api_type| is valid for the given uniform |
// If the api type is not valid generates the appropriate GL |
// error. Returns true if |api_type| is valid for the uniform |
@@ -8069,6 +8075,29 @@ bool GLES2DecoderImpl::ValidateAndAdjustDrawBuffers(const char* func_name) { |
return true; |
} |
+bool GLES2DecoderImpl::ValidateUniformBlockBackings(const char* func_name) { |
+ switch (feature_info_->context_type()) { |
+ case CONTEXT_TYPE_OPENGLES2: |
+ case CONTEXT_TYPE_WEBGL1: |
+ // Uniform blocks do not exist in ES2 contexts. |
+ return true; |
+ default: |
+ break; |
+ } |
+ DCHECK(state_.current_program.get()); |
+ for (auto info : state_.current_program->uniform_block_size_info()) { |
+ uint32_t buffer_size = static_cast<uint32_t>( |
+ state_.indexed_uniform_buffer_bindings->GetEffectiveBufferSize( |
+ info.binding)); |
+ if (info.data_size > buffer_size) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name, |
+ "uniform blocks are not backed by a buffer with sufficient data"); |
+ return false; |
+ } |
+ } |
+ return true; |
+} |
+ |
bool GLES2DecoderImpl::CheckUniformForApiType( |
const Program::UniformInfo* info, |
const char* function_name, |
@@ -9099,6 +9128,9 @@ error::Error GLES2DecoderImpl::DoDrawArrays( |
if (!ValidateAndAdjustDrawBuffers(function_name)) { |
return error::kNoError; |
} |
+ if (!ValidateUniformBlockBackings(function_name)) { |
+ return error::kNoError; |
+ } |
if (!instanced) { |
glDrawArrays(mode, first, count); |
} else { |
@@ -9243,6 +9275,9 @@ error::Error GLES2DecoderImpl::DoDrawElements(const char* function_name, |
if (!ValidateAndAdjustDrawBuffers(function_name)) { |
return error::kNoError; |
} |
+ if (!ValidateUniformBlockBackings(function_name)) { |
+ return error::kNoError; |
+ } |
if (state_.enable_flags.primitive_restart_fixed_index && |
feature_info_->feature_flags(). |
emulate_primitive_restart_fixed_index) { |
@@ -15912,6 +15947,7 @@ void GLES2DecoderImpl::DoMatrixLoadIdentityCHROMIUM(GLenum matrix_mode) { |
error::Error GLES2DecoderImpl::HandleUniformBlockBinding( |
uint32_t immediate_data_size, const void* cmd_data) { |
+ const char* func_name = "glUniformBlockBinding"; |
if (!unsafe_es3_apis_enabled()) |
return error::kUnknownCommand; |
const gles2::cmds::UniformBlockBinding& c = |
@@ -15919,13 +15955,23 @@ error::Error GLES2DecoderImpl::HandleUniformBlockBinding( |
GLuint client_id = c.program; |
GLuint index = static_cast<GLuint>(c.index); |
GLuint binding = static_cast<GLuint>(c.binding); |
- Program* program = GetProgramInfoNotShader( |
- client_id, "glUniformBlockBinding"); |
+ Program* program = GetProgramInfoNotShader(client_id, func_name); |
if (!program) { |
return error::kNoError; |
} |
+ if (index >= program->uniform_block_size_info().size()) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, |
+ "uniformBlockIndex is not an active uniform block index"); |
+ return error::kNoError; |
+ } |
+ if (binding >= group_->max_uniform_buffer_bindings()) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, |
+ "uniformBlockBinding >= MAX_UNIFORM_BUFFER_BINDINGS"); |
+ return error::kNoError; |
+ } |
GLuint service_id = program->service_id(); |
glUniformBlockBinding(service_id, index, binding); |
+ program->SetUniformBlockBinding(index, binding); |
return error::kNoError; |
} |