summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-08 01:03:17 +0000
committerapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-08 01:03:17 +0000
commit5d00542d45b54da292f98791cdd912281e84618a (patch)
tree7a97a373989b5ab2d216304ecf691e75199b7ae5 /gpu
parent941bb6001f9fd8ad7455f64969aa0202de4fb0d9 (diff)
downloadchromium_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.h2
-rw-r--r--gpu/command_buffer/common/constants.h8
-rw-r--r--gpu/command_buffer/service/cmd_parser.cc3
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc13
-rw-r--r--gpu/command_buffer/service/gpu_processor.cc53
-rw-r--r--gpu/command_buffer/service/gpu_processor.h4
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_;