OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "platform/graphics/OffscreenCanvasFrameDispatcherImpl.h" | 5 #include "platform/graphics/OffscreenCanvasFrameDispatcherImpl.h" |
6 | 6 |
7 #include "cc/output/compositor_frame.h" | 7 #include "cc/output/compositor_frame.h" |
8 #include "cc/quads/texture_draw_quad.h" | 8 #include "cc/quads/texture_draw_quad.h" |
9 #include "gpu/command_buffer/client/gles2_interface.h" | 9 #include "gpu/command_buffer/client/gles2_interface.h" |
| 10 #include "platform/CrossThreadFunctional.h" |
10 #include "platform/Histogram.h" | 11 #include "platform/Histogram.h" |
| 12 #include "platform/WebTaskRunner.h" |
| 13 #include "platform/graphics/OffscreenCanvasPlaceholder.h" |
11 #include "platform/graphics/gpu/SharedGpuContext.h" | 14 #include "platform/graphics/gpu/SharedGpuContext.h" |
12 #include "public/platform/InterfaceProvider.h" | 15 #include "public/platform/InterfaceProvider.h" |
13 #include "public/platform/Platform.h" | 16 #include "public/platform/Platform.h" |
14 #include "public/platform/WebGraphicsContext3DProvider.h" | 17 #include "public/platform/WebGraphicsContext3DProvider.h" |
15 #include "public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
-blink.h" | 18 #include "public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
-blink.h" |
16 #include "third_party/khronos/GLES2/gl2.h" | 19 #include "third_party/khronos/GLES2/gl2.h" |
17 #include "third_party/khronos/GLES2/gl2ext.h" | 20 #include "third_party/khronos/GLES2/gl2ext.h" |
18 #include "third_party/skia/include/core/SkColor.h" | 21 #include "third_party/skia/include/core/SkColor.h" |
19 #include "third_party/skia/include/core/SkImage.h" | 22 #include "third_party/skia/include/core/SkImage.h" |
20 #include "ui/gfx/geometry/rect.h" | 23 #include "ui/gfx/geometry/rect.h" |
21 #include "ui/gfx/transform.h" | 24 #include "ui/gfx/transform.h" |
22 #include "wtf/typed_arrays/ArrayBuffer.h" | 25 #include "wtf/typed_arrays/ArrayBuffer.h" |
23 #include "wtf/typed_arrays/Uint8Array.h" | 26 #include "wtf/typed_arrays/Uint8Array.h" |
24 | 27 |
25 namespace blink { | 28 namespace blink { |
26 | 29 |
27 OffscreenCanvasFrameDispatcherImpl::OffscreenCanvasFrameDispatcherImpl( | 30 OffscreenCanvasFrameDispatcherImpl::OffscreenCanvasFrameDispatcherImpl( |
28 uint32_t clientId, | 31 uint32_t clientId, |
29 uint32_t sinkId, | 32 uint32_t sinkId, |
30 uint32_t localId, | 33 uint32_t localId, |
31 uint64_t nonceHigh, | 34 uint64_t nonceHigh, |
32 uint64_t nonceLow, | 35 uint64_t nonceLow, |
| 36 int canvasId, |
33 int width, | 37 int width, |
34 int height) | 38 int height) |
35 : m_surfaceId( | 39 : m_surfaceId( |
36 cc::FrameSinkId(clientId, sinkId), | 40 cc::FrameSinkId(clientId, sinkId), |
37 cc::LocalFrameId( | 41 cc::LocalFrameId( |
38 localId, | 42 localId, |
39 base::UnguessableToken::Deserialize(nonceHigh, nonceLow))), | 43 base::UnguessableToken::Deserialize(nonceHigh, nonceLow))), |
40 m_width(width), | 44 m_width(width), |
41 m_height(height), | 45 m_height(height), |
42 m_nextResourceId(1u), | 46 m_nextResourceId(1u), |
43 m_binding(this) { | 47 m_binding(this), |
| 48 m_placeholderCanvasId(canvasId) { |
44 DCHECK(!m_sink.is_bound()); | 49 DCHECK(!m_sink.is_bound()); |
45 mojom::blink::OffscreenCanvasCompositorFrameSinkProviderPtr provider; | 50 mojom::blink::OffscreenCanvasCompositorFrameSinkProviderPtr provider; |
46 Platform::current()->interfaceProvider()->getInterface( | 51 Platform::current()->interfaceProvider()->getInterface( |
47 mojo::GetProxy(&provider)); | 52 mojo::GetProxy(&provider)); |
48 provider->CreateCompositorFrameSink(m_surfaceId, | 53 provider->CreateCompositorFrameSink(m_surfaceId, |
49 m_binding.CreateInterfacePtrAndBind(), | 54 m_binding.CreateInterfacePtrAndBind(), |
50 mojo::GetProxy(&m_sink)); | 55 mojo::GetProxy(&m_sink)); |
51 } | 56 } |
52 | 57 |
53 void OffscreenCanvasFrameDispatcherImpl::setTransferableResourceToSharedBitmap( | 58 void OffscreenCanvasFrameDispatcherImpl::setTransferableResourceToSharedBitmap( |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 resource.mailbox_holder = | 148 resource.mailbox_holder = |
144 gpu::MailboxHolder(image->mailbox(), image->syncToken(), GL_TEXTURE_2D); | 149 gpu::MailboxHolder(image->mailbox(), image->syncToken(), GL_TEXTURE_2D); |
145 resource.read_lock_fences_enabled = false; | 150 resource.read_lock_fences_enabled = false; |
146 resource.is_software = false; | 151 resource.is_software = false; |
147 | 152 |
148 // Hold ref to |image|, to keep it alive until the browser ReclaimResources. | 153 // Hold ref to |image|, to keep it alive until the browser ReclaimResources. |
149 // It guarantees that the resource is not re-used or deleted. | 154 // It guarantees that the resource is not re-used or deleted. |
150 m_cachedImages.add(m_nextResourceId, std::move(image)); | 155 m_cachedImages.add(m_nextResourceId, std::move(image)); |
151 } | 156 } |
152 | 157 |
| 158 namespace { |
| 159 |
| 160 void updatePlaceholderImage(WeakPtr<OffscreenCanvasFrameDispatcher> dispatcher, |
| 161 std::unique_ptr<WebTaskRunner> taskRunner, |
| 162 int placeholderCanvasId, |
| 163 RefPtr<blink::Image> image, |
| 164 unsigned resourceId) { |
| 165 DCHECK(isMainThread()); |
| 166 OffscreenCanvasPlaceholder* placeholderCanvas = |
| 167 OffscreenCanvasPlaceholder::getPlaceholderById(placeholderCanvasId); |
| 168 if (placeholderCanvas) { |
| 169 placeholderCanvas->setPlaceholderFrame(std::move(image), |
| 170 std::move(dispatcher), |
| 171 std::move(taskRunner), resourceId); |
| 172 } |
| 173 } |
| 174 |
| 175 } // namespace |
| 176 |
153 void OffscreenCanvasFrameDispatcherImpl::dispatchFrame( | 177 void OffscreenCanvasFrameDispatcherImpl::dispatchFrame( |
154 RefPtr<StaticBitmapImage> image, | 178 RefPtr<StaticBitmapImage> image, |
155 double commitStartTime, | 179 double commitStartTime, |
156 bool isWebGLSoftwareRendering /* This flag is true when WebGL's commit is | 180 bool isWebGLSoftwareRendering /* This flag is true when WebGL's commit is |
157 called on SwiftShader. */) { | 181 called on SwiftShader. */) { |
158 if (!image) | 182 if (!image) |
159 return; | 183 return; |
160 if (!verifyImageSize(image->size())) | 184 if (!verifyImageSize(image->size())) |
161 return; | 185 return; |
162 cc::CompositorFrame frame; | 186 cc::CompositorFrame frame; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 !isWebGLSoftwareRendering) { | 232 !isWebGLSoftwareRendering) { |
209 // Case 3: canvas is not gpu-accelerated, but compositor is | 233 // Case 3: canvas is not gpu-accelerated, but compositor is |
210 commitType = CommitSoftwareCanvasGPUCompositing; | 234 commitType = CommitSoftwareCanvasGPUCompositing; |
211 setTransferableResourceToSharedGPUContext(resource, image); | 235 setTransferableResourceToSharedGPUContext(resource, image); |
212 } else { | 236 } else { |
213 // Case 4: both canvas and compositor are not gpu accelerated. | 237 // Case 4: both canvas and compositor are not gpu accelerated. |
214 commitType = CommitSoftwareCanvasSoftwareCompositing; | 238 commitType = CommitSoftwareCanvasSoftwareCompositing; |
215 setTransferableResourceToSharedBitmap(resource, image); | 239 setTransferableResourceToSharedBitmap(resource, image); |
216 } | 240 } |
217 } | 241 } |
| 242 |
| 243 // After this point, |image| can only be used on the main thread, until |
| 244 // it is returned. |
| 245 image->transfer(); |
| 246 std::unique_ptr<WebTaskRunner> dispatcherTaskRunner = |
| 247 Platform::current()->currentThread()->getWebTaskRunner()->clone(); |
| 248 |
| 249 Platform::current()->mainThread()->getWebTaskRunner()->postTask( |
| 250 BLINK_FROM_HERE, |
| 251 crossThreadBind(updatePlaceholderImage, this->createWeakPtr(), |
| 252 passed(std::move(dispatcherTaskRunner)), |
| 253 m_placeholderCanvasId, std::move(image), resource.id)); |
| 254 m_spareResourceLocks.add(m_nextResourceId); |
| 255 |
218 commitTypeHistogram.count(commitType); | 256 commitTypeHistogram.count(commitType); |
219 | 257 |
220 m_nextResourceId++; | 258 m_nextResourceId++; |
221 frame.resource_list.push_back(std::move(resource)); | 259 frame.resource_list.push_back(std::move(resource)); |
222 | 260 |
223 cc::TextureDrawQuad* quad = | 261 cc::TextureDrawQuad* quad = |
224 pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>(); | 262 pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>(); |
225 gfx::Size rectSize(m_width, m_height); | 263 gfx::Size rectSize(m_width, m_height); |
226 | 264 |
227 const bool needsBlending = true; | 265 const bool needsBlending = true; |
228 // TOOD(crbug.com/645993): this should be inherited from WebGL context's | 266 // TOOD(crbug.com/645993): this should be inherited from WebGL context's |
229 // creation settings. | 267 // creation settings. |
230 const bool premultipliedAlpha = true; | 268 const bool premultipliedAlpha = true; |
231 const gfx::PointF uvTopLeft(0.f, 0.f); | 269 const gfx::PointF uvTopLeft(0.f, 0.f); |
232 const gfx::PointF uvBottomRight(1.f, 1.f); | 270 const gfx::PointF uvBottomRight(1.f, 1.f); |
233 float vertexOpacity[4] = {1.f, 1.f, 1.f, 1.f}; | 271 float vertexOpacity[4] = {1.f, 1.f, 1.f, 1.f}; |
234 // TODO(crbug.com/645994): this should be true when using style | 272 // TODO(crbug.com/645994): this should be true when using style |
235 // "image-rendering: pixelated". | 273 // "image-rendering: pixelated". |
236 const bool nearestNeighbor = false; | 274 const bool nearestNeighbor = false; |
237 quad->SetAll(sqs, bounds, bounds, bounds, needsBlending, resource.id, | 275 quad->SetAll(sqs, bounds, bounds, bounds, needsBlending, resource.id, |
238 gfx::Size(), premultipliedAlpha, uvTopLeft, uvBottomRight, | 276 gfx::Size(), premultipliedAlpha, uvTopLeft, uvBottomRight, |
239 SK_ColorTRANSPARENT, vertexOpacity, yflipped, nearestNeighbor, | 277 SK_ColorTRANSPARENT, vertexOpacity, yflipped, nearestNeighbor, |
240 false); | 278 false); |
241 | 279 |
242 frame.render_pass_list.push_back(std::move(pass)); | 280 frame.render_pass_list.push_back(std::move(pass)); |
243 | 281 |
244 double elapsedTime = WTF::monotonicallyIncreasingTime() - commitStartTime; | 282 double elapsedTime = WTF::monotonicallyIncreasingTime() - commitStartTime; |
| 283 |
| 284 // TODO(crbug.com/663916): The off-main-thread metrics are commented-out |
| 285 // because they cause thread check errors (static variable accessed in many |
| 286 // threads) |
245 switch (commitType) { | 287 switch (commitType) { |
246 case CommitGPUCanvasGPUCompositing: | 288 case CommitGPUCanvasGPUCompositing: |
247 if (isMainThread()) { | 289 if (isMainThread()) { |
248 DEFINE_STATIC_LOCAL( | 290 DEFINE_STATIC_LOCAL( |
249 CustomCountHistogram, commitGPUCanvasGPUCompositingMainTimer, | 291 CustomCountHistogram, commitGPUCanvasGPUCompositingMainTimer, |
250 ("Blink.Canvas.OffscreenCommit.GPUCanvasGPUCompositingMain", 0, | 292 ("Blink.Canvas.OffscreenCommit.GPUCanvasGPUCompositingMain", 0, |
251 10000000, 50)); | 293 10000000, 50)); |
252 commitGPUCanvasGPUCompositingMainTimer.count(elapsedTime * 1000000.0); | 294 commitGPUCanvasGPUCompositingMainTimer.count(elapsedTime * 1000000.0); |
253 } else { | 295 } /* else { |
254 DEFINE_STATIC_LOCAL( | 296 DEFINE_STATIC_LOCAL( |
255 CustomCountHistogram, commitGPUCanvasGPUCompositingWorkerTimer, | 297 CustomCountHistogram, commitGPUCanvasGPUCompositingWorkerTimer, |
256 ("Blink.Canvas.OffscreenCommit.GPUCanvasGPUCompositingWorker", 0, | 298 ("Blink.Canvas.OffscreenCommit.GPUCanvasGPUCompositingWorker", 0, |
257 10000000, 50)); | 299 10000000, 50)); |
258 commitGPUCanvasGPUCompositingWorkerTimer.count(elapsedTime * 1000000.0); | 300 commitGPUCanvasGPUCompositingWorkerTimer.count(elapsedTime * 1000000.0); |
259 } | 301 } */ |
260 break; | 302 break; |
261 case CommitGPUCanvasSoftwareCompositing: | 303 case CommitGPUCanvasSoftwareCompositing: |
262 if (isMainThread()) { | 304 if (isMainThread()) { |
263 DEFINE_STATIC_LOCAL( | 305 DEFINE_STATIC_LOCAL( |
264 CustomCountHistogram, commitGPUCanvasSoftwareCompositingMainTimer, | 306 CustomCountHistogram, commitGPUCanvasSoftwareCompositingMainTimer, |
265 ("Blink.Canvas.OffscreenCommit.GPUCanvasSoftwareCompositingMain", 0, | 307 ("Blink.Canvas.OffscreenCommit.GPUCanvasSoftwareCompositingMain", 0, |
266 10000000, 50)); | 308 10000000, 50)); |
267 commitGPUCanvasSoftwareCompositingMainTimer.count(elapsedTime * | 309 commitGPUCanvasSoftwareCompositingMainTimer.count(elapsedTime * |
268 1000000.0); | 310 1000000.0); |
269 } else { | 311 } /* else { |
270 DEFINE_STATIC_LOCAL( | 312 DEFINE_STATIC_LOCAL( |
271 CustomCountHistogram, commitGPUCanvasSoftwareCompositingWorkerTimer, | 313 CustomCountHistogram, commitGPUCanvasSoftwareCompositingWorkerTimer, |
272 ("Blink.Canvas.OffscreenCommit.GPUCanvasSoftwareCompositingWorker", | 314 ("Blink.Canvas.OffscreenCommit.GPUCanvasSoftwareCompositingWorker", |
273 0, 10000000, 50)); | 315 0, 10000000, 50)); |
274 commitGPUCanvasSoftwareCompositingWorkerTimer.count(elapsedTime * | 316 commitGPUCanvasSoftwareCompositingWorkerTimer.count(elapsedTime * |
275 1000000.0); | 317 1000000.0); |
276 } | 318 } */ |
277 break; | 319 break; |
278 case CommitSoftwareCanvasGPUCompositing: | 320 case CommitSoftwareCanvasGPUCompositing: |
279 if (isMainThread()) { | 321 if (isMainThread()) { |
280 DEFINE_STATIC_LOCAL( | 322 DEFINE_STATIC_LOCAL( |
281 CustomCountHistogram, commitSoftwareCanvasGPUCompositingMainTimer, | 323 CustomCountHistogram, commitSoftwareCanvasGPUCompositingMainTimer, |
282 ("Blink.Canvas.OffscreenCommit.SoftwareCanvasGPUCompositingMain", 0, | 324 ("Blink.Canvas.OffscreenCommit.SoftwareCanvasGPUCompositingMain", 0, |
283 10000000, 50)); | 325 10000000, 50)); |
284 commitSoftwareCanvasGPUCompositingMainTimer.count(elapsedTime * | 326 commitSoftwareCanvasGPUCompositingMainTimer.count(elapsedTime * |
285 1000000.0); | 327 1000000.0); |
286 } else { | 328 } /* else { |
287 DEFINE_STATIC_LOCAL( | 329 DEFINE_STATIC_LOCAL( |
288 CustomCountHistogram, commitSoftwareCanvasGPUCompositingWorkerTimer, | 330 CustomCountHistogram, commitSoftwareCanvasGPUCompositingWorkerTimer, |
289 ("Blink.Canvas.OffscreenCommit.SoftwareCanvasGPUCompositingWorker", | 331 ("Blink.Canvas.OffscreenCommit.SoftwareCanvasGPUCompositingWorker", |
290 0, 10000000, 50)); | 332 0, 10000000, 50)); |
291 commitSoftwareCanvasGPUCompositingWorkerTimer.count(elapsedTime * | 333 commitSoftwareCanvasGPUCompositingWorkerTimer.count(elapsedTime * |
292 1000000.0); | 334 1000000.0); |
293 } | 335 } */ |
294 break; | 336 break; |
295 case CommitSoftwareCanvasSoftwareCompositing: | 337 case CommitSoftwareCanvasSoftwareCompositing: |
296 if (isMainThread()) { | 338 if (isMainThread()) { |
297 DEFINE_STATIC_LOCAL(CustomCountHistogram, | 339 DEFINE_STATIC_LOCAL(CustomCountHistogram, |
298 commitSoftwareCanvasSoftwareCompositingMainTimer, | 340 commitSoftwareCanvasSoftwareCompositingMainTimer, |
299 ("Blink.Canvas.OffscreenCommit." | 341 ("Blink.Canvas.OffscreenCommit." |
300 "SoftwareCanvasSoftwareCompositingMain", | 342 "SoftwareCanvasSoftwareCompositingMain", |
301 0, 10000000, 50)); | 343 0, 10000000, 50)); |
302 commitSoftwareCanvasSoftwareCompositingMainTimer.count(elapsedTime * | 344 commitSoftwareCanvasSoftwareCompositingMainTimer.count(elapsedTime * |
303 1000000.0); | 345 1000000.0); |
304 } else { | 346 } /* else { |
305 DEFINE_STATIC_LOCAL(CustomCountHistogram, | 347 DEFINE_STATIC_LOCAL(CustomCountHistogram, |
306 commitSoftwareCanvasSoftwareCompositingWorkerTimer, | 348 commitSoftwareCanvasSoftwareCompositingWorkerTimer, |
307 ("Blink.Canvas.OffscreenCommit." | 349 ("Blink.Canvas.OffscreenCommit." |
308 "SoftwareCanvasSoftwareCompositingWorker", | 350 "SoftwareCanvasSoftwareCompositingWorker", |
309 0, 10000000, 50)); | 351 0, 10000000, 50)); |
310 commitSoftwareCanvasSoftwareCompositingWorkerTimer.count(elapsedTime * | 352 commitSoftwareCanvasSoftwareCompositingWorkerTimer.count(elapsedTime * |
311 1000000.0); | 353 1000000.0); |
312 } | 354 } */ |
313 break; | 355 break; |
314 case OffscreenCanvasCommitTypeCount: | 356 case OffscreenCanvasCommitTypeCount: |
315 NOTREACHED(); | 357 NOTREACHED(); |
316 } | 358 } |
317 | 359 |
318 m_sink->SubmitCompositorFrame(std::move(frame)); | 360 m_sink->SubmitCompositorFrame(std::move(frame)); |
319 } | 361 } |
320 | 362 |
321 void OffscreenCanvasFrameDispatcherImpl::DidReceiveCompositorFrameAck() { | 363 void OffscreenCanvasFrameDispatcherImpl::DidReceiveCompositorFrameAck() { |
322 // TODO(fsamuel): Implement this. | 364 // TODO(fsamuel): Implement this. |
323 } | 365 } |
324 | 366 |
325 void OffscreenCanvasFrameDispatcherImpl::OnBeginFrame( | 367 void OffscreenCanvasFrameDispatcherImpl::OnBeginFrame( |
326 const cc::BeginFrameArgs& beginFrameArgs) {} | 368 const cc::BeginFrameArgs& beginFrameArgs) {} |
327 | 369 |
328 void OffscreenCanvasFrameDispatcherImpl::ReclaimResources( | 370 void OffscreenCanvasFrameDispatcherImpl::ReclaimResources( |
329 const cc::ReturnedResourceArray& resources) { | 371 const cc::ReturnedResourceArray& resources) { |
330 for (const auto& resource : resources) { | 372 for (const auto& resource : resources) { |
331 RefPtr<StaticBitmapImage> image = m_cachedImages.get(resource.id); | 373 RefPtr<StaticBitmapImage> image = m_cachedImages.get(resource.id); |
332 if (image) | 374 if (image) |
333 image->updateSyncToken(resource.sync_token); | 375 image->updateSyncToken(resource.sync_token); |
334 m_cachedImages.remove(resource.id); | 376 reclaimResource(resource.id); |
335 m_sharedBitmaps.remove(resource.id); | |
336 m_cachedTextureIds.remove(resource.id); | |
337 } | 377 } |
338 } | 378 } |
339 | 379 |
| 380 void OffscreenCanvasFrameDispatcherImpl::reclaimResource(unsigned resourceId) { |
| 381 // An image resource needs to be returned by both the |
| 382 // CompositorFrameSink and the HTMLCanvasElement. These |
| 383 // events can happen in any order. The first of the two |
| 384 // to return a given resource will result in the spare |
| 385 // resource lock being lifted, and the second will delete |
| 386 // the resource for real. |
| 387 if (m_spareResourceLocks.contains(resourceId)) { |
| 388 m_spareResourceLocks.remove(resourceId); |
| 389 return; |
| 390 } |
| 391 m_cachedImages.remove(resourceId); |
| 392 m_sharedBitmaps.remove(resourceId); |
| 393 m_cachedTextureIds.remove(resourceId); |
| 394 } |
| 395 |
340 bool OffscreenCanvasFrameDispatcherImpl::verifyImageSize( | 396 bool OffscreenCanvasFrameDispatcherImpl::verifyImageSize( |
341 const IntSize imageSize) { | 397 const IntSize imageSize) { |
342 if (imageSize.width() == m_width && imageSize.height() == m_height) | 398 if (imageSize.width() == m_width && imageSize.height() == m_height) |
343 return true; | 399 return true; |
344 return false; | 400 return false; |
345 } | 401 } |
346 | 402 |
347 } // namespace blink | 403 } // namespace blink |
OLD | NEW |