1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
// 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.
#include "content/renderer/gpu/compositor_output_surface.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop_proxy.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_ack.h"
#include "cc/output/managed_memory_policy.h"
#include "cc/output/output_surface_client.h"
#include "content/common/gpu/client/command_buffer_proxy_impl.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/view_messages.h"
#include "content/public/common/content_switches.h"
#include "content/renderer/gpu/frame_swap_message_queue.h"
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "ipc/ipc_sync_channel.h"
namespace {
// There are several compositor surfaces in a process, but they share the same
// compositor thread, so we use a simple int here to track prefer-smoothness.
int g_prefer_smoothness_count = 0;
} // namespace
namespace content {
CompositorOutputSurface::CompositorOutputSurface(
int32 routing_id,
uint32 output_surface_id,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
scoped_ptr<cc::SoftwareOutputDevice> software_device,
scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue,
bool use_swap_compositor_frame_message)
: OutputSurface(context_provider, software_device.Pass()),
output_surface_id_(output_surface_id),
use_swap_compositor_frame_message_(use_swap_compositor_frame_message),
output_surface_filter_(
RenderThreadImpl::current()->compositor_message_filter()),
frame_swap_message_queue_(swap_frame_message_queue),
routing_id_(routing_id),
prefers_smoothness_(false),
#if defined(OS_WIN)
// TODO(epenner): Implement PlatformThread::CurrentHandle() on windows.
main_thread_handle_(base::PlatformThreadHandle()),
#else
main_thread_handle_(base::PlatformThread::CurrentHandle()),
#endif
layout_test_mode_(RenderThreadImpl::current()->layout_test_mode()),
weak_ptrs_(this) {
DCHECK(output_surface_filter_.get());
DCHECK(frame_swap_message_queue_.get());
DetachFromThread();
message_sender_ = RenderThreadImpl::current()->sync_message_filter();
DCHECK(message_sender_.get());
if (OutputSurface::software_device())
capabilities_.max_frames_pending = 1;
}
CompositorOutputSurface::~CompositorOutputSurface() {
DCHECK(CalledOnValidThread());
if (!HasClient())
return;
UpdateSmoothnessTakesPriority(false);
if (output_surface_proxy_.get())
output_surface_proxy_->ClearOutputSurface();
output_surface_filter_->RemoveHandlerOnCompositorThread(
routing_id_,
output_surface_filter_handler_);
}
bool CompositorOutputSurface::BindToClient(
cc::OutputSurfaceClient* client) {
DCHECK(CalledOnValidThread());
if (!cc::OutputSurface::BindToClient(client))
return false;
output_surface_proxy_ = new CompositorOutputSurfaceProxy(this);
output_surface_filter_handler_ =
base::Bind(&CompositorOutputSurfaceProxy::OnMessageReceived,
output_surface_proxy_);
output_surface_filter_->AddHandlerOnCompositorThread(
routing_id_,
output_surface_filter_handler_);
if (!context_provider()) {
// Without a GPU context, the memory policy otherwise wouldn't be set.
client->SetMemoryPolicy(cc::ManagedMemoryPolicy(
128 * 1024 * 1024,
gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
base::SharedMemory::GetHandleLimit() / 3));
}
return true;
}
void CompositorOutputSurface::ShortcutSwapAck(
uint32 output_surface_id,
scoped_ptr<cc::GLFrameData> gl_frame_data,
scoped_ptr<cc::SoftwareFrameData> software_frame_data) {
if (!layout_test_previous_frame_ack_) {
layout_test_previous_frame_ack_.reset(new cc::CompositorFrameAck);
layout_test_previous_frame_ack_->gl_frame_data.reset(new cc::GLFrameData);
}
OnSwapAck(output_surface_id, *layout_test_previous_frame_ack_);
layout_test_previous_frame_ack_->gl_frame_data = gl_frame_data.Pass();
layout_test_previous_frame_ack_->last_software_frame_id =
software_frame_data ? software_frame_data->id : 0;
}
void CompositorOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
DCHECK(use_swap_compositor_frame_message_);
if (layout_test_mode_) {
// This code path is here to support layout tests that are currently
// doing a readback in the renderer instead of the browser. So they
// are using deprecated code paths in the renderer and don't need to
// actually swap anything to the browser. We shortcut the swap to the
// browser here and just ack directly within the renderer process.
// Once crbug.com/311404 is fixed, this can be removed.
// This would indicate that crbug.com/311404 is being fixed, and this
// block needs to be removed.
DCHECK(!frame->delegated_frame_data);
base::Closure closure =
base::Bind(&CompositorOutputSurface::ShortcutSwapAck,
weak_ptrs_.GetWeakPtr(),
output_surface_id_,
base::Passed(&frame->gl_frame_data),
base::Passed(&frame->software_frame_data));
if (context_provider()) {
gpu::gles2::GLES2Interface* context = context_provider()->ContextGL();
context->Flush();
uint32 sync_point = context->InsertSyncPointCHROMIUM();
context_provider()->ContextSupport()->SignalSyncPoint(sync_point,
closure);
} else {
base::MessageLoopProxy::current()->PostTask(FROM_HERE, closure);
}
client_->DidSwapBuffers();
return;
} else {
{
ScopedVector<IPC::Message> messages;
std::vector<IPC::Message> messages_to_deliver_with_frame;
scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope =
frame_swap_message_queue_->AcquireSendMessageScope();
frame_swap_message_queue_->DrainMessages(&messages);
FrameSwapMessageQueue::TransferMessages(messages,
&messages_to_deliver_with_frame);
Send(new ViewHostMsg_SwapCompositorFrame(routing_id_,
output_surface_id_,
*frame,
messages_to_deliver_with_frame));
// ~send_message_scope.
}
client_->DidSwapBuffers();
}
}
void CompositorOutputSurface::OnMessageReceived(const IPC::Message& message) {
DCHECK(CalledOnValidThread());
if (!HasClient())
return;
IPC_BEGIN_MESSAGE_MAP(CompositorOutputSurface, message)
IPC_MESSAGE_HANDLER(ViewMsg_UpdateVSyncParameters,
OnUpdateVSyncParametersFromBrowser);
IPC_MESSAGE_HANDLER(ViewMsg_SwapCompositorFrameAck, OnSwapAck);
IPC_MESSAGE_HANDLER(ViewMsg_ReclaimCompositorResources, OnReclaimResources);
IPC_END_MESSAGE_MAP()
}
void CompositorOutputSurface::OnUpdateVSyncParametersFromBrowser(
base::TimeTicks timebase,
base::TimeDelta interval) {
DCHECK(CalledOnValidThread());
CommitVSyncParameters(timebase, interval);
}
void CompositorOutputSurface::OnSwapAck(uint32 output_surface_id,
const cc::CompositorFrameAck& ack) {
// Ignore message if it's a stale one coming from a different output surface
// (e.g. after a lost context).
if (output_surface_id != output_surface_id_)
return;
ReclaimResources(&ack);
client_->DidSwapBuffersComplete();
}
void CompositorOutputSurface::OnReclaimResources(
uint32 output_surface_id,
const cc::CompositorFrameAck& ack) {
// Ignore message if it's a stale one coming from a different output surface
// (e.g. after a lost context).
if (output_surface_id != output_surface_id_)
return;
ReclaimResources(&ack);
}
bool CompositorOutputSurface::Send(IPC::Message* message) {
return message_sender_->Send(message);
}
namespace {
#if defined(OS_ANDROID)
void SetThreadPriorityToIdle(base::PlatformThreadHandle handle) {
base::PlatformThread::SetThreadPriority(
handle, base::kThreadPriority_Background);
}
void SetThreadPriorityToDefault(base::PlatformThreadHandle handle) {
base::PlatformThread::SetThreadPriority(
handle, base::kThreadPriority_Normal);
}
#else
void SetThreadPriorityToIdle(base::PlatformThreadHandle handle) {}
void SetThreadPriorityToDefault(base::PlatformThreadHandle handle) {}
#endif
}
void CompositorOutputSurface::UpdateSmoothnessTakesPriority(
bool prefers_smoothness) {
#ifndef NDEBUG
// If we use different compositor threads, we need to
// use an atomic int to track prefer smoothness count.
base::PlatformThreadId g_last_thread = base::PlatformThread::CurrentId();
DCHECK_EQ(g_last_thread, base::PlatformThread::CurrentId());
#endif
if (prefers_smoothness_ == prefers_smoothness)
return;
// If this is the first surface to start preferring smoothness,
// Throttle the main thread's priority.
if (prefers_smoothness_ == false &&
++g_prefer_smoothness_count == 1) {
SetThreadPriorityToIdle(main_thread_handle_);
}
// If this is the last surface to stop preferring smoothness,
// Reset the main thread's priority to the default.
if (prefers_smoothness_ == true &&
--g_prefer_smoothness_count == 0) {
SetThreadPriorityToDefault(main_thread_handle_);
}
prefers_smoothness_ = prefers_smoothness;
}
} // namespace content
|