OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/output/output_surface.h" | 5 #include "cc/output/output_surface.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/debug/trace_event.h" |
12 #include "base/logging.h" | 13 #include "base/logging.h" |
13 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
14 #include "base/strings/string_split.h" | 15 #include "base/strings/string_split.h" |
15 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
16 #include "cc/output/compositor_frame.h" | 17 #include "cc/output/compositor_frame.h" |
17 #include "cc/output/output_surface_client.h" | 18 #include "cc/output/output_surface_client.h" |
| 19 #include "cc/scheduler/delay_based_time_source.h" |
18 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" | 20 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" |
19 #include "third_party/khronos/GLES2/gl2.h" | 21 #include "third_party/khronos/GLES2/gl2.h" |
20 #include "third_party/khronos/GLES2/gl2ext.h" | 22 #include "third_party/khronos/GLES2/gl2ext.h" |
21 #include "ui/gfx/rect.h" | 23 #include "ui/gfx/rect.h" |
22 #include "ui/gfx/size.h" | 24 #include "ui/gfx/size.h" |
23 | 25 |
24 using std::set; | 26 using std::set; |
25 using std::string; | 27 using std::string; |
26 using std::vector; | 28 using std::vector; |
27 | 29 |
28 namespace cc { | 30 namespace cc { |
29 | 31 |
30 class OutputSurfaceCallbacks | 32 class OutputSurfaceCallbacks |
31 : public WebKit::WebGraphicsContext3D:: | 33 : public WebKit::WebGraphicsContext3D:: |
32 WebGraphicsSwapBuffersCompleteCallbackCHROMIUM, | 34 WebGraphicsSwapBuffersCompleteCallbackCHROMIUM, |
33 public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback { | 35 public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback { |
34 public: | 36 public: |
35 explicit OutputSurfaceCallbacks(OutputSurfaceClient* client) | 37 explicit OutputSurfaceCallbacks(OutputSurface* client) |
36 : client_(client) { | 38 : client_(client) { |
37 DCHECK(client_); | 39 DCHECK(client_); |
38 } | 40 } |
39 | 41 |
40 // WK:WGC3D::WGSwapBuffersCompleteCallbackCHROMIUM implementation. | 42 // WK:WGC3D::WGSwapBuffersCompleteCallbackCHROMIUM implementation. |
41 virtual void onSwapBuffersComplete() { client_->OnSwapBuffersComplete(NULL); } | 43 virtual void onSwapBuffersComplete() { client_->OnSwapBuffersComplete(NULL); } |
42 | 44 |
43 // WK:WGC3D::WGContextLostCallback implementation. | 45 // WK:WGC3D::WGContextLostCallback implementation. |
44 virtual void onContextLost() { client_->DidLoseOutputSurface(); } | 46 virtual void onContextLost() { client_->DidLoseOutputSurface(); } |
45 | 47 |
46 private: | 48 private: |
47 OutputSurfaceClient* client_; | 49 OutputSurface* client_; |
48 }; | 50 }; |
49 | 51 |
50 OutputSurface::OutputSurface( | 52 OutputSurface::OutputSurface( |
51 scoped_ptr<WebKit::WebGraphicsContext3D> context3d) | 53 scoped_ptr<WebKit::WebGraphicsContext3D> context3d) |
52 : client_(NULL), | 54 : context3d_(context3d.Pass()), |
53 context3d_(context3d.Pass()), | |
54 has_gl_discard_backbuffer_(false), | 55 has_gl_discard_backbuffer_(false), |
55 has_swap_buffers_complete_callback_(false), | 56 has_swap_buffers_complete_callback_(false), |
56 device_scale_factor_(-1), | 57 device_scale_factor_(-1), |
57 weak_ptr_factory_(this) { | 58 weak_ptr_factory_(this), |
| 59 max_frames_pending_(0), |
| 60 pending_swap_buffers_(0), |
| 61 begin_frame_pending_(false), |
| 62 client_(NULL) { |
58 } | 63 } |
59 | 64 |
60 OutputSurface::OutputSurface( | 65 OutputSurface::OutputSurface( |
61 scoped_ptr<cc::SoftwareOutputDevice> software_device) | 66 scoped_ptr<cc::SoftwareOutputDevice> software_device) |
62 : client_(NULL), | 67 : software_device_(software_device.Pass()), |
63 software_device_(software_device.Pass()), | |
64 has_gl_discard_backbuffer_(false), | 68 has_gl_discard_backbuffer_(false), |
65 has_swap_buffers_complete_callback_(false), | 69 has_swap_buffers_complete_callback_(false), |
66 device_scale_factor_(-1), | 70 device_scale_factor_(-1), |
67 weak_ptr_factory_(this) { | 71 weak_ptr_factory_(this), |
| 72 max_frames_pending_(0), |
| 73 pending_swap_buffers_(0), |
| 74 begin_frame_pending_(false), |
| 75 client_(NULL) { |
68 } | 76 } |
69 | 77 |
70 OutputSurface::OutputSurface( | 78 OutputSurface::OutputSurface( |
71 scoped_ptr<WebKit::WebGraphicsContext3D> context3d, | 79 scoped_ptr<WebKit::WebGraphicsContext3D> context3d, |
72 scoped_ptr<cc::SoftwareOutputDevice> software_device) | 80 scoped_ptr<cc::SoftwareOutputDevice> software_device) |
73 : client_(NULL), | 81 : context3d_(context3d.Pass()), |
74 context3d_(context3d.Pass()), | |
75 software_device_(software_device.Pass()), | 82 software_device_(software_device.Pass()), |
76 has_gl_discard_backbuffer_(false), | 83 has_gl_discard_backbuffer_(false), |
77 has_swap_buffers_complete_callback_(false), | 84 has_swap_buffers_complete_callback_(false), |
78 device_scale_factor_(-1), | 85 device_scale_factor_(-1), |
79 weak_ptr_factory_(this) { | 86 weak_ptr_factory_(this), |
| 87 max_frames_pending_(0), |
| 88 pending_swap_buffers_(0), |
| 89 begin_frame_pending_(false), |
| 90 client_(NULL) { |
| 91 } |
| 92 |
| 93 void OutputSurface::InitializeBeginFrameEmulation( |
| 94 Thread* thread, |
| 95 bool throttle_frame_production, |
| 96 base::TimeDelta interval) { |
| 97 if (throttle_frame_production){ |
| 98 frame_rate_controller_.reset( |
| 99 new FrameRateController( |
| 100 DelayBasedTimeSource::Create(interval, thread))); |
| 101 } else { |
| 102 frame_rate_controller_.reset(new FrameRateController(thread)); |
| 103 } |
| 104 |
| 105 frame_rate_controller_->SetClient(this); |
| 106 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending_); |
| 107 |
| 108 // The new frame rate controller will consume the swap acks of the old |
| 109 // frame rate controller, so we set that expectation up here. |
| 110 for (int i = 0; i < pending_swap_buffers_; i++) |
| 111 frame_rate_controller_->DidSwapBuffers(); |
| 112 } |
| 113 |
| 114 void OutputSurface::SetMaxFramesPending(int max_frames_pending) { |
| 115 if (frame_rate_controller_) |
| 116 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending); |
| 117 max_frames_pending_ = max_frames_pending; |
| 118 } |
| 119 |
| 120 void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase, |
| 121 base::TimeDelta interval) { |
| 122 TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged", |
| 123 "timebase", (timebase - base::TimeTicks()).InSecondsF(), |
| 124 "interval", interval.InSecondsF()); |
| 125 if (frame_rate_controller_) |
| 126 frame_rate_controller_->SetTimebaseAndInterval(timebase, interval); |
| 127 } |
| 128 |
| 129 void OutputSurface::FrameRateControllerTick(bool throttled) { |
| 130 DCHECK(frame_rate_controller_); |
| 131 if (!throttled) |
| 132 BeginFrame(frame_rate_controller_->LastTickTime()); |
| 133 } |
| 134 |
| 135 // Forwarded to OutputSurfaceClient |
| 136 void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) { |
| 137 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect"); |
| 138 client_->SetNeedsRedrawRect(damage_rect); |
| 139 } |
| 140 |
| 141 void OutputSurface::SetNeedsBeginFrame(bool enable) { |
| 142 TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginFrame", "enable", enable); |
| 143 begin_frame_pending_ = false; |
| 144 if (frame_rate_controller_) |
| 145 frame_rate_controller_->SetActive(enable); |
| 146 } |
| 147 |
| 148 void OutputSurface::BeginFrame(base::TimeTicks frame_time) { |
| 149 if (begin_frame_pending_ || |
| 150 (pending_swap_buffers_ >= max_frames_pending_ && max_frames_pending_ > 0)) |
| 151 return; |
| 152 TRACE_EVENT1("cc", "OutputSurface::BeginFrame", |
| 153 "pending_swap_buffers_", pending_swap_buffers_); |
| 154 begin_frame_pending_ = true; |
| 155 client_->BeginFrame(frame_time); |
| 156 } |
| 157 |
| 158 void OutputSurface::DidSwapBuffers() { |
| 159 begin_frame_pending_ = false; |
| 160 pending_swap_buffers_++; |
| 161 TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers", |
| 162 "pending_swap_buffers_", pending_swap_buffers_); |
| 163 if (frame_rate_controller_) |
| 164 frame_rate_controller_->DidSwapBuffers(); |
| 165 } |
| 166 |
| 167 void OutputSurface::OnSwapBuffersComplete(const CompositorFrameAck* ack) { |
| 168 pending_swap_buffers_--; |
| 169 TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete", |
| 170 "pending_swap_buffers_", pending_swap_buffers_); |
| 171 client_->OnSwapBuffersComplete(ack); |
| 172 if (frame_rate_controller_) |
| 173 frame_rate_controller_->DidSwapBuffersComplete(); |
| 174 } |
| 175 |
| 176 void OutputSurface::DidLoseOutputSurface() { |
| 177 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface"); |
| 178 begin_frame_pending_ = false; |
| 179 pending_swap_buffers_ = 0; |
| 180 client_->DidLoseOutputSurface(); |
| 181 } |
| 182 |
| 183 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform, |
| 184 gfx::Rect viewport) { |
| 185 client_->SetExternalDrawConstraints(transform, viewport); |
80 } | 186 } |
81 | 187 |
82 OutputSurface::~OutputSurface() { | 188 OutputSurface::~OutputSurface() { |
| 189 if (frame_rate_controller_) |
| 190 frame_rate_controller_->SetActive(false); |
83 } | 191 } |
84 | 192 |
85 bool OutputSurface::ForcedDrawToSoftwareDevice() const { | 193 bool OutputSurface::ForcedDrawToSoftwareDevice() const { |
86 return false; | 194 return false; |
87 } | 195 } |
88 | 196 |
89 bool OutputSurface::BindToClient( | 197 bool OutputSurface::BindToClient(cc::OutputSurfaceClient* client) { |
90 cc::OutputSurfaceClient* client) { | |
91 DCHECK(client); | 198 DCHECK(client); |
92 client_ = client; | 199 client_ = client; |
93 bool success = true; | 200 bool success = true; |
94 | 201 |
95 if (context3d_) { | 202 if (context3d_) { |
96 success = context3d_->makeContextCurrent(); | 203 success = context3d_->makeContextCurrent(); |
97 if (success) | 204 if (success) |
98 SetContext3D(context3d_.Pass()); | 205 SetContext3D(context3d_.Pass()); |
99 } | 206 } |
100 | 207 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 vector<string> extensions_list; | 243 vector<string> extensions_list; |
137 base::SplitString(extensions_string, ' ', &extensions_list); | 244 base::SplitString(extensions_string, ' ', &extensions_list); |
138 set<string> extensions(extensions_list.begin(), extensions_list.end()); | 245 set<string> extensions(extensions_list.begin(), extensions_list.end()); |
139 has_gl_discard_backbuffer_ = | 246 has_gl_discard_backbuffer_ = |
140 extensions.count("GL_CHROMIUM_discard_backbuffer") > 0; | 247 extensions.count("GL_CHROMIUM_discard_backbuffer") > 0; |
141 has_swap_buffers_complete_callback_ = | 248 has_swap_buffers_complete_callback_ = |
142 extensions.count("GL_CHROMIUM_swapbuffers_complete_callback") > 0; | 249 extensions.count("GL_CHROMIUM_swapbuffers_complete_callback") > 0; |
143 | 250 |
144 | 251 |
145 context3d_ = context3d.Pass(); | 252 context3d_ = context3d.Pass(); |
146 callbacks_.reset(new OutputSurfaceCallbacks(client_)); | 253 callbacks_.reset(new OutputSurfaceCallbacks(this)); |
147 context3d_->setSwapBuffersCompleteCallbackCHROMIUM(callbacks_.get()); | 254 context3d_->setSwapBuffersCompleteCallbackCHROMIUM(callbacks_.get()); |
148 context3d_->setContextLostCallback(callbacks_.get()); | 255 context3d_->setContextLostCallback(callbacks_.get()); |
149 } | 256 } |
150 | 257 |
151 void OutputSurface::EnsureBackbuffer() { | 258 void OutputSurface::EnsureBackbuffer() { |
152 DCHECK(context3d_); | 259 DCHECK(context3d_); |
153 if (has_gl_discard_backbuffer_) | 260 if (has_gl_discard_backbuffer_) |
154 context3d_->ensureBackbufferCHROMIUM(); | 261 context3d_->ensureBackbufferCHROMIUM(); |
155 } | 262 } |
156 | 263 |
(...skipping 22 matching lines...) Expand all Loading... |
179 } | 286 } |
180 | 287 |
181 void OutputSurface::BindFramebuffer() { | 288 void OutputSurface::BindFramebuffer() { |
182 DCHECK(context3d_); | 289 DCHECK(context3d_); |
183 context3d_->bindFramebuffer(GL_FRAMEBUFFER, 0); | 290 context3d_->bindFramebuffer(GL_FRAMEBUFFER, 0); |
184 } | 291 } |
185 | 292 |
186 void OutputSurface::SwapBuffers(cc::CompositorFrame* frame) { | 293 void OutputSurface::SwapBuffers(cc::CompositorFrame* frame) { |
187 if (frame->software_frame_data) { | 294 if (frame->software_frame_data) { |
188 PostSwapBuffersComplete(); | 295 PostSwapBuffersComplete(); |
| 296 DidSwapBuffers(); |
189 return; | 297 return; |
190 } | 298 } |
191 | 299 |
192 DCHECK(context3d_); | 300 DCHECK(context3d_); |
193 DCHECK(frame->gl_frame_data); | 301 DCHECK(frame->gl_frame_data); |
194 | 302 |
195 if (frame->gl_frame_data->partial_swap_allowed) { | 303 if (frame->gl_frame_data->partial_swap_allowed) { |
196 gfx::Rect sub_buffer_rect = frame->gl_frame_data->sub_buffer_rect; | 304 gfx::Rect sub_buffer_rect = frame->gl_frame_data->sub_buffer_rect; |
197 context3d()->postSubBufferCHROMIUM(sub_buffer_rect.x(), | 305 context3d()->postSubBufferCHROMIUM(sub_buffer_rect.x(), |
198 sub_buffer_rect.y(), | 306 sub_buffer_rect.y(), |
199 sub_buffer_rect.width(), | 307 sub_buffer_rect.width(), |
200 sub_buffer_rect.height()); | 308 sub_buffer_rect.height()); |
201 } else { | 309 } else { |
202 // Note that currently this has the same effect as SwapBuffers; we should | 310 // Note that currently this has the same effect as SwapBuffers; we should |
203 // consider exposing a different entry point on WebGraphicsContext3D. | 311 // consider exposing a different entry point on WebGraphicsContext3D. |
204 context3d()->prepareTexture(); | 312 context3d()->prepareTexture(); |
205 } | 313 } |
206 | 314 |
207 if (!has_swap_buffers_complete_callback_) | 315 if (!has_swap_buffers_complete_callback_) |
208 PostSwapBuffersComplete(); | 316 PostSwapBuffersComplete(); |
| 317 |
| 318 DidSwapBuffers(); |
209 } | 319 } |
210 | 320 |
211 void OutputSurface::PostSwapBuffersComplete() { | 321 void OutputSurface::PostSwapBuffersComplete() { |
212 base::MessageLoop::current()->PostTask( | 322 base::MessageLoop::current()->PostTask( |
213 FROM_HERE, | 323 FROM_HERE, |
214 base::Bind(&OutputSurface::SwapBuffersComplete, | 324 base::Bind(&OutputSurface::OnSwapBuffersComplete, |
215 weak_ptr_factory_.GetWeakPtr())); | 325 weak_ptr_factory_.GetWeakPtr(), |
216 } | 326 static_cast<CompositorFrameAck*>(NULL))); |
217 | |
218 void OutputSurface::SwapBuffersComplete() { | |
219 if (!client_) | |
220 return; | |
221 | |
222 client_->OnSwapBuffersComplete(NULL); | |
223 } | 327 } |
224 | 328 |
225 } // namespace cc | 329 } // namespace cc |
OLD | NEW |