diff options
author | jbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-28 02:11:08 +0000 |
---|---|---|
committer | jbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-28 02:11:08 +0000 |
commit | a7266a9dc36aa68143d670eb8646f9d67237fa61 (patch) | |
tree | 783113824e460a2154aec46f401ead1f1ffd8e66 /gpu | |
parent | 0390d8c8d8c72dedb6bcb9ef39b96fbb8e6915b2 (diff) | |
download | chromium_src-a7266a9dc36aa68143d670eb8646f9d67237fa61.zip chromium_src-a7266a9dc36aa68143d670eb8646f9d67237fa61.tar.gz chromium_src-a7266a9dc36aa68143d670eb8646f9d67237fa61.tar.bz2 |
Defer descheduling of GPU commands until draw or swap
This CL adds support to Windows and Mac. Linux doesn't gain anything, because the GPU process is blocked on the actual SwapBuffers call (whereas Windows and Mac asynchronously notify the browser to execute the Swap).
The surface gets a chance to defer either Draws or Swaps. The surface can unschedule the GpuScheduler on the first attempt at a draw, for example, and reschedule it later when the draw is safe to execute (ie: when the pending SwapBuffers is acked by the browser).
Platforms with triple-buffered contexts can defer all the way until a Swap, while most platforms will use the draws to defer.
Review URL: https://chromiumcodereview.appspot.com/10389202
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144648 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
9 files changed, 47 insertions, 27 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 3426e3f..af6d353 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -872,7 +872,10 @@ _FUNCTION_INFO = { 'error_value': 'GL_FRAMEBUFFER_UNSUPPORTED', 'result': ['GLenum'], }, - 'Clear': {'decoder_func': 'DoClear'}, + 'Clear': { + 'type': 'Manual', + 'cmd_args': 'GLbitfield mask' + }, 'ClearColor': {'decoder_func': 'DoClearColor'}, 'ClearDepthf': { 'decoder_func': 'DoClearDepthf', diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 953f87f..ca3a9e7 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -971,6 +971,12 @@ GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM( return result; } +void GLES2Implementation::Clear(GLbitfield mask) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << this << "] glClear(" << mask << ")"); + helper_->Clear(mask); +} + void GLES2Implementation::DrawElements( GLenum mode, GLsizei count, GLenum type, const void* indices) { GPU_CLIENT_SINGLE_THREAD_CHECK(); diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index ee673ce..5432345 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -120,11 +120,7 @@ GLenum CheckFramebufferStatus(GLenum target) { return *result; } -void Clear(GLbitfield mask) { - GPU_CLIENT_SINGLE_THREAD_CHECK(); - GPU_CLIENT_LOG("[" << this << "] glClear(" << mask << ")"); - helper_->Clear(mask); -} +void Clear(GLbitfield mask); void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { GPU_CLIENT_SINGLE_THREAD_CHECK(); diff --git a/gpu/command_buffer/common/constants.h b/gpu/command_buffer/common/constants.h index 38a8c32..a2eeb74 100644 --- a/gpu/command_buffer/common/constants.h +++ b/gpu/command_buffer/common/constants.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -21,12 +21,13 @@ namespace error { kUnknownCommand, kInvalidArguments, kLostContext, - kGenericError + kGenericError, + kDeferCommandUntilLater }; // Return true if the given error code is an actual error. inline bool IsError(Error error) { - return error != kNoError; + return error != kNoError && error != kDeferCommandUntilLater; } // Provides finer grained information about why the context was lost. diff --git a/gpu/command_buffer/service/cmd_parser.cc b/gpu/command_buffer/service/cmd_parser.cc index a58d5a5..0ca1e61 100644 --- a/gpu/command_buffer/service/cmd_parser.cc +++ b/gpu/command_buffer/service/cmd_parser.cc @@ -79,7 +79,7 @@ error::Error CommandParser::ProcessCommand() { } // If get was not set somewhere else advance it. - if (get == get_) + if (get == get_ && result != error::kDeferCommandUntilLater) get_ = (get + header.size) % entry_count_; if (trace_gl_commands_) diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index bc7b9b8..0f2ef5c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -1003,7 +1003,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, GLenum DoCheckFramebufferStatus(GLenum target); // Wrapper for glClear - void DoClear(GLbitfield mask); + error::Error DoClear(GLbitfield mask); // Wrappers for clear and mask settings functions. void DoClearColor( @@ -1356,6 +1356,12 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, void RenderWarning(const std::string& msg); void PerformanceWarning(const std::string& msg); + bool ShouldDeferDraws() { + return !offscreen_target_frame_buffer_.get() && + bound_draw_framebuffer_ == NULL && + surface_->DeferDraws(); + } + // Generate a member function prototype for each command in an automated and // typesafe way. #define GLES2_CMD_OP(name) \ @@ -4243,13 +4249,22 @@ error::Error GLES2DecoderImpl::HandleRegisterSharedIdsCHROMIUM( return error::kNoError; } -void GLES2DecoderImpl::DoClear(GLbitfield mask) { +error::Error GLES2DecoderImpl::DoClear(GLbitfield mask) { + if (ShouldDeferDraws()) + return error::kDeferCommandUntilLater; if (CheckBoundFramebuffersValid("glClear")) { UNSHIPPED_TRACE_EVENT_INSTANT2("test_gpu", "DoClear", "red", clear_red_, "green", clear_green_); ApplyDirtyState(); glClear(mask); } + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleClear( + uint32 immediate_data_size, const gles2::Clear& c) { + GLbitfield mask = static_cast<GLbitfield>(c.mask); + return DoClear(mask); } void GLES2DecoderImpl::DoFramebufferRenderbuffer( @@ -5492,6 +5507,8 @@ error::Error GLES2DecoderImpl::DoDrawArrays( GLint first, GLsizei count, GLsizei primcount) { + if (ShouldDeferDraws()) + return error::kDeferCommandUntilLater; if (!validators_->draw_mode.IsValid(mode)) { SetGLError(GL_INVALID_ENUM, function_name, "mode GL_INVALID_ENUM"); return error::kNoError; @@ -5593,6 +5610,8 @@ error::Error GLES2DecoderImpl::DoDrawElements( GLenum type, int32 offset, GLsizei primcount) { + if (ShouldDeferDraws()) + return error::kDeferCommandUntilLater; if (!bound_element_array_buffer_) { SetGLError(GL_INVALID_OPERATION, function_name, "No element array buffer bound"); @@ -8204,6 +8223,10 @@ error::Error GLES2DecoderImpl::HandleShaderBinary( error::Error GLES2DecoderImpl::HandleSwapBuffers( uint32 immediate_data_size, const gles2::SwapBuffers& c) { bool is_offscreen = !!offscreen_target_frame_buffer_.get(); + if (!is_offscreen && surface_->DeferSwapBuffers()) { + return error::kDeferCommandUntilLater; + } + int this_frame_number = frame_number_++; // TRACE_EVENT for gpu tests: TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers", diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index ab06503..dc85cc2 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h @@ -223,13 +223,6 @@ error::Error GLES2DecoderImpl::HandleCheckFramebufferStatus( return error::kNoError; } -error::Error GLES2DecoderImpl::HandleClear( - uint32 immediate_data_size, const gles2::Clear& c) { - GLbitfield mask = static_cast<GLbitfield>(c.mask); - DoClear(mask); - return error::kNoError; -} - error::Error GLES2DecoderImpl::HandleClearColor( uint32 immediate_data_size, const gles2::ClearColor& c) { GLclampf red = static_cast<GLclampf>(c.red); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h index 495b16a..bd7dbd7 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h @@ -290,15 +290,8 @@ TEST_F(GLES2DecoderTest1, CheckFramebufferStatusInvalidArgsBadSharedMemoryId) { cmd.Init(GL_FRAMEBUFFER, shared_memory_id_, kInvalidSharedMemoryOffset); EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); } +// TODO(gman): Clear -TEST_F(GLES2DecoderTest1, ClearValidArgs) { - EXPECT_CALL(*gl_, Clear(1)); - SpecializedSetup<Clear, 0>(true); - Clear cmd; - cmd.Init(1); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); -} TEST_F(GLES2DecoderTest1, ClearColorValidArgs) { EXPECT_CALL(*gl_, ClearColor(1, 2, 3, 4)); diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc index 85d4f75..de83617 100644 --- a/gpu/command_buffer/service/gpu_scheduler.cc +++ b/gpu/command_buffer/service/gpu_scheduler.cc @@ -80,6 +80,11 @@ void GpuScheduler::PutChanged() { error = parser_->ProcessCommand(); + if (error == error::kDeferCommandUntilLater) { + DCHECK(unscheduled_count_ > 0); + return; + } + // TODO(piman): various classes duplicate various pieces of state, leading // to needlessly complex update logic. It should be possible to simply // share the state across all of them. |