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"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "base/trace_event/trace_event.h"
12 #include "cc/output/managed_memory_policy.h"
13 #include "cc/output/output_surface_client.h"
14 #include "gpu/GLES2/gl2extchromium.h"
15 #include "gpu/command_buffer/client/context_support.h"
16 #include "gpu/command_buffer/client/gles2_interface.h"
17 #include "third_party/skia/include/core/SkTraceMemoryDump.h"
18 #include "third_party/skia/include/gpu/GrContext.h"
19 #include "ui/gfx/geometry/rect.h"
20 #include "ui/gfx/geometry/size.h"
21 #include "ui/gl/trace_util.h"
23 class SkDiscardableMemory
;
29 // Constants used by SkiaGpuTraceMemoryDump to identify different memory types.
30 const char* kGLTextureBackingType
= "gl_texture";
31 const char* kGLBufferBackingType
= "gl_buffer";
32 const char* kGLRenderbufferBackingType
= "gl_renderbuffer";
34 // Derives from SkTraceMemoryDump and implements graphics specific memory
35 // backing functionality.
36 class SkiaGpuTraceMemoryDump
: public SkTraceMemoryDump
{
38 // This should never outlive the provided ProcessMemoryDump, as it should
39 // always be scoped to a single OnMemoryDump funciton call.
40 explicit SkiaGpuTraceMemoryDump(base::trace_event::ProcessMemoryDump
* pmd
,
41 uint64_t share_group_tracing_guid
)
42 : pmd_(pmd
), share_group_tracing_guid_(share_group_tracing_guid
) {}
44 // Overridden from SkTraceMemoryDump:
45 void dumpNumericValue(const char* dump_name
,
46 const char* value_name
,
48 uint64_t value
) override
{
49 auto dump
= GetOrCreateAllocatorDump(dump_name
);
50 dump
->AddScalar(value_name
, units
, value
);
53 void setMemoryBacking(const char* dump_name
,
54 const char* backing_type
,
55 const char* backing_object_id
) override
{
56 const uint64 tracing_process_id
=
57 base::trace_event::MemoryDumpManager::GetInstance()
58 ->GetTracingProcessId();
60 // For uniformity, skia provides this value as a string. Convert back to a
63 std::strtoul(backing_object_id
, nullptr /* str_end */, 10 /* base */);
65 // Populated in if statements below.
66 base::trace_event::MemoryAllocatorDumpGuid guid
;
68 if (strcmp(backing_type
, kGLTextureBackingType
) == 0) {
69 guid
= gfx::GetGLTextureClientGUIDForTracing(share_group_tracing_guid_
,
71 } else if (strcmp(backing_type
, kGLBufferBackingType
) == 0) {
72 guid
= gfx::GetGLBufferGUIDForTracing(tracing_process_id
, gl_id
);
73 } else if (strcmp(backing_type
, kGLRenderbufferBackingType
) == 0) {
74 guid
= gfx::GetGLRenderbufferGUIDForTracing(tracing_process_id
, gl_id
);
78 pmd_
->CreateSharedGlobalAllocatorDump(guid
);
80 auto* dump
= GetOrCreateAllocatorDump(dump_name
);
82 const int kImportance
= 2;
83 pmd_
->AddOwnershipEdge(dump
->guid(), guid
, kImportance
);
87 void setDiscardableMemoryBacking(
88 const char* dump_name
,
89 const SkDiscardableMemory
& discardable_memory_object
) override
{
90 // We don't use this class for dumping discardable memory.
95 // Helper to create allocator dumps.
96 base::trace_event::MemoryAllocatorDump
* GetOrCreateAllocatorDump(
97 const char* dump_name
) {
98 auto dump
= pmd_
->GetAllocatorDump(dump_name
);
100 dump
= pmd_
->CreateAllocatorDump(dump_name
);
104 base::trace_event::ProcessMemoryDump
* pmd_
;
105 uint64_t share_group_tracing_guid_
;
107 DISALLOW_COPY_AND_ASSIGN(SkiaGpuTraceMemoryDump
);
112 OutputSurface::OutputSurface(
113 const scoped_refptr
<ContextProvider
>& context_provider
,
114 const scoped_refptr
<ContextProvider
>& worker_context_provider
,
115 scoped_ptr
<SoftwareOutputDevice
> software_device
)
117 context_provider_(context_provider
),
118 worker_context_provider_(worker_context_provider
),
119 software_device_(software_device
.Pass()),
120 device_scale_factor_(-1),
121 external_stencil_test_enabled_(false),
122 weak_ptr_factory_(this) {
125 OutputSurface::OutputSurface(
126 const scoped_refptr
<ContextProvider
>& context_provider
)
127 : OutputSurface(context_provider
, nullptr, nullptr) {
130 OutputSurface::OutputSurface(
131 const scoped_refptr
<ContextProvider
>& context_provider
,
132 const scoped_refptr
<ContextProvider
>& worker_context_provider
)
133 : OutputSurface(context_provider
, worker_context_provider
, nullptr) {
136 OutputSurface::OutputSurface(scoped_ptr
<SoftwareOutputDevice
> software_device
)
137 : OutputSurface(nullptr, nullptr, software_device
.Pass()) {
140 OutputSurface::OutputSurface(
141 const scoped_refptr
<ContextProvider
>& context_provider
,
142 scoped_ptr
<SoftwareOutputDevice
> software_device
)
143 : OutputSurface(context_provider
, nullptr, software_device
.Pass()) {
146 void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase
,
147 base::TimeDelta interval
) {
149 "OutputSurface::CommitVSyncParameters",
151 (timebase
- base::TimeTicks()).InSecondsF(),
153 interval
.InSecondsF());
154 client_
->CommitVSyncParameters(timebase
, interval
);
157 // Forwarded to OutputSurfaceClient
158 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect
& damage_rect
) {
159 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
160 client_
->SetNeedsRedrawRect(damage_rect
);
163 void OutputSurface::ReclaimResources(const CompositorFrameAck
* ack
) {
164 client_
->ReclaimResources(ack
);
167 void OutputSurface::DidLoseOutputSurface() {
168 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
169 client_
->DidLoseOutputSurface();
172 void OutputSurface::SetExternalStencilTest(bool enabled
) {
173 external_stencil_test_enabled_
= enabled
;
176 void OutputSurface::SetExternalDrawConstraints(
177 const gfx::Transform
& transform
,
178 const gfx::Rect
& viewport
,
179 const gfx::Rect
& clip
,
180 const gfx::Rect
& viewport_rect_for_tile_priority
,
181 const gfx::Transform
& transform_for_tile_priority
,
182 bool resourceless_software_draw
) {
183 client_
->SetExternalDrawConstraints(transform
,
186 viewport_rect_for_tile_priority
,
187 transform_for_tile_priority
,
188 resourceless_software_draw
);
191 OutputSurface::~OutputSurface() {
192 // Unregister any dump provider. Safe to call (no-op) if we have not yet
194 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
197 if (context_provider_
.get()) {
198 context_provider_
->SetLostContextCallback(
199 ContextProvider::LostContextCallback());
200 context_provider_
->SetMemoryPolicyChangedCallback(
201 ContextProvider::MemoryPolicyChangedCallback());
205 bool OutputSurface::HasExternalStencilTest() const {
206 return external_stencil_test_enabled_
;
209 bool OutputSurface::BindToClient(OutputSurfaceClient
* client
) {
214 if (context_provider_
.get()) {
215 success
= context_provider_
->BindToCurrentThread();
217 context_provider_
->SetLostContextCallback(base::Bind(
218 &OutputSurface::DidLoseOutputSurface
, base::Unretained(this)));
219 context_provider_
->SetMemoryPolicyChangedCallback(
220 base::Bind(&OutputSurface::SetMemoryPolicy
, base::Unretained(this)));
224 if (success
&& worker_context_provider_
.get()) {
225 success
= worker_context_provider_
->BindToCurrentThread();
227 worker_context_provider_
->SetupLock();
233 // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
234 // Don't register a dump provider in these cases.
235 // TODO(ericrk): Get this working in Android Webview. crbug.com/517156
236 if (base::ThreadTaskRunnerHandle::IsSet()) {
237 // Now that we are on the context thread, register a dump provider with this
238 // thread's task runner. This will overwrite any previous dump provider
240 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
241 this, base::ThreadTaskRunnerHandle::Get());
247 void OutputSurface::EnsureBackbuffer() {
248 if (software_device_
)
249 software_device_
->EnsureBackbuffer();
252 void OutputSurface::DiscardBackbuffer() {
253 if (context_provider_
.get())
254 context_provider_
->ContextGL()->DiscardBackbufferCHROMIUM();
255 if (software_device_
)
256 software_device_
->DiscardBackbuffer();
259 void OutputSurface::Reshape(const gfx::Size
& size
, float scale_factor
) {
260 if (size
== surface_size_
&& scale_factor
== device_scale_factor_
)
263 surface_size_
= size
;
264 device_scale_factor_
= scale_factor
;
265 if (context_provider_
.get()) {
266 context_provider_
->ContextGL()->ResizeCHROMIUM(
267 size
.width(), size
.height(), scale_factor
);
269 if (software_device_
)
270 software_device_
->Resize(size
, scale_factor
);
273 void OutputSurface::BindFramebuffer() {
274 DCHECK(context_provider_
.get());
275 context_provider_
->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER
, 0);
278 void OutputSurface::PostSwapBuffersComplete() {
279 base::ThreadTaskRunnerHandle::Get()->PostTask(
280 FROM_HERE
, base::Bind(&OutputSurface::OnSwapBuffersComplete
,
281 weak_ptr_factory_
.GetWeakPtr()));
284 // We don't post tasks bound to the client directly since they might run
285 // after the OutputSurface has been destroyed.
286 void OutputSurface::OnSwapBuffersComplete() {
287 client_
->DidSwapBuffersComplete();
290 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy
& policy
) {
291 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
292 "bytes_limit_when_visible", policy
.bytes_limit_when_visible
);
293 // Just ignore the memory manager when it says to set the limit to zero
294 // bytes. This will happen when the memory manager thinks that the renderer
295 // is not visible (which the renderer knows better).
296 if (policy
.bytes_limit_when_visible
)
297 client_
->SetMemoryPolicy(policy
);
300 OverlayCandidateValidator
* OutputSurface::GetOverlayCandidateValidator() const {
304 unsigned OutputSurface::GetOverlayTextureId() const {
308 void OutputSurface::SetWorkerContextShouldAggressivelyFreeResources(
309 bool aggressively_free_resources
) {
311 "OutputSurface::SetWorkerContextShouldAggressivelyFreeResources",
312 "aggressively_free_resources", aggressively_free_resources
);
313 if (auto* context_provider
= worker_context_provider()) {
314 ContextProvider::ScopedContextLock
scoped_context(context_provider
);
316 if (aggressively_free_resources
) {
317 context_provider
->DeleteCachedResources();
320 if (auto* context_support
= context_provider
->ContextSupport()) {
321 context_support
->SetAggressivelyFreeResources(
322 aggressively_free_resources
);
327 bool OutputSurface::SurfaceIsSuspendForRecycle() const {
331 bool OutputSurface::OnMemoryDump(const base::trace_event::MemoryDumpArgs
& args
,
332 base::trace_event::ProcessMemoryDump
* pmd
) {
333 if (auto* context_provider
= this->context_provider()) {
334 // No need to lock, main context provider is not shared.
335 if (auto* gr_context
= context_provider
->GrContext()) {
336 SkiaGpuTraceMemoryDump
trace_memory_dump(
337 pmd
, context_provider
->ContextSupport()->ShareGroupTracingGUID());
338 gr_context
->dumpMemoryStatistics(&trace_memory_dump
);
341 if (auto* context_provider
= worker_context_provider()) {
342 ContextProvider::ScopedContextLock
scoped_context(context_provider
);
344 if (auto* gr_context
= context_provider
->GrContext()) {
345 SkiaGpuTraceMemoryDump
trace_memory_dump(
346 pmd
, context_provider
->ContextSupport()->ShareGroupTracingGUID());
347 gr_context
->dumpMemoryStatistics(&trace_memory_dump
);