[go: nahoru, domu]

Move ownership of gpu texture resources to ResourcePool

This makes allocation of resources in OneCopyRasterBufferProvider
and GpuRasterBufferProvider happen directly instead of through
a ResourceProvider lock, and stores ownership of the resources in the
ResourcePool. For each RasterBufferProvider,
a) When AcquireBufferForRaster is called it creates the GpuBacking
and ensures the sync token is waited on if present, and creates a texture
and mailbox.
b) After playback on the worker, a sync token is created.
c) When the RasterBuffer is destroyed, back on the compositor thread,
it stores that sync token into the GpuBacking.

R=sunnyps@chromium.org, vmpstr@chromium.org

Bug: 730660, 738190
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.android:android_optional_gpu_tests_rel
Change-Id: Ide0005262435cc4a0925766761221dc8852f0026
Reviewed-on: https://chromium-review.googlesource.com/895806
Commit-Queue: danakj <danakj@chromium.org>
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: Eric Karl <ericrk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#535741}
diff --git a/cc/raster/gpu_raster_buffer_provider.cc b/cc/raster/gpu_raster_buffer_provider.cc
index 58f2663b..ed755ba 100644
--- a/cc/raster/gpu_raster_buffer_provider.cc
+++ b/cc/raster/gpu_raster_buffer_provider.cc
@@ -21,15 +21,19 @@
 #include "cc/resources/resource.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
+#include "components/viz/common/gpu/texture_allocation.h"
 #include "components/viz/common/resources/resource_format_utils.h"
+#include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/client/raster_interface.h"
+#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "third_party/skia/include/core/SkMultiPictureDraw.h"
 #include "third_party/skia/include/core/SkPictureRecorder.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "ui/gfx/geometry/axis_transform2d.h"
+#include "ui/gl/trace_util.h"
 
 namespace cc {
 namespace {
@@ -37,21 +41,37 @@
 static void RasterizeSourceOOP(
     const RasterSource* raster_source,
     bool resource_has_previous_content,
+    const gpu::Mailbox& mailbox,
+    GLenum texture_target,
+    bool texture_is_overlay_candidate,
+    bool texture_storage_allocated,
+    const gfx::Size& resource_size,
+    viz::ResourceFormat resource_format,
+    const gfx::ColorSpace& color_space,
     const gfx::Rect& raster_full_rect,
     const gfx::Rect& playback_rect,
     const gfx::AxisTransform2d& transform,
     const RasterSource::PlaybackSettings& playback_settings,
     viz::RasterContextProvider* context_provider,
-    LayerTreeResourceProvider::ScopedWriteLockRaster* resource_lock,
     bool use_distance_field_text,
     int msaa_sample_count) {
   gpu::raster::RasterInterface* ri = context_provider->RasterInterface();
-  GLuint texture_id = resource_lock->ConsumeTexture(ri);
+  GLuint texture_id = ri->CreateAndConsumeTextureCHROMIUM(mailbox.name);
+  if (!texture_storage_allocated) {
+    viz::TextureAllocation alloc = {texture_id, texture_target,
+                                    texture_is_overlay_candidate};
+    viz::TextureAllocation::AllocateStorage(
+        ri, context_provider->ContextCapabilities(), resource_format,
+        resource_size, alloc, color_space);
+  }
 
-  ri->BeginRasterCHROMIUM(texture_id, raster_source->background_color(),
-                          msaa_sample_count, playback_settings.use_lcd_text,
-                          use_distance_field_text, resource_lock->ColorType(),
-                          playback_settings.raster_color_space);
+  // TODO(enne): Use the |texture_target|? GpuMemoryBuffer backed textures don't
+  // use GL_TEXTURE_2D.
+  ri->BeginRasterCHROMIUM(
+      texture_id, raster_source->background_color(), msaa_sample_count,
+      playback_settings.use_lcd_text, use_distance_field_text,
+      viz::ResourceFormatToClosestSkColorType(resource_format),
+      playback_settings.raster_color_space);
   float recording_to_raster_scale =
       transform.scale() / raster_source->recording_scale_factor();
   gfx::Size content_size = raster_source->GetContentSize(transform.scale());
@@ -92,23 +112,36 @@
 static void RasterizeSource(
     const RasterSource* raster_source,
     bool resource_has_previous_content,
+    const gpu::Mailbox& mailbox,
+    GLenum texture_target,
+    bool texture_is_overlay_candidate,
+    bool texture_storage_allocated,
+    const gfx::Size& resource_size,
+    viz::ResourceFormat resource_format,
+    const gfx::ColorSpace& color_space,
     const gfx::Rect& raster_full_rect,
     const gfx::Rect& playback_rect,
     const gfx::AxisTransform2d& transform,
     const RasterSource::PlaybackSettings& playback_settings,
     viz::RasterContextProvider* context_provider,
-    LayerTreeResourceProvider::ScopedWriteLockRaster* resource_lock,
     bool use_distance_field_text,
     int msaa_sample_count) {
   ScopedGrContextAccess gr_context_access(context_provider);
 
   gpu::raster::RasterInterface* ri = context_provider->RasterInterface();
-  GLuint texture_id = resource_lock->ConsumeTexture(ri);
+  GLuint texture_id = ri->CreateAndConsumeTextureCHROMIUM(mailbox.name);
+  if (!texture_storage_allocated) {
+    viz::TextureAllocation alloc = {texture_id, texture_target,
+                                    texture_is_overlay_candidate};
+    viz::TextureAllocation::AllocateStorage(
+        ri, context_provider->ContextCapabilities(), resource_format,
+        resource_size, alloc, color_space);
+  }
 
   {
     LayerTreeResourceProvider::ScopedSkSurface scoped_surface(
-        context_provider->GrContext(), texture_id, resource_lock->target(),
-        resource_lock->size(), resource_lock->format(), use_distance_field_text,
+        context_provider->GrContext(), texture_id, texture_target,
+        resource_size, resource_format, use_distance_field_text,
         playback_settings.use_lcd_text, msaa_sample_count);
 
     SkSurface* surface = scoped_surface.surface();
@@ -127,9 +160,9 @@
       canvas->discard();
 
     gfx::Size content_size = raster_source->GetContentSize(transform.scale());
-    raster_source->PlaybackToCanvas(
-        canvas, resource_lock->color_space_for_raster(), content_size,
-        raster_full_rect, playback_rect, transform, playback_settings);
+    raster_source->PlaybackToCanvas(canvas, color_space, content_size,
+                                    raster_full_rect, playback_rect, transform,
+                                    playback_settings);
   }
 
   ri->DeleteTextures(1, &texture_id);
@@ -137,20 +170,69 @@
 
 }  // namespace
 
+// Subclass for InUsePoolResource that holds ownership of a gpu-rastered backing
+// and does cleanup of the backing when destroyed.
+class GpuRasterBufferProvider::GpuRasterBacking
+    : public ResourcePool::GpuBacking {
+ public:
+  ~GpuRasterBacking() override {
+    gpu::gles2::GLES2Interface* gl = compositor_context_provider->ContextGL();
+    if (returned_sync_token.HasData())
+      gl->WaitSyncTokenCHROMIUM(returned_sync_token.GetConstData());
+    if (mailbox_sync_token.HasData())
+      gl->WaitSyncTokenCHROMIUM(mailbox_sync_token.GetConstData());
+    if (texture_id)
+      gl->DeleteTextures(1, &texture_id);
+  }
+
+  base::trace_event::MemoryAllocatorDumpGuid MemoryDumpGuid(
+      uint64_t tracing_process_id) override {
+    return gl::GetGLTextureClientGUIDForTracing(
+        compositor_context_provider->ContextSupport()->ShareGroupTracingGUID(),
+        texture_id);
+  }
+  base::UnguessableToken SharedMemoryGuid() override { return {}; }
+
+  // The ContextProvider used to clean up the texture id.
+  viz::ContextProvider* compositor_context_provider = nullptr;
+  // The texture backing of the resource.
+  GLuint texture_id = 0;
+  // The allocation of storage for the |texture_id| is deferred, and this tracks
+  // if it has been done.
+  bool storage_allocated = false;
+};
+
 GpuRasterBufferProvider::RasterBufferImpl::RasterBufferImpl(
     GpuRasterBufferProvider* client,
-    LayerTreeResourceProvider* resource_provider,
-    viz::ResourceId resource_id,
+    const ResourcePool::InUsePoolResource& in_use_resource,
+    GpuRasterBacking* backing,
     bool resource_has_previous_content)
     : client_(client),
-      lock_(resource_provider, resource_id),
-      resource_has_previous_content_(resource_has_previous_content) {
+      backing_(backing),
+      resource_size_(in_use_resource.size()),
+      resource_format_(in_use_resource.format()),
+      color_space_(in_use_resource.color_space()),
+      resource_has_previous_content_(resource_has_previous_content),
+      returned_sync_token_(backing->returned_sync_token),
+      mailbox_(backing->mailbox),
+      texture_target_(backing->texture_target),
+      texture_is_overlay_candidate_(backing->overlay_candidate),
+      texture_storage_allocated_(backing->storage_allocated) {
   client_->pending_raster_buffers_.insert(this);
-  lock_.CreateMailbox();
 }
 
 GpuRasterBufferProvider::RasterBufferImpl::~RasterBufferImpl() {
   client_->pending_raster_buffers_.erase(this);
+
+  // This SyncToken was created on the worker context after rastering the
+  // texture content.
+  backing_->mailbox_sync_token = after_raster_sync_token_;
+  if (after_raster_sync_token_.HasData()) {
+    // The returned SyncToken was waited on in Playback. We know Playback
+    // happened if the |after_raster_sync_token_| was set.
+    backing_->returned_sync_token = gpu::SyncToken();
+  }
+  backing_->storage_allocated = texture_storage_allocated_;
 }
 
 void GpuRasterBufferProvider::RasterBufferImpl::Playback(
@@ -161,10 +243,23 @@
     const gfx::AxisTransform2d& transform,
     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, transform, playback_settings);
+  // Either a SyncToken had to be made in OrderingBarrier, because a texture
+  // was made in AcquireBufferForRaster, or a texture already existed and we're
+  // reusing it. In that case a SyncToken was on the GpuBacking that we must
+  // wait on befor using the texture.
+  if (returned_sync_token_.HasData())
+    before_raster_sync_token_ = returned_sync_token_;
+  // The |sync_token_| passed in here was created on the compositor thread, or
+  // given back with the texture for reuse. This call returns another SyncToken
+  // generated on the worker thread to synchronize with after the raster is
+  // complete.
+  after_raster_sync_token_ = client_->PlaybackOnWorkerThread(
+      mailbox_, texture_target_, texture_is_overlay_candidate_,
+      texture_storage_allocated_, before_raster_sync_token_, resource_size_,
+      resource_format_, color_space_, resource_has_previous_content_,
+      raster_source, raster_full_rect, raster_dirty_rect, new_content_id,
+      transform, playback_settings);
+  texture_storage_allocated_ = true;
 }
 
 GpuRasterBufferProvider::GpuRasterBufferProvider(
@@ -172,6 +267,7 @@
     viz::RasterContextProvider* worker_context_provider,
     LayerTreeResourceProvider* resource_provider,
     bool use_distance_field_text,
+    bool use_gpu_memory_buffer_resources,
     int gpu_rasterization_msaa_sample_count,
     viz::ResourceFormat preferred_tile_format,
     bool enable_oop_rasterization)
@@ -179,6 +275,7 @@
       worker_context_provider_(worker_context_provider),
       resource_provider_(resource_provider),
       use_distance_field_text_(use_distance_field_text),
+      use_gpu_memory_buffer_resources_(use_gpu_memory_buffer_resources),
       msaa_sample_count_(gpu_rasterization_msaa_sample_count),
       preferred_tile_format_(preferred_tile_format),
       enable_oop_rasterization_(enable_oop_rasterization) {
@@ -194,10 +291,34 @@
     const ResourcePool::InUsePoolResource& resource,
     uint64_t resource_content_id,
     uint64_t previous_content_id) {
+  if (!resource.gpu_backing()) {
+    auto backing = std::make_unique<GpuRasterBacking>();
+    backing->compositor_context_provider = compositor_context_provider_;
+
+    gpu::gles2::GLES2Interface* gl = compositor_context_provider_->ContextGL();
+    const auto& caps = compositor_context_provider_->ContextCapabilities();
+
+    viz::TextureAllocation alloc = viz::TextureAllocation::MakeTextureId(
+        gl, caps, resource.format(), use_gpu_memory_buffer_resources_,
+        /*for_framebuffer_attachment=*/true);
+    backing->texture_id = alloc.texture_id;
+    backing->texture_target = alloc.texture_target;
+    backing->overlay_candidate = alloc.overlay_candidate;
+    backing->mailbox = gpu::Mailbox::Generate();
+    // The SyncToken in order to use this mailbox on another context will be
+    // generated later by OrderingBarrier(), once for all mailboxes made at a
+    // given time.
+    gl->ProduceTextureDirectCHROMIUM(backing->texture_id,
+                                     backing->mailbox.name);
+
+    resource.set_gpu_backing(std::move(backing));
+  }
+  GpuRasterBacking* backing =
+      static_cast<GpuRasterBacking*>(resource.gpu_backing());
+
   bool resource_has_previous_content =
       resource_content_id && resource_content_id == previous_content_id;
-  return std::make_unique<RasterBufferImpl>(this, resource_provider_,
-                                            resource.gpu_backing_resource_id(),
+  return std::make_unique<RasterBufferImpl>(this, resource, backing,
                                             resource_has_previous_content);
 }
 
@@ -243,10 +364,10 @@
 
 bool GpuRasterBufferProvider::IsResourceReadyToDraw(
     const ResourcePool::InUsePoolResource& resource) const {
-  gpu::SyncToken sync_token = resource_provider_->GetSyncTokenForResources(
-      {resource.gpu_backing_resource_id()});
-  if (!sync_token.HasData())
-    return true;
+  const gpu::SyncToken& sync_token = resource.gpu_backing()->mailbox_sync_token;
+  // This SyncToken() should have been set by calling OrderingBarrier() before
+  // calling this.
+  DCHECK(sync_token.HasData());
 
   // IsSyncTokenSignaled is thread-safe, no need for worker context lock.
   return worker_context_provider_->ContextSupport()->IsSyncTokenSignaled(
@@ -257,23 +378,24 @@
     const std::vector<const ResourcePool::InUsePoolResource*>& resources,
     const base::Closure& callback,
     uint64_t pending_callback_id) const {
-  std::vector<viz::ResourceId> resource_ids;
-  resource_ids.reserve(resources.size());
-  for (auto* resource : resources)
-    resource_ids.push_back(resource->gpu_backing_resource_id());
-  gpu::SyncToken sync_token =
-      resource_provider_->GetSyncTokenForResources(resource_ids);
-  uint64_t callback_id = sync_token.release_count();
+  gpu::SyncToken latest_sync_token;
+  for (const auto* in_use : resources) {
+    const gpu::SyncToken& sync_token =
+        in_use->gpu_backing()->mailbox_sync_token;
+    if (sync_token.release_count() > latest_sync_token.release_count())
+      latest_sync_token = sync_token;
+  }
+  uint64_t callback_id = latest_sync_token.release_count();
   DCHECK_NE(callback_id, 0u);
 
   // If the callback is different from the one the caller is already waiting on,
   // pass the callback through to SignalSyncToken. Otherwise the request is
   // redundant.
   if (callback_id != pending_callback_id) {
-    // Use the compositor context because we want this callback on the impl
-    // thread.
-    compositor_context_provider_->ContextSupport()->SignalSyncToken(sync_token,
-                                                                    callback);
+    // Use the compositor context because we want this callback on the
+    // compositor thread.
+    compositor_context_provider_->ContextSupport()->SignalSyncToken(
+        latest_sync_token, callback);
   }
 
   return callback_id;
@@ -283,9 +405,15 @@
   pending_raster_buffers_.clear();
 }
 
-void GpuRasterBufferProvider::PlaybackOnWorkerThread(
-    LayerTreeResourceProvider::ScopedWriteLockRaster* resource_lock,
+gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThread(
+    const gpu::Mailbox& mailbox,
+    GLenum texture_target,
+    bool texture_is_overlay_candidate,
+    bool texture_storage_allocated,
     const gpu::SyncToken& sync_token,
+    const gfx::Size& resource_size,
+    viz::ResourceFormat resource_format,
+    const gfx::ColorSpace& color_space,
     bool resource_has_previous_content,
     const RasterSource* raster_source,
     const gfx::Rect& raster_full_rect,
@@ -298,7 +426,9 @@
   gpu::raster::RasterInterface* ri = scoped_context.RasterInterface();
   DCHECK(ri);
 
-  // Synchronize with compositor. Nop if sync token is empty.
+  // Wait on the SyncToken that was created on the compositor thread after
+  // making the mailbox. This ensures that the mailbox we consume here is valid
+  // by the time the consume command executes.
   ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
 
   gfx::Rect playback_rect = raster_full_rect;
@@ -324,19 +454,22 @@
 
   if (enable_oop_rasterization_) {
     RasterizeSourceOOP(
-        raster_source, resource_has_previous_content, raster_full_rect,
-        playback_rect, transform, playback_settings, worker_context_provider_,
-        resource_lock, use_distance_field_text_, msaa_sample_count_);
+        raster_source, resource_has_previous_content, mailbox, texture_target,
+        texture_is_overlay_candidate, texture_storage_allocated, resource_size,
+        resource_format, color_space, raster_full_rect, playback_rect,
+        transform, playback_settings, worker_context_provider_,
+        use_distance_field_text_, msaa_sample_count_);
   } else {
-    RasterizeSource(raster_source, resource_has_previous_content,
-                    raster_full_rect, playback_rect, transform,
-                    playback_settings, worker_context_provider_, resource_lock,
+    RasterizeSource(raster_source, resource_has_previous_content, mailbox,
+                    texture_target, texture_is_overlay_candidate,
+                    texture_storage_allocated, resource_size, resource_format,
+                    color_space, raster_full_rect, playback_rect, transform,
+                    playback_settings, worker_context_provider_,
                     use_distance_field_text_, msaa_sample_count_);
   }
 
   // Generate sync token for cross context synchronization.
-  resource_lock->set_sync_token(
-      LayerTreeResourceProvider::GenerateSyncTokenHelper(ri));
+  return LayerTreeResourceProvider::GenerateSyncTokenHelper(ri);
 }
 
 }  // namespace cc