GPU workaround to simulate Out of Memory errors with large textures
[chromium-blink-merge.git] / cc / output / output_surface.cc
blobb1a2b9a4647121746fcd342a22d5f2be7d9cd24c
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
3 // found in the LICENSE file.
5 #include "cc/output/output_surface.h"
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/trace_event/trace_event.h"
10 #include "cc/output/managed_memory_policy.h"
11 #include "cc/output/output_surface_client.h"
12 #include "gpu/GLES2/gl2extchromium.h"
13 #include "gpu/command_buffer/client/gles2_interface.h"
14 #include "ui/gfx/geometry/rect.h"
15 #include "ui/gfx/geometry/size.h"
18 namespace cc {
20 OutputSurface::OutputSurface(
21 const scoped_refptr<ContextProvider>& context_provider,
22 const scoped_refptr<ContextProvider>& worker_context_provider,
23 scoped_ptr<SoftwareOutputDevice> software_device)
24 : client_(NULL),
25 context_provider_(context_provider),
26 worker_context_provider_(worker_context_provider),
27 software_device_(software_device.Pass()),
28 device_scale_factor_(-1),
29 external_stencil_test_enabled_(false),
30 weak_ptr_factory_(this) {
33 OutputSurface::OutputSurface(
34 const scoped_refptr<ContextProvider>& context_provider)
35 : OutputSurface(context_provider, nullptr, nullptr) {
38 OutputSurface::OutputSurface(
39 const scoped_refptr<ContextProvider>& context_provider,
40 const scoped_refptr<ContextProvider>& worker_context_provider)
41 : OutputSurface(context_provider, worker_context_provider, nullptr) {
44 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
45 : OutputSurface(nullptr, nullptr, software_device.Pass()) {
48 OutputSurface::OutputSurface(
49 const scoped_refptr<ContextProvider>& context_provider,
50 scoped_ptr<SoftwareOutputDevice> software_device)
51 : OutputSurface(context_provider, nullptr, software_device.Pass()) {
54 void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase,
55 base::TimeDelta interval) {
56 TRACE_EVENT2("cc",
57 "OutputSurface::CommitVSyncParameters",
58 "timebase",
59 (timebase - base::TimeTicks()).InSecondsF(),
60 "interval",
61 interval.InSecondsF());
62 client_->CommitVSyncParameters(timebase, interval);
65 // Forwarded to OutputSurfaceClient
66 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
67 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
68 client_->SetNeedsRedrawRect(damage_rect);
71 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
72 client_->ReclaimResources(ack);
75 void OutputSurface::DidLoseOutputSurface() {
76 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
77 client_->DidLoseOutputSurface();
80 void OutputSurface::SetExternalStencilTest(bool enabled) {
81 external_stencil_test_enabled_ = enabled;
84 void OutputSurface::SetExternalDrawConstraints(
85 const gfx::Transform& transform,
86 const gfx::Rect& viewport,
87 const gfx::Rect& clip,
88 const gfx::Rect& viewport_rect_for_tile_priority,
89 const gfx::Transform& transform_for_tile_priority,
90 bool resourceless_software_draw) {
91 client_->SetExternalDrawConstraints(transform,
92 viewport,
93 clip,
94 viewport_rect_for_tile_priority,
95 transform_for_tile_priority,
96 resourceless_software_draw);
99 OutputSurface::~OutputSurface() {
100 ResetContext3d();
103 bool OutputSurface::HasExternalStencilTest() const {
104 return external_stencil_test_enabled_;
107 bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
108 DCHECK(client);
109 client_ = client;
110 bool success = true;
112 if (context_provider_.get()) {
113 success = context_provider_->BindToCurrentThread();
114 if (success)
115 SetUpContext3d();
118 if (success && worker_context_provider_.get()) {
119 success = worker_context_provider_->BindToCurrentThread();
120 if (success) {
121 worker_context_provider_->SetupLock();
122 // The destructor resets the context lost callback, so base::Unretained
123 // is safe, as long as the worker threads stop using the context before
124 // the output surface is destroyed.
125 worker_context_provider_->SetLostContextCallback(base::Bind(
126 &OutputSurface::DidLoseOutputSurface, base::Unretained(this)));
130 if (!success)
131 client_ = NULL;
133 return success;
136 bool OutputSurface::InitializeAndSetContext3d(
137 scoped_refptr<ContextProvider> context_provider,
138 scoped_refptr<ContextProvider> worker_context_provider) {
139 DCHECK(!context_provider_.get());
140 DCHECK(context_provider.get());
141 DCHECK(client_);
143 bool success = context_provider->BindToCurrentThread();
144 if (success) {
145 context_provider_ = context_provider;
146 SetUpContext3d();
148 if (success && worker_context_provider.get()) {
149 success = worker_context_provider->BindToCurrentThread();
150 if (success) {
151 worker_context_provider_ = worker_context_provider;
152 // The destructor resets the context lost callback, so base::Unretained
153 // is safe, as long as the worker threads stop using the context before
154 // the output surface is destroyed.
155 worker_context_provider_->SetLostContextCallback(base::Bind(
156 &OutputSurface::DidLoseOutputSurface, base::Unretained(this)));
160 if (!success)
161 ResetContext3d();
162 else
163 client_->DeferredInitialize();
165 return success;
168 void OutputSurface::ReleaseGL() {
169 DCHECK(client_);
170 DCHECK(context_provider_.get());
171 client_->ReleaseGL();
172 DCHECK(!context_provider_.get());
175 void OutputSurface::SetUpContext3d() {
176 DCHECK(context_provider_.get());
177 DCHECK(client_);
179 context_provider_->SetLostContextCallback(
180 base::Bind(&OutputSurface::DidLoseOutputSurface,
181 base::Unretained(this)));
182 context_provider_->SetMemoryPolicyChangedCallback(
183 base::Bind(&OutputSurface::SetMemoryPolicy,
184 base::Unretained(this)));
187 void OutputSurface::ReleaseContextProvider() {
188 DCHECK(client_);
189 DCHECK(context_provider_.get());
190 ResetContext3d();
193 void OutputSurface::ResetContext3d() {
194 if (context_provider_.get()) {
195 context_provider_->SetLostContextCallback(
196 ContextProvider::LostContextCallback());
197 context_provider_->SetMemoryPolicyChangedCallback(
198 ContextProvider::MemoryPolicyChangedCallback());
200 if (worker_context_provider_.get()) {
201 worker_context_provider_->SetLostContextCallback(
202 ContextProvider::LostContextCallback());
204 context_provider_ = NULL;
205 worker_context_provider_ = NULL;
208 void OutputSurface::EnsureBackbuffer() {
209 if (software_device_)
210 software_device_->EnsureBackbuffer();
213 void OutputSurface::DiscardBackbuffer() {
214 if (context_provider_.get())
215 context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
216 if (software_device_)
217 software_device_->DiscardBackbuffer();
220 void OutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
221 if (size == surface_size_ && scale_factor == device_scale_factor_)
222 return;
224 surface_size_ = size;
225 device_scale_factor_ = scale_factor;
226 if (context_provider_.get()) {
227 context_provider_->ContextGL()->ResizeCHROMIUM(
228 size.width(), size.height(), scale_factor);
230 if (software_device_)
231 software_device_->Resize(size, scale_factor);
234 gfx::Size OutputSurface::SurfaceSize() const {
235 return surface_size_;
238 void OutputSurface::BindFramebuffer() {
239 DCHECK(context_provider_.get());
240 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
243 void OutputSurface::PostSwapBuffersComplete() {
244 base::MessageLoop::current()->PostTask(
245 FROM_HERE,
246 base::Bind(&OutputSurface::OnSwapBuffersComplete,
247 weak_ptr_factory_.GetWeakPtr()));
250 // We don't post tasks bound to the client directly since they might run
251 // after the OutputSurface has been destroyed.
252 void OutputSurface::OnSwapBuffersComplete() {
253 client_->DidSwapBuffersComplete();
256 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
257 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
258 "bytes_limit_when_visible", policy.bytes_limit_when_visible);
259 // Just ignore the memory manager when it says to set the limit to zero
260 // bytes. This will happen when the memory manager thinks that the renderer
261 // is not visible (which the renderer knows better).
262 if (policy.bytes_limit_when_visible)
263 client_->SetMemoryPolicy(policy);
266 } // namespace cc