| 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/CrossThreadFunctional.h" |
| 11 #include "platform/Histogram.h" | 11 #include "platform/Histogram.h" |
| 12 #include "platform/WebTaskRunner.h" | 12 #include "platform/WebTaskRunner.h" |
| 13 #include "platform/graphics/OffscreenCanvasPlaceholder.h" | 13 #include "platform/graphics/OffscreenCanvasPlaceholder.h" |
| 14 #include "platform/graphics/gpu/SharedGpuContext.h" | 14 #include "platform/graphics/gpu/SharedGpuContext.h" |
| 15 #include "public/platform/InterfaceProvider.h" | 15 #include "public/platform/InterfaceProvider.h" |
| 16 #include "public/platform/Platform.h" | 16 #include "public/platform/Platform.h" |
| 17 #include "public/platform/WebGraphicsContext3DProvider.h" | 17 #include "public/platform/WebGraphicsContext3DProvider.h" |
| 18 #include "public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
-blink.h" | 18 #include "public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
-blink.h" |
| 19 #include "third_party/khronos/GLES2/gl2.h" | 19 #include "third_party/khronos/GLES2/gl2.h" |
| 20 #include "third_party/khronos/GLES2/gl2ext.h" | 20 #include "third_party/khronos/GLES2/gl2ext.h" |
| 21 #include "third_party/skia/include/core/SkColor.h" | 21 #include "third_party/skia/include/core/SkColor.h" |
| 22 #include "third_party/skia/include/core/SkImage.h" | 22 #include "third_party/skia/include/core/SkImage.h" |
| 23 #include "ui/gfx/geometry/rect.h" | 23 #include "ui/gfx/geometry/rect.h" |
| 24 #include "ui/gfx/transform.h" | 24 #include "ui/gfx/transform.h" |
| 25 #include "wtf/typed_arrays/ArrayBuffer.h" | 25 #include "wtf/typed_arrays/ArrayBuffer.h" |
| 26 #include "wtf/typed_arrays/Uint8Array.h" | 26 #include "wtf/typed_arrays/Uint8Array.h" |
| 27 | 27 |
| 28 namespace blink { | 28 namespace blink { |
| 29 | 29 |
| 30 // This constant specifies the maximum number of pixel buffer that are allowed | |
| 31 // to co-exist at a given time. The minimum number is 2 (double buffered). | |
| 32 // larger numbers can help maintain a steadier frame rates, but they increase | |
| 33 // latency. | |
| 34 const int kMaximumOffscreenCanvasBufferCount = 3; | |
| 35 | |
| 36 OffscreenCanvasFrameDispatcherImpl::OffscreenCanvasFrameDispatcherImpl( | 30 OffscreenCanvasFrameDispatcherImpl::OffscreenCanvasFrameDispatcherImpl( |
| 37 OffscreenCanvasFrameDispatcherClient* client, | 31 OffscreenCanvasFrameDispatcherClient* client, |
| 38 uint32_t clientId, | 32 uint32_t clientId, |
| 39 uint32_t sinkId, | 33 uint32_t sinkId, |
| 40 int canvasId, | 34 int canvasId, |
| 41 int width, | 35 int width, |
| 42 int height) | 36 int height) |
| 43 : OffscreenCanvasFrameDispatcher(client), | 37 : OffscreenCanvasFrameDispatcher(client), |
| 44 m_frameSinkId(cc::FrameSinkId(clientId, sinkId)), | 38 m_frameSinkId(cc::FrameSinkId(clientId, sinkId)), |
| 45 m_width(width), | 39 m_width(width), |
| 46 m_height(height), | 40 m_height(height), |
| 47 m_changeSizeForNextCommit(false), | 41 m_changeSizeForNextCommit(false), |
| 42 m_needsBeginFrame(false), |
| 48 m_nextResourceId(1u), | 43 m_nextResourceId(1u), |
| 49 m_binding(this), | 44 m_binding(this), |
| 50 m_placeholderCanvasId(canvasId) { | 45 m_placeholderCanvasId(canvasId) { |
| 51 m_currentLocalSurfaceId = m_surfaceIdAllocator.GenerateId(); | 46 if (m_frameSinkId.is_valid()) { |
| 52 DCHECK(!m_sink.is_bound()); | 47 // Only frameless canvas pass an invalid frame sink id; we don't create |
| 53 mojom::blink::OffscreenCanvasCompositorFrameSinkProviderPtr provider; | 48 // mojo channel for this special case. |
| 54 Platform::current()->interfaceProvider()->getInterface( | 49 m_currentLocalSurfaceId = m_surfaceIdAllocator.GenerateId(); |
| 55 mojo::MakeRequest(&provider)); | 50 DCHECK(!m_sink.is_bound()); |
| 56 provider->CreateCompositorFrameSink(m_frameSinkId, | 51 mojom::blink::OffscreenCanvasCompositorFrameSinkProviderPtr provider; |
| 57 m_binding.CreateInterfacePtrAndBind(), | 52 Platform::current()->interfaceProvider()->getInterface( |
| 58 mojo::MakeRequest(&m_sink)); | 53 mojo::MakeRequest(&provider)); |
| 54 provider->CreateCompositorFrameSink(m_frameSinkId, |
| 55 m_binding.CreateInterfacePtrAndBind(), |
| 56 mojo::MakeRequest(&m_sink)); |
| 57 } |
| 59 } | 58 } |
| 60 | 59 |
| 61 OffscreenCanvasFrameDispatcherImpl::~OffscreenCanvasFrameDispatcherImpl() { | 60 OffscreenCanvasFrameDispatcherImpl::~OffscreenCanvasFrameDispatcherImpl() { |
| 62 m_syntheticBeginFrameTask.cancel(); | |
| 63 } | 61 } |
| 64 | 62 |
| 65 void OffscreenCanvasFrameDispatcherImpl::setTransferableResourceToSharedBitmap( | 63 void OffscreenCanvasFrameDispatcherImpl::setTransferableResourceToSharedBitmap( |
| 66 cc::TransferableResource& resource, | 64 cc::TransferableResource& resource, |
| 67 RefPtr<StaticBitmapImage> image) { | 65 RefPtr<StaticBitmapImage> image) { |
| 68 std::unique_ptr<cc::SharedBitmap> bitmap = | 66 std::unique_ptr<cc::SharedBitmap> bitmap = |
| 69 Platform::current()->allocateSharedBitmap(IntSize(m_width, m_height)); | 67 Platform::current()->allocateSharedBitmap(IntSize(m_width, m_height)); |
| 70 if (!bitmap) | 68 if (!bitmap) |
| 71 return; | 69 return; |
| 72 unsigned char* pixels = bitmap->pixels(); | 70 unsigned char* pixels = bitmap->pixels(); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 OffscreenCanvasPlaceholder::getPlaceholderById(placeholderCanvasId); | 176 OffscreenCanvasPlaceholder::getPlaceholderById(placeholderCanvasId); |
| 179 if (placeholderCanvas) { | 177 if (placeholderCanvas) { |
| 180 placeholderCanvas->setPlaceholderFrame(std::move(image), | 178 placeholderCanvas->setPlaceholderFrame(std::move(image), |
| 181 std::move(dispatcher), | 179 std::move(dispatcher), |
| 182 std::move(taskRunner), resourceId); | 180 std::move(taskRunner), resourceId); |
| 183 } | 181 } |
| 184 } | 182 } |
| 185 | 183 |
| 186 } // namespace | 184 } // namespace |
| 187 | 185 |
| 186 void OffscreenCanvasFrameDispatcherImpl::postImageToPlaceholder( |
| 187 RefPtr<StaticBitmapImage> image) { |
| 188 // After this point, |image| can only be used on the main thread, until |
| 189 // it is returned. |
| 190 image->transfer(); |
| 191 RefPtr<WebTaskRunner> dispatcherTaskRunner = |
| 192 Platform::current()->currentThread()->getWebTaskRunner(); |
| 193 |
| 194 Platform::current()->mainThread()->getWebTaskRunner()->postTask( |
| 195 BLINK_FROM_HERE, |
| 196 crossThreadBind(updatePlaceholderImage, this->createWeakPtr(), |
| 197 WTF::passed(std::move(dispatcherTaskRunner)), |
| 198 m_placeholderCanvasId, std::move(image), |
| 199 m_nextResourceId)); |
| 200 m_spareResourceLocks.insert(m_nextResourceId); |
| 201 } |
| 202 |
| 188 void OffscreenCanvasFrameDispatcherImpl::dispatchFrame( | 203 void OffscreenCanvasFrameDispatcherImpl::dispatchFrame( |
| 189 RefPtr<StaticBitmapImage> image, | 204 RefPtr<StaticBitmapImage> image, |
| 190 double commitStartTime, | 205 double commitStartTime, |
| 191 bool isWebGLSoftwareRendering /* This flag is true when WebGL's commit is | 206 bool isWebGLSoftwareRendering /* This flag is true when WebGL's commit is |
| 192 called on SwiftShader. */) { | 207 called on SwiftShader. */) { |
| 193 if (!image || !verifyImageSize(image->size())) | 208 if (!image || !verifyImageSize(image->size())) |
| 194 return; | 209 return; |
| 210 if (!m_frameSinkId.is_valid()) { |
| 211 postImageToPlaceholder(std::move(image)); |
| 212 return; |
| 213 } |
| 195 cc::CompositorFrame frame; | 214 cc::CompositorFrame frame; |
| 196 // TODO(crbug.com/652931): update the device_scale_factor | 215 // TODO(crbug.com/652931): update the device_scale_factor |
| 197 frame.metadata.device_scale_factor = 1.0f; | 216 frame.metadata.device_scale_factor = 1.0f; |
| 198 | 217 |
| 199 const gfx::Rect bounds(m_width, m_height); | 218 const gfx::Rect bounds(m_width, m_height); |
| 200 const int renderPassId = 1; | 219 const int renderPassId = 1; |
| 201 std::unique_ptr<cc::RenderPass> pass = cc::RenderPass::Create(); | 220 std::unique_ptr<cc::RenderPass> pass = cc::RenderPass::Create(); |
| 202 pass->SetNew(renderPassId, bounds, bounds, gfx::Transform()); | 221 pass->SetNew(renderPassId, bounds, bounds, gfx::Transform()); |
| 203 pass->has_transparent_background = false; | 222 pass->has_transparent_background = false; |
| 204 | 223 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 // Case 3: canvas is not gpu-accelerated, but compositor is | 259 // Case 3: canvas is not gpu-accelerated, but compositor is |
| 241 commitType = CommitSoftwareCanvasGPUCompositing; | 260 commitType = CommitSoftwareCanvasGPUCompositing; |
| 242 setTransferableResourceToSharedGPUContext(resource, image); | 261 setTransferableResourceToSharedGPUContext(resource, image); |
| 243 } else { | 262 } else { |
| 244 // Case 4: both canvas and compositor are not gpu accelerated. | 263 // Case 4: both canvas and compositor are not gpu accelerated. |
| 245 commitType = CommitSoftwareCanvasSoftwareCompositing; | 264 commitType = CommitSoftwareCanvasSoftwareCompositing; |
| 246 setTransferableResourceToSharedBitmap(resource, image); | 265 setTransferableResourceToSharedBitmap(resource, image); |
| 247 } | 266 } |
| 248 } | 267 } |
| 249 | 268 |
| 250 // After this point, |image| can only be used on the main thread, until | 269 postImageToPlaceholder(std::move(image)); |
| 251 // it is returned. | |
| 252 image->transfer(); | |
| 253 RefPtr<WebTaskRunner> dispatcherTaskRunner = | |
| 254 Platform::current()->currentThread()->getWebTaskRunner(); | |
| 255 | |
| 256 Platform::current()->mainThread()->getWebTaskRunner()->postTask( | |
| 257 BLINK_FROM_HERE, | |
| 258 crossThreadBind(updatePlaceholderImage, this->createWeakPtr(), | |
| 259 WTF::passed(std::move(dispatcherTaskRunner)), | |
| 260 m_placeholderCanvasId, std::move(image), resource.id)); | |
| 261 m_spareResourceLocks.insert(m_nextResourceId); | |
| 262 | |
| 263 commitTypeHistogram.count(commitType); | 270 commitTypeHistogram.count(commitType); |
| 264 | 271 |
| 265 m_nextResourceId++; | 272 m_nextResourceId++; |
| 266 frame.resource_list.push_back(std::move(resource)); | 273 frame.resource_list.push_back(std::move(resource)); |
| 267 | 274 |
| 268 cc::TextureDrawQuad* quad = | 275 cc::TextureDrawQuad* quad = |
| 269 pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>(); | 276 pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>(); |
| 270 gfx::Size rectSize(m_width, m_height); | 277 gfx::Size rectSize(m_width, m_height); |
| 271 | 278 |
| 272 const bool needsBlending = true; | 279 const bool needsBlending = true; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 } | 371 } |
| 365 break; | 372 break; |
| 366 case OffscreenCanvasCommitTypeCount: | 373 case OffscreenCanvasCommitTypeCount: |
| 367 NOTREACHED(); | 374 NOTREACHED(); |
| 368 } | 375 } |
| 369 | 376 |
| 370 if (m_changeSizeForNextCommit) { | 377 if (m_changeSizeForNextCommit) { |
| 371 m_currentLocalSurfaceId = m_surfaceIdAllocator.GenerateId(); | 378 m_currentLocalSurfaceId = m_surfaceIdAllocator.GenerateId(); |
| 372 m_changeSizeForNextCommit = false; | 379 m_changeSizeForNextCommit = false; |
| 373 } | 380 } |
| 381 |
| 374 m_sink->SubmitCompositorFrame(m_currentLocalSurfaceId, std::move(frame)); | 382 m_sink->SubmitCompositorFrame(m_currentLocalSurfaceId, std::move(frame)); |
| 375 | |
| 376 // TODO(crbug.com/674744): Get BeginFrame to fire on its own. | |
| 377 scheduleSyntheticBeginFrame(); | |
| 378 } | |
| 379 | |
| 380 void OffscreenCanvasFrameDispatcherImpl::scheduleSyntheticBeginFrame() { | |
| 381 m_syntheticBeginFrameTask = | |
| 382 Platform::current() | |
| 383 ->currentThread() | |
| 384 ->getWebTaskRunner() | |
| 385 ->postDelayedCancellableTask( | |
| 386 BLINK_FROM_HERE, | |
| 387 WTF::bind(&OffscreenCanvasFrameDispatcherImpl::OnBeginFrame, | |
| 388 WTF::unretained(this), cc::BeginFrameArgs()), | |
| 389 16); | |
| 390 } | 383 } |
| 391 | 384 |
| 392 void OffscreenCanvasFrameDispatcherImpl::DidReceiveCompositorFrameAck() { | 385 void OffscreenCanvasFrameDispatcherImpl::DidReceiveCompositorFrameAck() { |
| 393 // TODO(fsamuel): Implement this. | 386 // TODO(fsamuel): Implement this. |
| 394 } | 387 } |
| 395 | 388 |
| 396 void OffscreenCanvasFrameDispatcherImpl::OnBeginFrame( | 389 void OffscreenCanvasFrameDispatcherImpl::setNeedsBeginFrame( |
| 397 const cc::BeginFrameArgs& beginFrameArgs) { | 390 bool needsBeginFrame) { |
| 398 if (!client()) | 391 if (m_sink && needsBeginFrame != m_needsBeginFrame) { |
| 399 return; | 392 m_needsBeginFrame = needsBeginFrame; |
| 400 unsigned framesInFlight = m_cachedImages.size() + m_sharedBitmaps.size() + | 393 m_sink->SetNeedsBeginFrame(needsBeginFrame); |
| 401 m_cachedTextureIds.size(); | |
| 402 | |
| 403 // Limit the rate of compositor commits. | |
| 404 if (framesInFlight < kMaximumOffscreenCanvasBufferCount) { | |
| 405 client()->beginFrame(); | |
| 406 } else { | |
| 407 // TODO(crbug.com/674744): Get BeginFrame to fire on its own. | |
| 408 // The following call is to reschedule the frame in cases where we encounter | |
| 409 // a backlog. | |
| 410 scheduleSyntheticBeginFrame(); | |
| 411 } | 394 } |
| 412 } | 395 } |
| 413 | 396 |
| 397 void OffscreenCanvasFrameDispatcherImpl::OnBeginFrame( |
| 398 const cc::BeginFrameArgs& beginFrameArgs) { |
| 399 DCHECK(client()); |
| 400 client()->beginFrame(); |
| 401 } |
| 402 |
| 414 void OffscreenCanvasFrameDispatcherImpl::ReclaimResources( | 403 void OffscreenCanvasFrameDispatcherImpl::ReclaimResources( |
| 415 const cc::ReturnedResourceArray& resources) { | 404 const cc::ReturnedResourceArray& resources) { |
| 416 for (const auto& resource : resources) { | 405 for (const auto& resource : resources) { |
| 417 RefPtr<StaticBitmapImage> image = m_cachedImages.get(resource.id); | 406 RefPtr<StaticBitmapImage> image = m_cachedImages.get(resource.id); |
| 418 if (image) | 407 if (image) |
| 419 image->updateSyncToken(resource.sync_token); | 408 image->updateSyncToken(resource.sync_token); |
| 420 reclaimResource(resource.id); | 409 reclaimResource(resource.id); |
| 421 } | 410 } |
| 422 } | 411 } |
| 423 | 412 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 450 | 439 |
| 451 void OffscreenCanvasFrameDispatcherImpl::reshape(int width, int height) { | 440 void OffscreenCanvasFrameDispatcherImpl::reshape(int width, int height) { |
| 452 if (m_width != width || m_height != height) { | 441 if (m_width != width || m_height != height) { |
| 453 m_width = width; | 442 m_width = width; |
| 454 m_height = height; | 443 m_height = height; |
| 455 m_changeSizeForNextCommit = true; | 444 m_changeSizeForNextCommit = true; |
| 456 } | 445 } |
| 457 } | 446 } |
| 458 | 447 |
| 459 } // namespace blink | 448 } // namespace blink |
| OLD | NEW |