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.
4
5#include "webkit/common/gpu/context_provider_in_process.h"
6
7#include <set>
8
9#include "base/bind.h"
10#include "base/callback_helpers.h"
11#include "base/strings/string_split.h"
12#include "base/strings/stringprintf.h"
13#include "cc/output/managed_memory_policy.h"
14#include "gpu/command_buffer/client/gles2_implementation.h"
15#include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
16
17namespace webkit {
18namespace gpu {
19
20class ContextProviderInProcess::LostContextCallbackProxy
21    : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
22 public:
23  explicit LostContextCallbackProxy(ContextProviderInProcess* provider)
24      : provider_(provider) {
25    provider_->context3d_->setContextLostCallback(this);
26  }
27
28  virtual ~LostContextCallbackProxy() {
29    provider_->context3d_->setContextLostCallback(NULL);
30  }
31
32  virtual void onContextLost() {
33    provider_->OnLostContext();
34  }
35
36 private:
37  ContextProviderInProcess* provider_;
38};
39
40// static
41scoped_refptr<ContextProviderInProcess> ContextProviderInProcess::Create(
42    scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
43    const std::string& debug_name) {
44  if (!context3d)
45    return NULL;
46  return new ContextProviderInProcess(context3d.Pass(), debug_name);
47}
48
49// static
50scoped_refptr<ContextProviderInProcess>
51ContextProviderInProcess::CreateOffscreen(
52    bool lose_context_when_out_of_memory) {
53  blink::WebGraphicsContext3D::Attributes attributes;
54  attributes.depth = false;
55  attributes.stencil = true;
56  attributes.antialias = false;
57  attributes.shareResources = true;
58  attributes.noAutomaticFlushes = true;
59
60  return Create(
61      WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
62          attributes, lose_context_when_out_of_memory),
63      "Offscreen");
64}
65
66ContextProviderInProcess::ContextProviderInProcess(
67    scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
68    const std::string& debug_name)
69    : context3d_(context3d.Pass()),
70      destroyed_(false),
71      debug_name_(debug_name) {
72  DCHECK(main_thread_checker_.CalledOnValidThread());
73  DCHECK(context3d_);
74  context_thread_checker_.DetachFromThread();
75}
76
77ContextProviderInProcess::~ContextProviderInProcess() {
78  DCHECK(main_thread_checker_.CalledOnValidThread() ||
79         context_thread_checker_.CalledOnValidThread());
80}
81
82blink::WebGraphicsContext3D* ContextProviderInProcess::WebContext3D() {
83  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
84  DCHECK(context_thread_checker_.CalledOnValidThread());
85
86  return context3d_.get();
87}
88
89bool ContextProviderInProcess::BindToCurrentThread() {
90  DCHECK(context3d_);
91
92  // This is called on the thread the context will be used.
93  DCHECK(context_thread_checker_.CalledOnValidThread());
94
95  if (lost_context_callback_proxy_)
96    return true;
97
98  if (!context3d_->InitializeOnCurrentThread())
99    return false;
100
101  InitializeCapabilities();
102
103  std::string unique_context_name =
104      base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get());
105  context3d_->pushGroupMarkerEXT(unique_context_name.c_str());
106
107  lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
108  return true;
109}
110
111void ContextProviderInProcess::InitializeCapabilities() {
112  capabilities_.gpu = context3d_->GetImplementation()->capabilities();
113
114  size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit();
115  capabilities_.max_transfer_buffer_usage_bytes =
116      mapped_memory_limit ==
117              WebGraphicsContext3DInProcessCommandBufferImpl::kNoLimit
118          ? std::numeric_limits<size_t>::max()
119          : mapped_memory_limit;
120}
121
122cc::ContextProvider::Capabilities
123ContextProviderInProcess::ContextCapabilities() {
124  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
125  DCHECK(context_thread_checker_.CalledOnValidThread());
126  return capabilities_;
127}
128
129::gpu::gles2::GLES2Interface* ContextProviderInProcess::ContextGL() {
130  DCHECK(context3d_);
131  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
132  DCHECK(context_thread_checker_.CalledOnValidThread());
133
134  return context3d_->GetGLInterface();
135}
136
137::gpu::ContextSupport* ContextProviderInProcess::ContextSupport() {
138  DCHECK(context3d_);
139  if (!lost_context_callback_proxy_)
140    return NULL;  // Not bound to anything.
141
142  DCHECK(context_thread_checker_.CalledOnValidThread());
143
144  return context3d_->GetContextSupport();
145}
146
147class GrContext* ContextProviderInProcess::GrContext() {
148  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
149  DCHECK(context_thread_checker_.CalledOnValidThread());
150
151  if (gr_context_)
152    return gr_context_->get();
153
154  gr_context_.reset(
155      new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
156  return gr_context_->get();
157}
158
159bool ContextProviderInProcess::IsContextLost() {
160  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
161  DCHECK(context_thread_checker_.CalledOnValidThread());
162
163  return context3d_->isContextLost();
164}
165
166void ContextProviderInProcess::VerifyContexts() {
167  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
168  DCHECK(context_thread_checker_.CalledOnValidThread());
169
170  if (context3d_->isContextLost())
171    OnLostContext();
172}
173
174void ContextProviderInProcess::DeleteCachedResources() {
175  DCHECK(context_thread_checker_.CalledOnValidThread());
176
177  if (gr_context_)
178    gr_context_->FreeGpuResources();
179}
180
181void ContextProviderInProcess::OnLostContext() {
182  DCHECK(context_thread_checker_.CalledOnValidThread());
183  {
184    base::AutoLock lock(destroyed_lock_);
185    if (destroyed_)
186      return;
187    destroyed_ = true;
188  }
189  if (!lost_context_callback_.is_null())
190    base::ResetAndReturn(&lost_context_callback_).Run();
191  if (gr_context_)
192    gr_context_->OnLostContext();
193}
194
195bool ContextProviderInProcess::DestroyedOnMainThread() {
196  DCHECK(main_thread_checker_.CalledOnValidThread());
197
198  base::AutoLock lock(destroyed_lock_);
199  return destroyed_;
200}
201
202void ContextProviderInProcess::SetLostContextCallback(
203    const LostContextCallback& lost_context_callback) {
204  DCHECK(context_thread_checker_.CalledOnValidThread());
205  DCHECK(lost_context_callback_.is_null() ||
206         lost_context_callback.is_null());
207  lost_context_callback_ = lost_context_callback;
208}
209
210void ContextProviderInProcess::SetMemoryPolicyChangedCallback(
211    const MemoryPolicyChangedCallback& memory_policy_changed_callback) {
212  // There's no memory manager for the in-process implementation.
213}
214
215}  // namespace gpu
216}  // namespace webkit
217