[go: nahoru, domu]

Reland of cc: Add mailbox support to ResourceProvider write locks. (patchset #1 id:1 of https://codereview.chromium.org/2106503002/ )

Original issue's description:
> Revert of cc: Add mailbox support to ResourceProvider write locks. (patchset #5 id:70001 of https://codereview.chromium.org/2081883002/ )
>
> Reason for revert:
> Causing canvas crashes - bug 623101
>
> Original issue's description:
> > Reland of cc: Add mailbox support to ResourceProvider write locks. (patchset #24 id:460001 of https://codereview.chromium.org/1951193002/ )
> >
> > Original issue's description:
> > > cc: Add mailbox support to ResourceProvider write locks.
> > >
> > > This adds support for mailboxes to ScopedWriteLockGL. Using the mailbox
> > > requires using ScopedTextureProvider/ScopedSkSurfaceProvider which
> > > ensures that the texture id for the mailbox is destroyed after use on
> > > the worker context.
> > >
> > > This CL also includes the following cleanup:
> > > 1. ResourceProvider locks don't keep resource pointers around.
> > > 2. ScopedSamplerGL does not inherit from ScopedReadLockGL.
> > > 3. GpuRasterizer is folded back into GpuRasterBufferProvider.
> > > 4. TileTaskManager does not own RasterBufferProvider.
> > >
> > > BUG=525259
> > > R=piman@chromium.org
> > > CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel
> > >
> > > Committed: https://crrev.com/5fa5dbdf25bbec21b84f752d3f0642cd184467e2
> > > Committed: https://crrev.com/3b0f0b8d3db0a9f66864d5b7da87c82f49e74a29
> > > Cr-Original-Commit-Position: refs/heads/master@{#398204}
> > > Cr-Commit-Position: refs/heads/master@{#399983}
> >
> > R=piman@chromium.org
> > BUG=525259, 621422, 621130
> > CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel
> >
> > Committed: https://crrev.com/b3071e4aabd0cb1f29cd624e77eb5f40722be965
> > Cr-Commit-Position: refs/heads/master@{#401717}
>
> TBR=piman@chromium.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=525259, 621422, 621130
>
> Committed: https://crrev.com/4d27a5a3c38c34bfa34e9937ef8e3ea3831d2194
> Cr-Commit-Position: refs/heads/master@{#402290}

TBR=piman@chromium.org
BUG=525259, 621422, 621130

Review-Url: https://codereview.chromium.org/2101043002
Cr-Commit-Position: refs/heads/master@{#402345}
diff --git a/cc/raster/gpu_raster_buffer_provider.cc b/cc/raster/gpu_raster_buffer_provider.cc
index 6e5b4c4..12fb55a1 100644
--- a/cc/raster/gpu_raster_buffer_provider.cc
+++ b/cc/raster/gpu_raster_buffer_provider.cc
@@ -12,7 +12,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/playback/raster_source.h"
-#include "cc/raster/gpu_rasterizer.h"
 #include "cc/raster/scoped_gpu_raster.h"
 #include "cc/resources/resource.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
@@ -24,89 +23,121 @@
 namespace cc {
 namespace {
 
-class RasterBufferImpl : public RasterBuffer {
- public:
-  RasterBufferImpl(GpuRasterizer* rasterizer,
-                   const Resource* resource,
-                   uint64_t resource_content_id,
-                   uint64_t previous_content_id)
-      : rasterizer_(rasterizer),
-        lock_(rasterizer->resource_provider(), resource->id()),
-        resource_has_previous_content_(
-            resource_content_id && resource_content_id == previous_content_id) {
+static sk_sp<SkPicture> PlaybackToPicture(
+    const RasterSource* raster_source,
+    bool resource_has_previous_content,
+    const gfx::Size& resource_size,
+    const gfx::Rect& raster_full_rect,
+    const gfx::Rect& raster_dirty_rect,
+    float scale,
+    const RasterSource::PlaybackSettings& playback_settings) {
+  // GPU raster doesn't do low res tiles, so should always include images.
+  DCHECK(!playback_settings.skip_images);
+
+  gfx::Rect playback_rect = raster_full_rect;
+  if (resource_has_previous_content) {
+    playback_rect.Intersect(raster_dirty_rect);
   }
+  DCHECK(!playback_rect.IsEmpty())
+      << "Why are we rastering a tile that's not dirty?";
 
-  // Overridden from RasterBuffer:
-  void Playback(
-      const RasterSource* raster_source,
-      const gfx::Rect& raster_full_rect,
-      const gfx::Rect& raster_dirty_rect,
-      uint64_t new_content_id,
-      float scale,
-      const RasterSource::PlaybackSettings& playback_settings) override {
-    TRACE_EVENT0("cc", "GpuRasterBuffer::Playback");
-    // GPU raster doesn't do low res tiles, so should always include images.
-    DCHECK(!playback_settings.skip_images);
+  // Play back raster_source into temp SkPicture.
+  SkPictureRecorder recorder;
+  const int flags = SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
+  sk_sp<SkCanvas> canvas = sk_ref_sp(recorder.beginRecording(
+      resource_size.width(), resource_size.height(), NULL, flags));
+  canvas->save();
+  raster_source->PlaybackToCanvas(canvas.get(), raster_full_rect, playback_rect,
+                                  scale, playback_settings);
+  canvas->restore();
+  return recorder.finishRecordingAsPicture();
+}
 
-    ContextProvider::ScopedContextLock scoped_context(
-        rasterizer_->worker_context_provider());
+static void RasterizePicture(SkPicture* picture,
+                             ContextProvider* context_provider,
+                             ResourceProvider::ScopedWriteLockGL* resource_lock,
+                             bool async_worker_context_enabled,
+                             bool use_distance_field_text,
+                             bool can_use_lcd_text,
+                             int msaa_sample_count) {
+  ScopedGpuRaster gpu_raster(context_provider);
 
-    gfx::Rect playback_rect = raster_full_rect;
-    if (resource_has_previous_content_) {
-      playback_rect.Intersect(raster_dirty_rect);
-    }
-    DCHECK(!playback_rect.IsEmpty())
-        << "Why are we rastering a tile that's not dirty?";
+  ResourceProvider::ScopedSkSurfaceProvider scoped_surface(
+      context_provider, resource_lock, async_worker_context_enabled,
+      use_distance_field_text, can_use_lcd_text, msaa_sample_count);
+  SkSurface* sk_surface = scoped_surface.sk_surface();
+  // Allocating an SkSurface will fail after a lost context.  Pretend we
+  // rasterized, as the contents of the resource don't matter anymore.
+  if (!sk_surface)
+    return;
 
-    // TODO(danakj): Implement partial raster with raster_dirty_rect.
-    // Rasterize source into resource.
-    rasterizer_->RasterizeSource(&lock_, raster_source, raster_full_rect,
-                                 playback_rect, scale, playback_settings);
-
-    gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL();
-    const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM();
-
-    // Barrier to sync worker context output to cc context.
-    gl->OrderingBarrierCHROMIUM();
-
-    // Generate sync token after the barrier for cross context synchronization.
-    gpu::SyncToken sync_token;
-    gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
-    lock_.UpdateResourceSyncToken(sync_token);
-  }
-
- private:
-  GpuRasterizer* rasterizer_;
-  ResourceProvider::ScopedWriteLockGr lock_;
-  bool resource_has_previous_content_;
-
-  DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
-};
+  SkMultiPictureDraw multi_picture_draw;
+  multi_picture_draw.add(sk_surface->getCanvas(), picture);
+  multi_picture_draw.draw(false);
+}
 
 }  // namespace
 
+GpuRasterBufferProvider::RasterBufferImpl::RasterBufferImpl(
+    GpuRasterBufferProvider* client,
+    ResourceProvider* resource_provider,
+    ResourceId resource_id,
+    bool async_worker_context_enabled,
+    bool resource_has_previous_content)
+    : client_(client),
+      lock_(resource_provider, resource_id, async_worker_context_enabled),
+      resource_has_previous_content_(resource_has_previous_content) {
+  client_->pending_raster_buffers_.insert(this);
+}
+
+GpuRasterBufferProvider::RasterBufferImpl::~RasterBufferImpl() {
+  client_->pending_raster_buffers_.erase(this);
+}
+
+void GpuRasterBufferProvider::RasterBufferImpl::Playback(
+    const RasterSource* raster_source,
+    const gfx::Rect& raster_full_rect,
+    const gfx::Rect& raster_dirty_rect,
+    uint64_t new_content_id,
+    float scale,
+    const RasterSource::PlaybackSettings& playback_settings) {
+  TRACE_EVENT0("cc", "GpuRasterBuffer::Playback");
+  client_->PlaybackOnWorkerThread(&lock_, sync_token_,
+                                  resource_has_previous_content_, raster_source,
+                                  raster_full_rect, raster_dirty_rect,
+                                  new_content_id, scale, playback_settings);
+}
+
 GpuRasterBufferProvider::GpuRasterBufferProvider(
     ContextProvider* compositor_context_provider,
     ContextProvider* worker_context_provider,
     ResourceProvider* resource_provider,
     bool use_distance_field_text,
-    int gpu_rasterization_msaa_sample_count)
+    int gpu_rasterization_msaa_sample_count,
+    bool async_worker_context_enabled)
     : compositor_context_provider_(compositor_context_provider),
-      rasterizer_(new GpuRasterizer(worker_context_provider,
-                                    resource_provider,
-                                    use_distance_field_text,
-                                    gpu_rasterization_msaa_sample_count)) {
-  DCHECK(compositor_context_provider_);
+      worker_context_provider_(worker_context_provider),
+      resource_provider_(resource_provider),
+      use_distance_field_text_(use_distance_field_text),
+      msaa_sample_count_(gpu_rasterization_msaa_sample_count),
+      async_worker_context_enabled_(async_worker_context_enabled) {
+  DCHECK(compositor_context_provider);
+  DCHECK(worker_context_provider);
 }
 
-GpuRasterBufferProvider::~GpuRasterBufferProvider() {}
+GpuRasterBufferProvider::~GpuRasterBufferProvider() {
+  DCHECK(pending_raster_buffers_.empty());
+}
 
 std::unique_ptr<RasterBuffer> GpuRasterBufferProvider::AcquireBufferForRaster(
     const Resource* resource,
     uint64_t resource_content_id,
     uint64_t previous_content_id) {
-  return std::unique_ptr<RasterBuffer>(new RasterBufferImpl(
-      rasterizer_.get(), resource, resource_content_id, previous_content_id));
+  bool resource_has_previous_content =
+      resource_content_id && resource_content_id == previous_content_id;
+  return base::WrapUnique(new RasterBufferImpl(
+      this, resource_provider_, resource->id(), async_worker_context_enabled_,
+      resource_has_previous_content));
 }
 
 void GpuRasterBufferProvider::ReleaseBufferForRaster(
@@ -116,12 +147,29 @@
 
 void GpuRasterBufferProvider::OrderingBarrier() {
   TRACE_EVENT0("cc", "GpuRasterBufferProvider::OrderingBarrier");
-  compositor_context_provider_->ContextGL()->OrderingBarrierCHROMIUM();
+
+  gpu::gles2::GLES2Interface* gl = compositor_context_provider_->ContextGL();
+  if (async_worker_context_enabled_) {
+    GLuint64 fence = gl->InsertFenceSyncCHROMIUM();
+    gl->OrderingBarrierCHROMIUM();
+
+    gpu::SyncToken sync_token;
+    gl->GenUnverifiedSyncTokenCHROMIUM(fence, sync_token.GetData());
+
+    DCHECK(sync_token.HasData() ||
+           gl->GetGraphicsResetStatusKHR() != GL_NO_ERROR);
+
+    for (RasterBufferImpl* buffer : pending_raster_buffers_)
+      buffer->set_sync_token(sync_token);
+  } else {
+    gl->OrderingBarrierCHROMIUM();
+  }
+  pending_raster_buffers_.clear();
 }
 
 ResourceFormat GpuRasterBufferProvider::GetResourceFormat(
     bool must_support_alpha) const {
-  return rasterizer_->resource_provider()->best_render_buffer_format();
+  return resource_provider_->best_render_buffer_format();
 }
 
 bool GpuRasterBufferProvider::GetResourceRequiresSwizzle(
@@ -130,6 +178,56 @@
   return false;
 }
 
-void GpuRasterBufferProvider::Shutdown() {}
+void GpuRasterBufferProvider::Shutdown() {
+  pending_raster_buffers_.clear();
+}
+
+void GpuRasterBufferProvider::PlaybackOnWorkerThread(
+    ResourceProvider::ScopedWriteLockGL* resource_lock,
+    const gpu::SyncToken& sync_token,
+    bool resource_has_previous_content,
+    const RasterSource* raster_source,
+    const gfx::Rect& raster_full_rect,
+    const gfx::Rect& raster_dirty_rect,
+    uint64_t new_content_id,
+    float scale,
+    const RasterSource::PlaybackSettings& playback_settings) {
+  ContextProvider::ScopedContextLock scoped_context(worker_context_provider_);
+  gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL();
+  DCHECK(gl);
+
+  if (async_worker_context_enabled_) {
+    // Early out if sync token is invalid. This happens if the compositor
+    // context was lost before ScheduleTasks was called.
+    if (!sync_token.HasData())
+      return;
+    // Synchronize with compositor.
+    gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
+  }
+
+  sk_sp<SkPicture> picture = PlaybackToPicture(
+      raster_source, resource_has_previous_content, resource_lock->size(),
+      raster_full_rect, raster_dirty_rect, scale, playback_settings);
+
+  // Turn on distance fields for layers that have ever animated.
+  bool use_distance_field_text =
+      use_distance_field_text_ ||
+      raster_source->ShouldAttemptToUseDistanceFieldText();
+
+  RasterizePicture(picture.get(), worker_context_provider_, resource_lock,
+                   async_worker_context_enabled_, use_distance_field_text,
+                   raster_source->CanUseLCDText(), msaa_sample_count_);
+
+  const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM();
+
+  // Barrier to sync worker context output to cc context.
+  gl->OrderingBarrierCHROMIUM();
+
+  // Generate sync token after the barrier for cross context synchronization.
+  gpu::SyncToken resource_sync_token;
+  gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, resource_sync_token.GetData());
+  resource_lock->set_sync_token(resource_sync_token);
+  resource_lock->set_synchronized(!async_worker_context_enabled_);
+}
 
 }  // namespace cc