Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(695)

Unified Diff: services/gfx/compositor/backend/gpu_output.cc

Issue 2009503003: Mozart: Reduce pipeline depth and unify frame queue. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: fix comments Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « services/gfx/compositor/backend/gpu_output.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: services/gfx/compositor/backend/gpu_output.cc
diff --git a/services/gfx/compositor/backend/gpu_output.cc b/services/gfx/compositor/backend/gpu_output.cc
index d52ef5a250e7c0f35da9e94f40725465be62dfd9..bab1167fc09b19a13784ad6f148458fb79916f9b 100644
--- a/services/gfx/compositor/backend/gpu_output.cc
+++ b/services/gfx/compositor/backend/gpu_output.cc
@@ -18,9 +18,9 @@
namespace compositor {
namespace {
constexpr const char* kPipelineDepthSwitch = "pipeline-depth";
-constexpr uint32_t kDefaultPipelineDepth = 2u; // ideally should be 1
+constexpr uint32_t kDefaultPipelineDepth = 1u;
constexpr uint32_t kMinPipelineDepth = 1u;
-constexpr uint32_t kMaxPipelineDepth = 10u;
+constexpr uint32_t kMaxPipelineDepth = 10u; // for experimentation
scoped_ptr<base::MessagePump> CreateMessagePumpMojo() {
return base::MessageLoop::CreateMessagePumpForType(
@@ -86,24 +86,48 @@ void GpuOutput::SubmitFrame(const scoped_refptr<RenderFrame>& frame) {
TRACE_EVENT0("gfx", "GpuOutput::SubmitFrame");
const int64_t submit_time = MojoGetTimeTicksNow();
- scoped_refptr<FrameData> frame_data(
- new FrameData(frame, submit_time)); // drop outside lock
+
+ // Note: we may swap an old frame into |frame_data| to keep alive until
+ // we exit the lock.
+ std::unique_ptr<FrameData> frame_data(new FrameData(frame, submit_time));
{
std::lock_guard<std::mutex> lock(shared_state_.mutex);
- TRACE_EVENT_FLOW_BEGIN0("gfx", "Frame Queued", frame_data.get());
- shared_state_.current_frame_data.swap(frame_data);
- if (frame_data && !frame_data->drawn) {
- // Dropped an undrawn frame.
- DVLOG(2) << "Rasterizer stalled, dropping frame to catch up.";
+ // Enqueue the frame, ensuring that the queue only contains at most
+ // one pending or scheduled frame. If the last frame hasn't been drawn by
+ // now then the rasterizer must be falling behind.
+ if (shared_state_.frames.empty() ||
+ shared_state_.frames.back()->state == FrameData::State::Drawing) {
+ // The queue is busy drawing. Enqueue the new frame at the end.
+ shared_state_.frames.emplace(std::move(frame_data));
+ } else if (shared_state_.frames.back()->state ==
+ FrameData::State::Finished) {
+ // The queue contains a finished frame which we had retained to prevent
+ // the queue from becoming empty and losing track of the current frame.
+ // Replace it with the new frame.
+ DCHECK(shared_state_.frames.size() == 1u);
+ shared_state_.frames.back().swap(frame_data);
+ } else {
+ // The queue already contains a pending frame which means the rasterizer
+ // has gotten so far behind it wasn't even able to issue the previous
+ // undrawn frame. Replace it with the new frame, thereby ensuring
+ // the queue never contains more than one pending frame at a time.
+ DCHECK(shared_state_.frames.back()->state == FrameData::State::Pending);
+ shared_state_.frames.back().swap(frame_data);
TRACE_EVENT_FLOW_END1("gfx", "Frame Queued", frame_data.get(), "drawn",
false);
+ DVLOG(2) << "Rasterizer stalled, dropped a frame to catch up.";
}
- // TODO(jeffbrown): If the draw queue is full, we should pause
+ TRACE_EVENT_FLOW_BEGIN0("gfx", "Frame Queued",
+ shared_state_.frames.back().get());
+
+ if (!shared_state_.rasterizer_ready)
+ return;
+
+ // TODO(jeffbrown): If the draw queue is overfull, we should pause
// scheduling until the queue drains.
- if (shared_state_.rasterizer_ready &&
- shared_state_.drawn_frames_awaiting_finish.size() < pipeline_depth_)
+ if (shared_state_.frames.size() <= pipeline_depth_)
ScheduleDrawLocked();
}
}
@@ -134,15 +158,14 @@ void GpuOutput::OnRasterizerReady(int64_t vsync_timebase,
if (shared_state_.rasterizer_ready)
return;
- DCHECK(shared_state_.drawn_frames_awaiting_finish.empty());
shared_state_.rasterizer_ready = true;
- if (!shared_state_.current_frame_data)
+ if (shared_state_.frames.empty())
return;
- shared_state_.current_frame_data->Recycle();
+ shared_state_.frames.back()->ResetDrawState();
TRACE_EVENT_FLOW_BEGIN0("gfx", "Frame Queued",
- shared_state_.current_frame_data.get());
+ shared_state_.frames.back().get());
ScheduleDrawLocked();
}
}
@@ -169,8 +192,9 @@ void GpuOutput::OnRasterizerError() {
}
void GpuOutput::ScheduleDrawLocked() {
- DCHECK(shared_state_.current_frame_data);
- DCHECK(!shared_state_.current_frame_data->drawn);
+ DCHECK(!shared_state_.frames.empty());
+ DCHECK(shared_state_.frames.back()->state == FrameData::State::Pending);
+ DCHECK(shared_state_.frames.size() <= pipeline_depth_);
if (shared_state_.draw_scheduled)
return;
@@ -184,32 +208,31 @@ void GpuOutput::OnDraw() {
DCHECK(rasterizer_task_runner_->RunsTasksOnCurrentThread());
TRACE_EVENT0("gfx", "GpuOutput::OnDraw");
- scoped_refptr<FrameData> frame_data; // used outside lock
+ FrameData* frame_data; // used outside lock
{
std::lock_guard<std::mutex> lock(shared_state_.mutex);
DCHECK(shared_state_.draw_scheduled);
- DCHECK(shared_state_.current_frame_data);
- DCHECK(!shared_state_.current_frame_data->drawn);
+ DCHECK(!shared_state_.frames.empty());
+ DCHECK(shared_state_.frames.back()->state == FrameData::State::Pending);
shared_state_.draw_scheduled = false;
-
- if (!shared_state_.rasterizer_ready ||
- shared_state_.drawn_frames_awaiting_finish.size() >= pipeline_depth_)
+ if (!shared_state_.rasterizer_ready)
return;
- frame_data = shared_state_.current_frame_data;
- frame_data->drawn = true;
- frame_data->draw_time = MojoGetTimeTicksNow();
- TRACE_EVENT_FLOW_END1("gfx", "Frame Queued", frame_data.get(), "drawn",
- true);
-
- TRACE_EVENT_ASYNC_BEGIN0("gfx", "Rasterize", frame_data.get());
- shared_state_.drawn_frames_awaiting_finish.emplace(frame_data);
+ frame_data = shared_state_.frames.back().get();
+ frame_data->state = FrameData::State::Drawing;
+ frame_data->draw_started_time = MojoGetTimeTicksNow();
+ TRACE_EVENT_FLOW_END1("gfx", "Frame Queued", frame_data, "drawn", true);
}
+ // It is safe to access |frame_data| outside of the lock here because
+ // it will not be dequeued until |OnRasterizerFinishedDraw| gets posted
+ // to this thread's message loop. Moreover |SubmitFrame| will not discard
+ // or replace the frame because its state is |Drawing|.
+ TRACE_EVENT_ASYNC_BEGIN0("gfx", "Rasterize", frame_data);
rasterizer_->DrawFrame(frame_data->frame);
- frame_data->wait_time = MojoGetTimeTicksNow();
+ frame_data->draw_issued_time = MojoGetTimeTicksNow();
}
void GpuOutput::OnRasterizerFinishedDraw(bool presented) {
@@ -217,20 +240,24 @@ void GpuOutput::OnRasterizerFinishedDraw(bool presented) {
TRACE_EVENT0("gfx", "GpuOutput::OnRasterizerFinishedDraw");
const int64_t finish_time = MojoGetTimeTicksNow();
- scoped_refptr<FrameData> frame_data; // drop outside lock
+
+ // Note: we may swap an old frame into |old_frame_data| to keep alive until
+ // we exit the lock.
+ std::unique_ptr<FrameData> old_frame_data;
{
std::lock_guard<std::mutex> lock(shared_state_.mutex);
DCHECK(shared_state_.rasterizer_ready);
- DCHECK(!shared_state_.drawn_frames_awaiting_finish.empty());
- size_t draw_queue_depth = shared_state_.drawn_frames_awaiting_finish.size();
- shared_state_.drawn_frames_awaiting_finish.front().swap(frame_data);
- shared_state_.drawn_frames_awaiting_finish.pop();
+ DCHECK(!shared_state_.frames.empty());
+
+ FrameData* frame_data = shared_state_.frames.front().get();
DCHECK(frame_data);
- DCHECK(frame_data->drawn);
- TRACE_EVENT_ASYNC_END1("gfx", "Rasterize", frame_data.get(), "presented",
+ DCHECK(frame_data->state == FrameData::State::Drawing);
+ TRACE_EVENT_ASYNC_END1("gfx", "Rasterize", frame_data, "presented",
presented);
+ frame_data->state = FrameData::State::Finished;
+
// TODO(jeffbrown): Adjust scheduler behavior based on observed timing.
// Note: These measurements don't account for systematic downstream delay
// in the display pipeline (how long it takes pixels to actually light up).
@@ -242,16 +269,17 @@ void GpuOutput::OnRasterizerFinishedDraw(bool presented) {
const int64_t frame_time = frame_info.frame_time;
const int64_t presentation_time = frame_info.presentation_time;
const int64_t composition_time = frame_metadata.composition_time();
- const int64_t draw_time = frame_data->draw_time;
- const int64_t wait_time = frame_data->wait_time;
+ const int64_t draw_started_time = frame_data->draw_started_time;
+ const int64_t draw_issued_time = frame_data->draw_issued_time;
const int64_t submit_time = frame_data->submit_time;
+ const size_t draw_queue_depth = shared_state_.frames.size();
DVLOG(2) << "Presented frame: composition latency "
<< (composition_time - frame_time) << " us, submission latency "
<< (submit_time - composition_time) << " us, queue latency "
- << (draw_time - submit_time) << " us, draw latency "
- << (wait_time - draw_time) << " us, GPU latency "
- << (finish_time - wait_time) << " us, total latency "
+ << (draw_started_time - submit_time) << " us, draw latency "
+ << (draw_issued_time - draw_started_time) << " us, GPU latency "
+ << (finish_time - draw_issued_time) << " us, total latency "
<< (finish_time - frame_time) << " us, presentation time error "
<< (finish_time - presentation_time) << " us"
<< ", draw queue depth " << draw_queue_depth;
@@ -259,9 +287,12 @@ void GpuOutput::OnRasterizerFinishedDraw(bool presented) {
DVLOG(2) << "Rasterizer dropped frame.";
}
- DCHECK(shared_state_.current_frame_data);
- if (!shared_state_.current_frame_data->drawn)
- ScheduleDrawLocked();
+ if (shared_state_.frames.size() > 1u) {
+ shared_state_.frames.front().swap(old_frame_data);
+ shared_state_.frames.pop();
+ if (shared_state_.frames.back()->state == FrameData::State::Pending)
+ ScheduleDrawLocked();
+ }
}
}
@@ -295,10 +326,10 @@ GpuOutput::FrameData::FrameData(const scoped_refptr<RenderFrame>& frame,
GpuOutput::FrameData::~FrameData() {}
-void GpuOutput::FrameData::Recycle() {
- drawn = false;
- draw_time = 0;
- wait_time = 0;
+void GpuOutput::FrameData::ResetDrawState() {
+ state = State::Pending;
+ draw_started_time = 0;
+ draw_issued_time = 0;
}
} // namespace compositor
« no previous file with comments | « services/gfx/compositor/backend/gpu_output.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698