| 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 d0b1c69ee505c718602fb41638fbaa866af50cb8..786765c2b54ed440df5280ade85e71e8f8db547c 100644
|
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| @@ -572,6 +572,11 @@ class GLES2DecoderImpl : public GLES2Decoder,
|
| unsigned int arg_count,
|
| const void* args) OVERRIDE;
|
|
|
| + virtual error::Error DoCommands(unsigned int num_commands,
|
| + const void* buffer,
|
| + int num_entries,
|
| + int* entries_processed) OVERRIDE;
|
| +
|
| // Overridden from AsyncAPIInterface.
|
| virtual const char* GetCommandName(unsigned int command_id) const OVERRIDE;
|
|
|
| @@ -1639,6 +1644,10 @@ class GLES2DecoderImpl : public GLES2Decoder,
|
| return error::kNoError;
|
| }
|
|
|
| + // Set remaining commands to process to 0 to force DoCommands to return
|
| + // and allow context preemption and GPU watchdog checks in GpuScheduler().
|
| + void ExitCommandProcessingEarly() { commands_to_process_ = 0; }
|
| +
|
| void ProcessPendingReadPixels();
|
| void FinishReadPixels(const cmds::ReadPixels& c, GLuint buffer);
|
|
|
| @@ -1760,6 +1769,9 @@ class GLES2DecoderImpl : public GLES2Decoder,
|
|
|
| int frame_number_;
|
|
|
| + // Number of commands remaining to be processed in DoCommands().
|
| + int commands_to_process_;
|
| +
|
| bool has_robustness_extension_;
|
| GLenum reset_status_;
|
| bool reset_by_robustness_extension_;
|
| @@ -3748,62 +3760,114 @@ const char* GLES2DecoderImpl::GetCommandName(unsigned int command_id) const {
|
| return GetCommonCommandName(static_cast<cmd::CommandId>(command_id));
|
| }
|
|
|
| -// Decode command with its arguments, and call the corresponding GL function.
|
| -// Note: args is a pointer to the command buffer. As such, it could be changed
|
| -// by a (malicious) client at any time, so if validation has to happen, it
|
| -// should operate on a copy of them.
|
| -error::Error GLES2DecoderImpl::DoCommand(
|
| - unsigned int command,
|
| - unsigned int arg_count,
|
| - const void* cmd_data) {
|
| +// Decode a command, and call the corresponding GL functions.
|
| +// NOTE: DoCommand() is slower than calling DoCommands() on larger batches
|
| +// of commands at once, and is now only used for tests that need to track
|
| +// individual commands.
|
| +error::Error GLES2DecoderImpl::DoCommand(unsigned int command,
|
| + unsigned int arg_count,
|
| + const void* cmd_data) {
|
| + return DoCommands(1, cmd_data, arg_count + 1, 0);
|
| +}
|
| +
|
| +// Decode multiple commands, and call the corresponding GL functions.
|
| +// NOTE: 'buffer' is a pointer to the command buffer. As such, it could be
|
| +// changed by a (malicious) client at any time, so if validation has to happen,
|
| +// it should operate on a copy of them.
|
| +// NOTE: This is duplicating code from AsyncAPIInterface::DoCommands() in the
|
| +// interest of performance in this critical execution loop.
|
| +error::Error GLES2DecoderImpl::DoCommands(unsigned int num_commands,
|
| + const void* buffer,
|
| + int num_entries,
|
| + int* entries_processed) {
|
| + commands_to_process_ = num_commands;
|
| error::Error result = error::kNoError;
|
| - if (log_commands()) {
|
| - // TODO(notme): Change this to a LOG/VLOG that works in release. Tried
|
| - // VLOG(1), no luck.
|
| - LOG(ERROR) << "[" << logger_.GetLogPrefix() << "]" << "cmd: "
|
| - << GetCommandName(command);
|
| - }
|
| - unsigned int command_index = command - kStartPoint - 1;
|
| - if (command_index < arraysize(command_info)) {
|
| - const CommandInfo& info = command_info[command_index];
|
| - unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
|
| - if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
|
| - (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
|
| - bool doing_gpu_trace = false;
|
| - if (gpu_trace_commands_) {
|
| - if (CMD_FLAG_GET_TRACE_LEVEL(info.cmd_flags) <= gpu_trace_level_) {
|
| - doing_gpu_trace = true;
|
| - gpu_tracer_->Begin(GetCommandName(command), kTraceDecoder);
|
| + const CommandBufferEntry* cmd_data =
|
| + static_cast<const CommandBufferEntry*>(buffer);
|
| + int process_pos = 0;
|
| + unsigned int command = 0;
|
| +
|
| + while (process_pos < num_entries && result == error::kNoError &&
|
| + commands_to_process_--) {
|
| + const unsigned int size = cmd_data->value_header.size;
|
| + command = cmd_data->value_header.command;
|
| +
|
| + if (size == 0) {
|
| + result = error::kInvalidSize;
|
| + break;
|
| + }
|
| +
|
| + if (static_cast<int>(size) + process_pos > num_entries) {
|
| + result = error::kOutOfBounds;
|
| + break;
|
| + }
|
| +
|
| + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cb_command"),
|
| + GetCommandName(command));
|
| +
|
| + if (log_commands()) {
|
| + LOG(ERROR) << "[" << logger_.GetLogPrefix() << "]"
|
| + << "cmd: " << GetCommandName(command);
|
| + }
|
| +
|
| + const unsigned int arg_count = size - 1;
|
| + unsigned int command_index = command - kStartPoint - 1;
|
| + if (command_index < arraysize(command_info)) {
|
| + const CommandInfo& info = command_info[command_index];
|
| + unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
|
| + if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
|
| + (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
|
| + bool doing_gpu_trace = false;
|
| + if (gpu_trace_commands_) {
|
| + if (CMD_FLAG_GET_TRACE_LEVEL(info.cmd_flags) <= gpu_trace_level_) {
|
| + doing_gpu_trace = true;
|
| + gpu_tracer_->Begin(GetCommandName(command), kTraceDecoder);
|
| + }
|
| }
|
| - }
|
|
|
| - uint32 immediate_data_size =
|
| - (arg_count - info_arg_count) * sizeof(CommandBufferEntry); // NOLINT
|
| + uint32 immediate_data_size = (arg_count - info_arg_count) *
|
| + sizeof(CommandBufferEntry); // NOLINT
|
|
|
| - result = (this->*info.cmd_handler)(immediate_data_size, cmd_data);
|
| + result = (this->*info.cmd_handler)(immediate_data_size, cmd_data);
|
|
|
| - if (doing_gpu_trace)
|
| - gpu_tracer_->End(kTraceDecoder);
|
| + if (doing_gpu_trace)
|
| + gpu_tracer_->End(kTraceDecoder);
|
|
|
| - if (debug()) {
|
| - GLenum error;
|
| - while ((error = glGetError()) != GL_NO_ERROR) {
|
| - LOG(ERROR) << "[" << logger_.GetLogPrefix() << "] "
|
| - << "GL ERROR: " << GLES2Util::GetStringEnum(error) << " : "
|
| - << GetCommandName(command);
|
| - LOCAL_SET_GL_ERROR(error, "DoCommand", "GL error from driver");
|
| + if (debug()) {
|
| + GLenum error;
|
| + while ((error = glGetError()) != GL_NO_ERROR) {
|
| + LOG(ERROR) << "[" << logger_.GetLogPrefix() << "] "
|
| + << "GL ERROR: " << GLES2Util::GetStringEnum(error)
|
| + << " : " << GetCommandName(command);
|
| + LOCAL_SET_GL_ERROR(error, "DoCommand", "GL error from driver");
|
| + }
|
| }
|
| + } else {
|
| + result = error::kInvalidArguments;
|
| }
|
| } else {
|
| - result = error::kInvalidArguments;
|
| + result = DoCommonCommand(command, arg_count, cmd_data);
|
| }
|
| - } else {
|
| - result = DoCommonCommand(command, arg_count, cmd_data);
|
| - }
|
| - if (result == error::kNoError && current_decoder_error_ != error::kNoError) {
|
| + if (result == error::kNoError &&
|
| + current_decoder_error_ != error::kNoError) {
|
| result = current_decoder_error_;
|
| current_decoder_error_ = error::kNoError;
|
| + }
|
| +
|
| + if (result != error::kDeferCommandUntilLater) {
|
| + process_pos += size;
|
| + cmd_data += size;
|
| + }
|
| + }
|
| +
|
| + if (entries_processed)
|
| + *entries_processed = process_pos;
|
| +
|
| + if (error::IsError(result)) {
|
| + LOG(ERROR) << "Error: " << result << " for Command "
|
| + << GetCommandName(command);
|
| }
|
| +
|
| return result;
|
| }
|
|
|
| @@ -5698,6 +5762,10 @@ void GLES2DecoderImpl::DoLinkProgram(GLuint program_id) {
|
| program_manager()->ClearUniforms(program);
|
| }
|
| }
|
| +
|
| + // LinkProgram can be very slow. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| };
|
|
|
| void GLES2DecoderImpl::DoTexParameterf(
|
| @@ -6826,7 +6894,11 @@ void GLES2DecoderImpl::DoCompileShader(GLuint client_id) {
|
| translator,
|
| feature_info_->feature_flags().angle_translated_shader_source ?
|
| ProgramManager::kANGLE : ProgramManager::kGL);
|
| -};
|
| +
|
| + // CompileShader can be very slow. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| +}
|
|
|
| void GLES2DecoderImpl::DoGetShaderiv(
|
| GLuint shader_id, GLenum pname, GLint* params) {
|
| @@ -8325,6 +8397,10 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage2D(
|
| texture_ref, target, level, internal_format,
|
| width, height, 1, border, 0, 0, true);
|
| }
|
| +
|
| + // This may be a slow command. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| return error::kNoError;
|
| }
|
|
|
| @@ -8472,6 +8548,10 @@ error::Error GLES2DecoderImpl::HandleTexImage2D(uint32 immediate_data_size,
|
| pixels, pixels_size};
|
| texture_manager()->ValidateAndDoTexImage2D(
|
| &texture_state_, &state_, &framebuffer_state_, args);
|
| +
|
| + // This may be a slow command. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| return error::kNoError;
|
| }
|
|
|
| @@ -8530,6 +8610,10 @@ void GLES2DecoderImpl::DoCompressedTexSubImage2D(
|
| // CompressedTexImage2D already cleared the texture.
|
| glCompressedTexSubImage2D(
|
| target, level, xoffset, yoffset, width, height, format, image_size, data);
|
| +
|
| + // This may be a slow command. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| }
|
|
|
| static void Clip(
|
| @@ -8675,6 +8759,10 @@ void GLES2DecoderImpl::DoCopyTexImage2D(
|
| texture_ref, target, level, internal_format, width, height, 1,
|
| border, internal_format, GL_UNSIGNED_BYTE, true);
|
| }
|
| +
|
| + // This may be a slow command. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| }
|
|
|
| void GLES2DecoderImpl::DoCopyTexSubImage2D(
|
| @@ -8785,6 +8873,10 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D(
|
| destX, destY, copyX, copyY,
|
| copyWidth, copyHeight);
|
| }
|
| +
|
| + // This may be a slow command. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| }
|
|
|
| bool GLES2DecoderImpl::ValidateTexSubImage2D(
|
| @@ -8915,6 +9007,10 @@ error::Error GLES2DecoderImpl::DoTexSubImage2D(
|
| target, level, xoffset, yoffset, width, height, format, type, data);
|
| }
|
| texture_manager()->SetLevelCleared(texture_ref, target, level, true);
|
| +
|
| + // This may be a slow command. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| return error::kNoError;
|
| }
|
|
|
| @@ -9401,6 +9497,10 @@ void GLES2DecoderImpl::DoSwapBuffers() {
|
| LoseContext(GL_UNKNOWN_CONTEXT_RESET_ARB);
|
| }
|
| }
|
| +
|
| + // This may be a slow command. Exit command processing to allow for
|
| + // context preemption and GPU watchdog checks.
|
| + ExitCommandProcessingEarly();
|
| }
|
|
|
| error::Error GLES2DecoderImpl::HandleEnableFeatureCHROMIUM(
|
|
|