diff options
author | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-08 01:03:17 +0000 |
---|---|---|
committer | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-08 01:03:17 +0000 |
commit | 5d00542d45b54da292f98791cdd912281e84618a (patch) | |
tree | 7a97a373989b5ab2d216304ecf691e75199b7ae5 /gpu | |
parent | 941bb6001f9fd8ad7455f64969aa0202de4fb0d9 (diff) | |
download | chromium_src-5d00542d45b54da292f98791cdd912281e84618a.zip chromium_src-5d00542d45b54da292f98791cdd912281e84618a.tar.gz chromium_src-5d00542d45b54da292f98791cdd912281e84618a.tar.bz2 |
Implemented GPU process side flow control.
Only one frame of GL calls are allowed to be pending presentation at a time. This reduced "jitter" for both ANGLE and GL. Also tuned client side flow control for minimal "jitter". Finally, I made the GPU scheduler prioritise command buffers directed at a window (i.e. the compositor's contexts) over those directed at offscreen targets.
TEST=trybots, watch fish in WebGL Aquarium and see if they jitter with and without vsync lock enabled, scientific experiments on gman
BUG=none
Review URL: http://codereview.chromium.org/6250166
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74071 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/command_buffer/client/gles2_implementation.h | 2 | ||||
-rw-r--r-- | gpu/command_buffer/common/constants.h | 8 | ||||
-rw-r--r-- | gpu/command_buffer/service/cmd_parser.cc | 3 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 13 | ||||
-rw-r--r-- | gpu/command_buffer/service/gpu_processor.cc | 53 | ||||
-rw-r--r-- | gpu/command_buffer/service/gpu_processor.h | 4 |
6 files changed, 75 insertions, 8 deletions
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 1017ef1..57db856 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h @@ -70,7 +70,7 @@ class GLES2Implementation { static const GLuint kClientSideElementArrayId = 0xFEDCBA99u; // Number of swap buffers allowed before waiting. - static const size_t kMaxSwapBuffers = 2; + static const size_t kMaxSwapBuffers = 1; GLES2Implementation( GLES2CmdHelper* helper, diff --git a/gpu/command_buffer/common/constants.h b/gpu/command_buffer/common/constants.h index e884e2f..79b0048 100644 --- a/gpu/command_buffer/common/constants.h +++ b/gpu/command_buffer/common/constants.h @@ -21,7 +21,13 @@ namespace error { kUnknownCommand, kInvalidArguments, kLostContext, - kGenericError + kGenericError, + + // This is not an error. It is returned by commands to mark a position + // in the command buffer that should not be issued to the the GL backend + // until no more than a fixed number of such positions have already been + // issued. + kThrottle }; } diff --git a/gpu/command_buffer/service/cmd_parser.cc b/gpu/command_buffer/service/cmd_parser.cc index 6d66628..47a2b5a 100644 --- a/gpu/command_buffer/service/cmd_parser.cc +++ b/gpu/command_buffer/service/cmd_parser.cc @@ -55,10 +55,11 @@ error::Error CommandParser::ProcessCommand() { error::Error result = handler_->DoCommand( header.command, header.size - 1, buffer_ + get); + // TODO(gman): If you want to log errors this is the best place to catch them. // It seems like we need an official way to turn on a debug mode and // get these errors. - if (result != error::kNoError) { + if (result != error::kNoError && result != error::kThrottle) { ReportError(header.command, result); } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 3d7be0d..f145f35 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -6017,7 +6017,7 @@ error::Error GLES2DecoderImpl::HandleSwapBuffers( if (swap_buffers_callback_.get()) { swap_buffers_callback_->Run(); } - return error::kNoError; + return error::kThrottle; } else { ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id()); @@ -6039,7 +6039,7 @@ error::Error GLES2DecoderImpl::HandleSwapBuffers( if (swap_buffers_callback_.get()) { swap_buffers_callback_->Run(); } - return error::kNoError; + return error::kThrottle; } } else { if (!context_->SwapBuffers()) { @@ -6052,7 +6052,14 @@ error::Error GLES2DecoderImpl::HandleSwapBuffers( swap_buffers_callback_->Run(); } - return error::kNoError; + // Do not throttle SwapBuffers by returning kThrottle. The intent of + // throttling the offscreen command buffers to a fixed number of frames + // ahead is to prevent them from rendering faster than they can be + // presented, not to limit the rate at which we present. + // + // This does not hold for ANGLE, possibly because all the GL contexts in a + // share group are actually one D3D device. Found by trial and error. + return IsAngle() ? error::kThrottle : error::kNoError; } error::Error GLES2DecoderImpl::HandleCommandBufferEnableCHROMIUM( diff --git a/gpu/command_buffer/service/gpu_processor.cc b/gpu/command_buffer/service/gpu_processor.cc index 57d9052..b36db6a 100644 --- a/gpu/command_buffer/service/gpu_processor.cc +++ b/gpu/command_buffer/service/gpu_processor.cc @@ -2,20 +2,25 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "gpu/command_buffer/service/gpu_processor.h" + +#include "app/gfx/gl/gl_bindings.h" #include "base/callback.h" #include "base/compiler_specific.h" #include "base/message_loop.h" #include "app/gfx/gl/gl_context.h" -#include "gpu/command_buffer/service/gpu_processor.h" using ::base::SharedMemory; +static size_t kNumThrottleFences = 1; + namespace gpu { GPUProcessor::GPUProcessor(CommandBuffer* command_buffer, gles2::ContextGroup* group) : command_buffer_(command_buffer), commands_per_update_(100), + num_throttle_fences_(0), #if defined(OS_MACOSX) swap_buffers_count_(0), acknowledged_swap_buffers_count_(0), @@ -32,6 +37,7 @@ GPUProcessor::GPUProcessor(CommandBuffer* command_buffer, int commands_per_update) : command_buffer_(command_buffer), commands_per_update_(commands_per_update), + num_throttle_fences_(0), #if defined(OS_MACOSX) swap_buffers_count_(0), acknowledged_swap_buffers_count_(0), @@ -54,6 +60,19 @@ bool GPUProcessor::InitializeCommon(gfx::GLContext* context, uint32 parent_texture_id) { DCHECK(context); + if (!context->MakeCurrent()) + return false; + + // If the NV_fence extension is present, use fences to defer the issue of + // commands once a certain fixed number of frames have been rendered. + num_throttle_fences_ = + context->HasExtension("GL_NV_fence") ? kNumThrottleFences : 0; + + // Do not limit to a certain number of commands before scheduling another + // update when rendering onscreen. + if (!context->IsOffscreen()) + commands_per_update_ = INT_MAX; + // Map the ring buffer and create the parser. Buffer ring_buffer = command_buffer_->GetRingBuffer(); if (ring_buffer.ptr) { @@ -129,10 +148,40 @@ void GPUProcessor::ProcessCommands() { } #endif + // Defer this command until the fence queue is not full. + while (num_throttle_fences_ > 0 && + throttle_fences_.size() >= num_throttle_fences_) { + GLuint fence = throttle_fences_.front(); + if (!glTestFenceNV(fence)) { + ScheduleProcessCommands(); + return; + } + + glDeleteFencesNV(1, &fence); + throttle_fences_.pop(); + } + int commands_processed = 0; while (commands_processed < commands_per_update_ && !parser_->IsEmpty()) { error::Error error = parser_->ProcessCommand(); - if (error != error::kNoError) { + + // If the command indicated it should be throttled, insert a new fence into + // the fence queue. + if (error == error::kThrottle) { + if (num_throttle_fences_ > 0 && + throttle_fences_.size() < num_throttle_fences_) { + GLuint fence; + glGenFencesNV(1, &fence); + glSetFenceNV(fence, GL_ALL_COMPLETED_NV); + throttle_fences_.push(fence); + + // Neither glTestFenceNV or glSetFenceNV are guaranteed to flush. + // Without an explicit flush, the glTestFenceNV loop might never + // make progress. + glFlush(); + break; + } + } else if (error != error::kNoError) { command_buffer_->SetParseError(error); return; } diff --git a/gpu/command_buffer/service/gpu_processor.h b/gpu/command_buffer/service/gpu_processor.h index 4446ba8..b76b6e3 100644 --- a/gpu/command_buffer/service/gpu_processor.h +++ b/gpu/command_buffer/service/gpu_processor.h @@ -5,6 +5,7 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_ #define GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_ +#include <queue> #include <vector> #include "app/surface/transport_dib.h" @@ -138,6 +139,9 @@ class GPUProcessor : public CommandBufferEngine { scoped_ptr<gles2::GLES2Decoder> decoder_; scoped_ptr<CommandParser> parser_; + size_t num_throttle_fences_; + std::queue<unsigned> throttle_fences_; + #if defined(OS_MACOSX) scoped_ptr<AcceleratedSurface> surface_; uint64 swap_buffers_count_; |