[go: nahoru, domu]

Add out of process gpu raster behind a flag

This patch adds a new --enable-oop-rasterization command line flag.
When enabled, it turns on a chromium_raster_transport gl extension and
makes all renderers that would have gone through the gpu raster path
instead do gpu raster in the gpu process by serializing/deserializing
recordings and rastering them there.

This is not ready to be turned on for both security and functionality
purposes by any means.  Without this flag, the command buffer ignores
these new raster commands, so this should be safe to land behind a flag.

As an initial approach, the raster is driven identically to gpu raster
in the renderer.  There's one raster thread.  The renderer decides
what to raster, adds decoding jobs, and then for one particular tile,
all the recorded paint commands for that tile are serialized and then
executed in the gpu process gles2 command decoder.

TBR=thakis@chromium.org

Bug: 757605
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I4d01d266bf5a7236d79a4e003c5fa8921e7826f8
Reviewed-on: https://chromium-review.googlesource.com/514505
Commit-Queue: enne <enne@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
Reviewed-by: Vladimir Levin <vmpstr@chromium.org>
Reviewed-by: Antoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#497934}
diff --git a/cc/raster/gpu_raster_buffer_provider.cc b/cc/raster/gpu_raster_buffer_provider.cc
index 0baf361..b239230 100644
--- a/cc/raster/gpu_raster_buffer_provider.cc
+++ b/cc/raster/gpu_raster_buffer_provider.cc
@@ -13,7 +13,9 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/base/histograms.h"
+#include "cc/paint/display_item_list.h"
 #include "cc/paint/paint_canvas.h"
+#include "cc/paint/paint_recorder.h"
 #include "cc/raster/raster_source.h"
 #include "cc/raster/scoped_gpu_raster.h"
 #include "cc/resources/resource.h"
@@ -23,16 +25,76 @@
 #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"
 
 namespace cc {
 namespace {
 
+// Reuse canvas setup code from RasterSource by storing it into a PaintRecord
+// that can then be transported.  This is somewhat more convoluted then it
+// should be.
+static sk_sp<PaintRecord> SetupForRaster(
+    const RasterSource* raster_source,
+    const gfx::Rect& raster_full_rect,
+    const gfx::Rect& playback_rect,
+    const gfx::AxisTransform2d& transform) {
+  PaintRecorder recorder;
+  PaintCanvas* canvas =
+      recorder.beginRecording(gfx::RectToSkRect(raster_full_rect));
+  // TODO(enne): The GLES2Decoder is guaranteeing the clear here, but it
+  // might be nice to figure out how to include the debugging clears for
+  // this mode.
+  canvas->translate(-raster_full_rect.x(), -raster_full_rect.y());
+  canvas->clipRect(SkRect::MakeFromIRect(gfx::RectToSkIRect(playback_rect)));
+  canvas->translate(transform.translation().x(), transform.translation().y());
+  canvas->scale(transform.scale(), transform.scale());
+  return recorder.finishRecordingAsPicture();
+}
+
+static void RasterizeSourceOOP(
+    const RasterSource* raster_source,
+    bool resource_has_previous_content,
+    const gfx::Size& resource_size,
+    const gfx::Rect& raster_full_rect,
+    const gfx::Rect& playback_rect,
+    const gfx::AxisTransform2d& transform,
+    const RasterSource::PlaybackSettings& playback_settings,
+    viz::ContextProvider* context_provider,
+    ResourceProvider::ScopedWriteLockGL* resource_lock,
+    bool use_distance_field_text,
+    int msaa_sample_count) {
+  gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
+  GLuint texture_id = resource_lock->ConsumeTexture(gl);
+
+  auto setup_list = make_scoped_refptr(
+      new DisplayItemList(DisplayItemList::kTopLevelDisplayItemList));
+  setup_list->StartPaint();
+  setup_list->push<DrawRecordOp>(SetupForRaster(raster_source, raster_full_rect,
+                                                playback_rect, transform));
+  setup_list->EndPaintOfUnpaired(raster_full_rect);
+  setup_list->Finalize();
+
+  // TODO(enne): need to pass color space and transform in the decoder.
+  gl->BeginRasterCHROMIUM(texture_id, raster_source->background_color(),
+                          msaa_sample_count, playback_settings.use_lcd_text,
+                          use_distance_field_text,
+                          resource_lock->PixelConfig());
+  gl->RasterCHROMIUM(setup_list.get(), playback_rect.x(), playback_rect.y(),
+                     playback_rect.width(), playback_rect.height());
+  gl->RasterCHROMIUM(raster_source->display_list(), playback_rect.x(),
+                     playback_rect.y(), playback_rect.width(),
+                     playback_rect.height());
+  gl->EndRasterCHROMIUM();
+
+  gl->DeleteTextures(1, &texture_id);
+}
+
 static void RasterizeSource(
     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,
+    const gfx::Rect& playback_rect,
     const gfx::AxisTransform2d& transform,
     const RasterSource::PlaybackSettings& playback_settings,
     viz::ContextProvider* context_provider,
@@ -59,28 +121,6 @@
       return;
     }
 
-    // Playback
-    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?";
-
-    // Log a histogram of the percentage of pixels that were saved due to
-    // partial raster.
-    const char* client_name = GetClientNameForMetrics();
-    float full_rect_size = raster_full_rect.size().GetArea();
-    if (full_rect_size > 0 && client_name) {
-      float fraction_partial_rastered =
-          static_cast<float>(playback_rect.size().GetArea()) / full_rect_size;
-      float fraction_saved = 1.0f - fraction_partial_rastered;
-      UMA_HISTOGRAM_PERCENTAGE(
-          base::StringPrintf("Renderer4.%s.PartialRasterPercentageSaved.Gpu",
-                             client_name),
-          100.0f * fraction_saved);
-    }
-
     SkCanvas* canvas = surface->getCanvas();
 
     // As an optimization, inform Skia to discard when not doing partial raster.
@@ -134,14 +174,16 @@
     bool use_distance_field_text,
     int gpu_rasterization_msaa_sample_count,
     viz::ResourceFormat preferred_tile_format,
-    bool async_worker_context_enabled)
+    bool async_worker_context_enabled,
+    bool enable_oop_rasterization)
     : compositor_context_provider_(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),
       preferred_tile_format_(preferred_tile_format),
-      async_worker_context_enabled_(async_worker_context_enabled) {
+      async_worker_context_enabled_(async_worker_context_enabled),
+      enable_oop_rasterization_(enable_oop_rasterization) {
   DCHECK(compositor_context_provider);
   DCHECK(worker_context_provider);
 }
@@ -271,10 +313,40 @@
   // Synchronize with compositor. Nop if sync token is empty.
   gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
 
-  RasterizeSource(raster_source, resource_has_previous_content,
-                  resource_lock->size(), raster_full_rect, raster_dirty_rect,
-                  transform, playback_settings, worker_context_provider_,
-                  resource_lock, use_distance_field_text_, msaa_sample_count_);
+  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?";
+
+  // Log a histogram of the percentage of pixels that were saved due to
+  // partial raster.
+  const char* client_name = GetClientNameForMetrics();
+  float full_rect_size = raster_full_rect.size().GetArea();
+  if (full_rect_size > 0 && client_name) {
+    float fraction_partial_rastered =
+        static_cast<float>(playback_rect.size().GetArea()) / full_rect_size;
+    float fraction_saved = 1.0f - fraction_partial_rastered;
+    UMA_HISTOGRAM_PERCENTAGE(
+        base::StringPrintf("Renderer4.%s.PartialRasterPercentageSaved.Gpu",
+                           client_name),
+        100.0f * fraction_saved);
+  }
+
+  if (enable_oop_rasterization_) {
+    RasterizeSourceOOP(raster_source, resource_has_previous_content,
+                       resource_lock->size(), raster_full_rect, playback_rect,
+                       transform, playback_settings, worker_context_provider_,
+                       resource_lock, use_distance_field_text_,
+                       msaa_sample_count_);
+  } else {
+    RasterizeSource(raster_source, resource_has_previous_content,
+                    resource_lock->size(), raster_full_rect, playback_rect,
+                    transform, playback_settings, worker_context_provider_,
+                    resource_lock, use_distance_field_text_,
+                    msaa_sample_count_);
+  }
 
   // Generate sync token for cross context synchronization.
   resource_lock->set_sync_token(ResourceProvider::GenerateSyncTokenHelper(gl));