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 "content/common/gpu/client/context_provider_command_buffer.h" | 5 #include "content/common/gpu/client/context_provider_command_buffer.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <set> | 10 #include <set> |
11 #include <utility> | 11 #include <utility> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
14 #include "base/callback_helpers.h" | 14 #include "base/callback_helpers.h" |
15 #include "base/command_line.h" | 15 #include "base/command_line.h" |
16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
17 #include "cc/output/managed_memory_policy.h" | 17 #include "cc/output/managed_memory_policy.h" |
18 #include "content/common/gpu/client/command_buffer_metrics.h" | 18 #include "content/common/gpu/client/command_buffer_metrics.h" |
19 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" | 19 #include "gpu/command_buffer/client/gles2_cmd_helper.h" |
20 #include "gpu/command_buffer/client/gles2_implementation.h" | 20 #include "gpu/command_buffer/client/gles2_implementation.h" |
21 #include "gpu/command_buffer/client/gles2_trace_implementation.h" | 21 #include "gpu/command_buffer/client/gles2_trace_implementation.h" |
22 #include "gpu/command_buffer/client/gpu_switches.h" | 22 #include "gpu/command_buffer/client/gpu_switches.h" |
| 23 #include "gpu/command_buffer/client/transfer_buffer.h" |
| 24 #include "gpu/command_buffer/common/constants.h" |
| 25 #include "gpu/ipc/client/command_buffer_proxy_impl.h" |
23 #include "gpu/ipc/client/gpu_channel_host.h" | 26 #include "gpu/ipc/client/gpu_channel_host.h" |
24 #include "gpu/skia_bindings/grcontext_for_gles2_interface.h" | 27 #include "gpu/skia_bindings/grcontext_for_gles2_interface.h" |
25 #include "third_party/skia/include/gpu/GrContext.h" | 28 #include "third_party/skia/include/gpu/GrContext.h" |
26 | 29 |
| 30 namespace { |
| 31 |
| 32 // Similar to base::AutoReset but it sets the variable to the new value |
| 33 // when it is destroyed. Use reset() to cancel setting the variable. |
| 34 class AutoSet { |
| 35 public: |
| 36 AutoSet(bool* b, bool set) : b_(b), set_(set) {} |
| 37 ~AutoSet() { |
| 38 if (b_) |
| 39 *b_ = set_; |
| 40 } |
| 41 // Stops us from setting _b on destruction. |
| 42 void Reset() { b_ = nullptr; } |
| 43 |
| 44 private: |
| 45 bool* b_; |
| 46 const bool set_; |
| 47 }; |
| 48 } |
| 49 |
27 namespace content { | 50 namespace content { |
28 | 51 |
29 ContextProviderCommandBuffer::SharedProviders::SharedProviders() = default; | 52 ContextProviderCommandBuffer::SharedProviders::SharedProviders() = default; |
30 ContextProviderCommandBuffer::SharedProviders::~SharedProviders() = default; | 53 ContextProviderCommandBuffer::SharedProviders::~SharedProviders() = default; |
31 | 54 |
32 ContextProviderCommandBuffer::ContextProviderCommandBuffer( | 55 ContextProviderCommandBuffer::ContextProviderCommandBuffer( |
33 scoped_refptr<gpu::GpuChannelHost> channel, | 56 scoped_refptr<gpu::GpuChannelHost> channel, |
34 gpu::SurfaceHandle surface_handle, | 57 gpu::SurfaceHandle surface_handle, |
35 const GURL& active_url, | 58 const GURL& active_url, |
36 gfx::GpuPreference gpu_preference, | 59 gfx::GpuPreference gpu_preference, |
37 bool automatic_flushes, | 60 bool automatic_flushes, |
38 const gpu::SharedMemoryLimits& memory_limits, | 61 const gpu::SharedMemoryLimits& memory_limits, |
39 const gpu::gles2::ContextCreationAttribHelper& attributes, | 62 const gpu::gles2::ContextCreationAttribHelper& attributes, |
40 ContextProviderCommandBuffer* shared_context_provider, | 63 ContextProviderCommandBuffer* shared_context_provider, |
41 command_buffer_metrics::ContextType type) | 64 command_buffer_metrics::ContextType type) |
42 : surface_handle_(surface_handle), | 65 : surface_handle_(surface_handle), |
43 active_url_(active_url), | 66 active_url_(active_url), |
44 gpu_preference_(gpu_preference), | 67 gpu_preference_(gpu_preference), |
45 automatic_flushes_(automatic_flushes), | 68 automatic_flushes_(automatic_flushes), |
46 memory_limits_(memory_limits), | 69 memory_limits_(memory_limits), |
47 attributes_(attributes), | 70 attributes_(attributes), |
48 context_type_(type), | 71 context_type_(type), |
49 shared_providers_(shared_context_provider | 72 shared_providers_(shared_context_provider |
50 ? shared_context_provider->shared_providers_ | 73 ? shared_context_provider->shared_providers_ |
51 : new SharedProviders), | 74 : new SharedProviders), |
52 channel_(std::move(channel)), | 75 channel_(std::move(channel)) { |
53 context3d_(new WebGraphicsContext3DCommandBufferImpl) { | |
54 DCHECK(main_thread_checker_.CalledOnValidThread()); | 76 DCHECK(main_thread_checker_.CalledOnValidThread()); |
55 DCHECK(channel_); | 77 DCHECK(channel_); |
56 context_thread_checker_.DetachFromThread(); | 78 context_thread_checker_.DetachFromThread(); |
57 } | 79 } |
58 | 80 |
59 ContextProviderCommandBuffer::~ContextProviderCommandBuffer() { | 81 ContextProviderCommandBuffer::~ContextProviderCommandBuffer() { |
60 DCHECK(main_thread_checker_.CalledOnValidThread() || | 82 DCHECK(main_thread_checker_.CalledOnValidThread() || |
61 context_thread_checker_.CalledOnValidThread()); | 83 context_thread_checker_.CalledOnValidThread()); |
62 | 84 |
63 { | 85 { |
64 base::AutoLock hold(shared_providers_->lock); | 86 base::AutoLock hold(shared_providers_->lock); |
65 auto it = std::find(shared_providers_->list.begin(), | 87 auto it = std::find(shared_providers_->list.begin(), |
66 shared_providers_->list.end(), this); | 88 shared_providers_->list.end(), this); |
67 if (it != shared_providers_->list.end()) | 89 if (it != shared_providers_->list.end()) |
68 shared_providers_->list.erase(it); | 90 shared_providers_->list.erase(it); |
69 } | 91 } |
70 | 92 |
71 if (bind_succeeded_) { | 93 if (bind_succeeded_) { |
72 // Clear the lock to avoid DCHECKs that the lock is being held during | 94 // Clear the lock to avoid DCHECKs that the lock is being held during |
73 // shutdown. | 95 // shutdown. |
74 context3d_->GetCommandBufferProxy()->SetLock(nullptr); | 96 command_buffer_->SetLock(nullptr); |
75 // Disconnect lost callbacks during destruction. | 97 // Disconnect lost callbacks during destruction. |
76 context3d_->GetImplementation()->SetLostContextCallback(base::Closure()); | 98 gles2_impl_->SetLostContextCallback(base::Closure()); |
77 } | 99 } |
78 } | 100 } |
79 | 101 |
80 gpu::CommandBufferProxyImpl* | 102 gpu::CommandBufferProxyImpl* |
81 ContextProviderCommandBuffer::GetCommandBufferProxy() { | 103 ContextProviderCommandBuffer::GetCommandBufferProxy() { |
82 return context3d_->GetCommandBufferProxy(); | 104 return command_buffer_.get(); |
83 } | 105 } |
84 | 106 |
85 bool ContextProviderCommandBuffer::BindToCurrentThread() { | 107 bool ContextProviderCommandBuffer::BindToCurrentThread() { |
86 // This is called on the thread the context will be used. | 108 // This is called on the thread the context will be used. |
87 DCHECK(context_thread_checker_.CalledOnValidThread()); | 109 DCHECK(context_thread_checker_.CalledOnValidThread()); |
88 | 110 |
89 if (!context3d_) | 111 if (bind_failed_) |
90 return false; // Already failed. | 112 return false; |
91 if (bind_succeeded_) | 113 if (bind_succeeded_) |
92 return true; // Already succeeded. | 114 return true; |
| 115 |
| 116 // Early outs should report failure. |
| 117 AutoSet set_bind_failed(&bind_failed_, true); |
93 | 118 |
94 // It's possible to be running BindToCurrentThread on two contexts | 119 // It's possible to be running BindToCurrentThread on two contexts |
95 // on different threads at the same time, but which will be in the same share | 120 // on different threads at the same time, but which will be in the same share |
96 // group. To ensure they end up in the same group, hold the lock on the | 121 // group. To ensure they end up in the same group, hold the lock on the |
97 // shared_providers_ (which they will share) after querying the group, until | 122 // shared_providers_ (which they will share) after querying the group, until |
98 // this context has been added to the list. | 123 // this context has been added to the list. |
99 { | 124 { |
100 ContextProviderCommandBuffer* shared_context_provider = nullptr; | 125 ContextProviderCommandBuffer* shared_context_provider = nullptr; |
101 gpu::CommandBufferProxyImpl* shared_command_buffer = nullptr; | 126 gpu::CommandBufferProxyImpl* shared_command_buffer = nullptr; |
102 scoped_refptr<gpu::gles2::ShareGroup> share_group; | 127 scoped_refptr<gpu::gles2::ShareGroup> share_group; |
103 | 128 |
104 base::AutoLock hold(shared_providers_->lock); | 129 base::AutoLock hold(shared_providers_->lock); |
105 | 130 |
106 if (!shared_providers_->list.empty()) { | 131 if (!shared_providers_->list.empty()) { |
107 shared_context_provider = shared_providers_->list.front(); | 132 shared_context_provider = shared_providers_->list.front(); |
108 shared_command_buffer = | 133 shared_command_buffer = shared_context_provider->command_buffer_.get(); |
109 shared_context_provider->context3d_->GetCommandBufferProxy(); | 134 share_group = shared_context_provider->gles2_impl_->share_group(); |
110 share_group = shared_context_provider->context3d_->GetImplementation() | 135 DCHECK_EQ(!!shared_command_buffer, !!share_group); |
111 ->share_group(); | |
112 } | 136 } |
113 | 137 |
114 if (!context3d_->InitializeOnCurrentThread( | 138 DCHECK(attributes_.buffer_preserved); |
115 surface_handle_, active_url_, channel_.get(), gpu_preference_, | 139 std::vector<int32_t> serialized_attributes; |
116 automatic_flushes_, memory_limits_, shared_command_buffer, | 140 attributes_.Serialize(&serialized_attributes); |
117 share_group, attributes_, context_type_)) { | 141 |
118 context3d_ = nullptr; | 142 // This command buffer is a client-side proxy to the command buffer in the |
| 143 // GPU process. |
| 144 command_buffer_ = channel_->CreateCommandBuffer( |
| 145 surface_handle_, gfx::Size(), shared_command_buffer, |
| 146 gpu::GpuChannelHost::kDefaultStreamId, |
| 147 gpu::GpuChannelHost::kDefaultStreamPriority, serialized_attributes, |
| 148 active_url_, gpu_preference_); |
| 149 // The command buffer takes ownership of the |channel_|, so no need to keep |
| 150 // a reference around here. |
| 151 channel_ = nullptr; |
| 152 if (!command_buffer_) { |
| 153 DLOG(ERROR) << "GpuChannelHost failed to create command buffer."; |
| 154 command_buffer_metrics::UmaRecordContextInitFailed(context_type_); |
119 return false; | 155 return false; |
120 } | 156 } |
121 | 157 |
| 158 // The GLES2 helper writes the command buffer protocol. |
| 159 gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_.get())); |
| 160 gles2_helper_->SetAutomaticFlushes(automatic_flushes_); |
| 161 if (!gles2_helper_->Initialize(memory_limits_.command_buffer_size)) { |
| 162 DLOG(ERROR) << "Failed to initialize GLES2CmdHelper."; |
| 163 return false; |
| 164 } |
| 165 |
| 166 // The transfer buffer is used to copy resources between the client |
| 167 // process and the GPU process. |
| 168 transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get())); |
| 169 |
| 170 // The GLES2Implementation exposes the OpenGLES2 API, as well as the |
| 171 // gpu::ContextSupport interface. |
| 172 constexpr bool support_client_side_arrays = false; |
| 173 gles2_impl_.reset(new gpu::gles2::GLES2Implementation( |
| 174 gles2_helper_.get(), share_group, transfer_buffer_.get(), |
| 175 attributes_.bind_generates_resource, |
| 176 attributes_.lose_context_when_out_of_memory, support_client_side_arrays, |
| 177 command_buffer_.get())); |
| 178 if (!gles2_impl_->Initialize(memory_limits_.start_transfer_buffer_size, |
| 179 memory_limits_.min_transfer_buffer_size, |
| 180 memory_limits_.max_transfer_buffer_size, |
| 181 memory_limits_.mapped_memory_reclaim_limit)) { |
| 182 DLOG(ERROR) << "Failed to initialize GLES2Implementation."; |
| 183 return false; |
| 184 } |
| 185 |
| 186 if (command_buffer_->GetLastError() != gpu::error::kNoError) { |
| 187 DLOG(ERROR) << "Context dead on arrival. Last error: " |
| 188 << command_buffer_->GetLastError(); |
| 189 return false; |
| 190 } |
| 191 |
122 // If any context in the share group has been lost, then abort and don't | 192 // If any context in the share group has been lost, then abort and don't |
123 // continue since we need to go back to the caller of the constructor to | 193 // continue since we need to go back to the caller of the constructor to |
124 // find the correct share group. | 194 // find the correct share group. |
125 // This may happen in between the share group being chosen at the | 195 // This may happen in between the share group being chosen at the |
126 // constructor, and getting to run this BindToCurrentThread method which | 196 // constructor, and getting to run this BindToCurrentThread method which |
127 // can be on some other thread. | 197 // can be on some other thread. |
128 // We intentionally call this *after* creating the command buffer via the | 198 // We intentionally call this *after* creating the command buffer via the |
129 // GpuChannelHost. Once that has happened, the service knows we are in the | 199 // GpuChannelHost. Once that has happened, the service knows we are in the |
130 // share group and if a shared context is lost, our context will be informed | 200 // share group and if a shared context is lost, our context will be informed |
131 // also, and the lost context callback will occur for the owner of the | 201 // also, and the lost context callback will occur for the owner of the |
132 // context provider. If we check sooner, the shared context may be lost in | 202 // context provider. If we check sooner, the shared context may be lost in |
133 // between these two states and our context here would be left in an orphan | 203 // between these two states and our context here would be left in an orphan |
134 // share group. | 204 // share group. |
135 if (share_group && share_group->IsLost()) { | 205 if (share_group && share_group->IsLost()) |
136 context3d_ = nullptr; | |
137 return false; | 206 return false; |
138 } | |
139 | 207 |
140 shared_providers_->list.push_back(this); | 208 shared_providers_->list.push_back(this); |
141 } | 209 } |
| 210 set_bind_failed.Reset(); |
| 211 bind_succeeded_ = true; |
142 | 212 |
143 context3d_->GetImplementation()->SetLostContextCallback( | 213 gles2_impl_->SetLostContextCallback( |
144 base::Bind(&ContextProviderCommandBuffer::OnLostContext, | 214 base::Bind(&ContextProviderCommandBuffer::OnLostContext, |
145 // |this| owns the GLES2Implementation which holds the | 215 // |this| owns the GLES2Implementation which holds the |
146 // callback. | 216 // callback. |
147 base::Unretained(this))); | 217 base::Unretained(this))); |
148 | 218 |
149 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 219 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
150 switches::kEnableGpuClientTracing)) { | 220 switches::kEnableGpuClientTracing)) { |
151 // This wraps the real GLES2Implementation and we should always use this | 221 // This wraps the real GLES2Implementation and we should always use this |
152 // instead when it's present. | 222 // instead when it's present. |
153 trace_impl_.reset(new gpu::gles2::GLES2TraceImplementation( | 223 trace_impl_.reset( |
154 context3d_->GetImplementation())); | 224 new gpu::gles2::GLES2TraceImplementation(gles2_impl_.get())); |
155 } | 225 } |
156 | 226 |
157 bind_succeeded_ = true; | |
158 | |
159 // Do this last once the context is set up. | 227 // Do this last once the context is set up. |
160 std::string type_name = | 228 std::string type_name = |
161 command_buffer_metrics::ContextTypeToString(context_type_); | 229 command_buffer_metrics::ContextTypeToString(context_type_); |
162 std::string unique_context_name = | 230 std::string unique_context_name = |
163 base::StringPrintf("%s-%p", type_name.c_str(), context3d_.get()); | 231 base::StringPrintf("%s-%p", type_name.c_str(), gles2_impl_.get()); |
164 ContextGL()->TraceBeginCHROMIUM("gpu_toplevel", unique_context_name.c_str()); | 232 ContextGL()->TraceBeginCHROMIUM("gpu_toplevel", unique_context_name.c_str()); |
165 return true; | 233 return true; |
166 } | 234 } |
167 | 235 |
168 void ContextProviderCommandBuffer::DetachFromThread() { | 236 void ContextProviderCommandBuffer::DetachFromThread() { |
169 context_thread_checker_.DetachFromThread(); | 237 context_thread_checker_.DetachFromThread(); |
170 } | 238 } |
171 | 239 |
172 gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() { | 240 gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() { |
173 DCHECK(context3d_); | |
174 DCHECK(bind_succeeded_); | 241 DCHECK(bind_succeeded_); |
175 DCHECK(context_thread_checker_.CalledOnValidThread()); | 242 DCHECK(context_thread_checker_.CalledOnValidThread()); |
176 | 243 |
177 if (trace_impl_) | 244 if (trace_impl_) |
178 return trace_impl_.get(); | 245 return trace_impl_.get(); |
179 return context3d_->GetImplementation(); | 246 return gles2_impl_.get(); |
180 } | 247 } |
181 | 248 |
182 gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() { | 249 gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() { |
183 return context3d_->GetImplementation(); | 250 return gles2_impl_.get(); |
184 } | 251 } |
185 | 252 |
186 class GrContext* ContextProviderCommandBuffer::GrContext() { | 253 class GrContext* ContextProviderCommandBuffer::GrContext() { |
187 DCHECK(bind_succeeded_); | 254 DCHECK(bind_succeeded_); |
188 DCHECK(context_thread_checker_.CalledOnValidThread()); | 255 DCHECK(context_thread_checker_.CalledOnValidThread()); |
189 | 256 |
190 if (gr_context_) | 257 if (gr_context_) |
191 return gr_context_->get(); | 258 return gr_context_->get(); |
192 | 259 |
193 gr_context_.reset(new skia_bindings::GrContextForGLES2Interface(ContextGL())); | 260 gr_context_.reset(new skia_bindings::GrContextForGLES2Interface(ContextGL())); |
(...skipping 10 matching lines...) Expand all Loading... |
204 if (gr_context_) { | 271 if (gr_context_) { |
205 DCHECK(bind_succeeded_); | 272 DCHECK(bind_succeeded_); |
206 DCHECK(context_thread_checker_.CalledOnValidThread()); | 273 DCHECK(context_thread_checker_.CalledOnValidThread()); |
207 gr_context_->ResetContext(state); | 274 gr_context_->ResetContext(state); |
208 } | 275 } |
209 } | 276 } |
210 | 277 |
211 void ContextProviderCommandBuffer::SetupLock() { | 278 void ContextProviderCommandBuffer::SetupLock() { |
212 DCHECK(bind_succeeded_); | 279 DCHECK(bind_succeeded_); |
213 DCHECK(context_thread_checker_.CalledOnValidThread()); | 280 DCHECK(context_thread_checker_.CalledOnValidThread()); |
214 context3d_->GetCommandBufferProxy()->SetLock(&context_lock_); | 281 command_buffer_->SetLock(&context_lock_); |
215 } | 282 } |
216 | 283 |
217 base::Lock* ContextProviderCommandBuffer::GetLock() { | 284 base::Lock* ContextProviderCommandBuffer::GetLock() { |
218 return &context_lock_; | 285 return &context_lock_; |
219 } | 286 } |
220 | 287 |
221 gpu::Capabilities ContextProviderCommandBuffer::ContextCapabilities() { | 288 gpu::Capabilities ContextProviderCommandBuffer::ContextCapabilities() { |
222 DCHECK(bind_succeeded_); | 289 DCHECK(bind_succeeded_); |
223 DCHECK(context_thread_checker_.CalledOnValidThread()); | 290 DCHECK(context_thread_checker_.CalledOnValidThread()); |
224 // Skips past the trace_impl_ as it doesn't have capabilities. | 291 // Skips past the trace_impl_ as it doesn't have capabilities. |
225 return context3d_->GetImplementation()->capabilities(); | 292 return gles2_impl_->capabilities(); |
226 } | 293 } |
227 | 294 |
228 void ContextProviderCommandBuffer::DeleteCachedResources() { | 295 void ContextProviderCommandBuffer::DeleteCachedResources() { |
229 DCHECK(context_thread_checker_.CalledOnValidThread()); | 296 DCHECK(context_thread_checker_.CalledOnValidThread()); |
230 | 297 |
231 if (gr_context_) | 298 if (gr_context_) |
232 gr_context_->FreeGpuResources(); | 299 gr_context_->FreeGpuResources(); |
233 } | 300 } |
234 | 301 |
235 void ContextProviderCommandBuffer::OnLostContext() { | 302 void ContextProviderCommandBuffer::OnLostContext() { |
(...skipping 11 matching lines...) Expand all Loading... |
247 | 314 |
248 void ContextProviderCommandBuffer::SetLostContextCallback( | 315 void ContextProviderCommandBuffer::SetLostContextCallback( |
249 const LostContextCallback& lost_context_callback) { | 316 const LostContextCallback& lost_context_callback) { |
250 DCHECK(context_thread_checker_.CalledOnValidThread()); | 317 DCHECK(context_thread_checker_.CalledOnValidThread()); |
251 DCHECK(lost_context_callback_.is_null() || | 318 DCHECK(lost_context_callback_.is_null() || |
252 lost_context_callback.is_null()); | 319 lost_context_callback.is_null()); |
253 lost_context_callback_ = lost_context_callback; | 320 lost_context_callback_ = lost_context_callback; |
254 } | 321 } |
255 | 322 |
256 } // namespace content | 323 } // namespace content |
OLD | NEW |