[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/paint/display_item_list.h b/cc/paint/display_item_list.h
index 8e0420d..3f96dc4 100644
--- a/cc/paint/display_item_list.h
+++ b/cc/paint/display_item_list.h
@@ -26,6 +26,12 @@
 
 class SkCanvas;
 
+namespace gpu {
+namespace gles2 {
+class GLES2Implementation;
+}  // namespace gles2
+}  // namespace gpu
+
 namespace base {
 namespace trace_event {
 class TracedValue;
@@ -168,6 +174,7 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithNoOps);
   FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithOps);
+  friend gpu::gles2::GLES2Implementation;
 
   ~DisplayItemList();
 
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index 1b1c681..6bd74ba 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -280,8 +280,19 @@
 
   // We don't write the cached shader, so don't attempt to read it either.
 
-  if (!(*shader)->IsValid())
+  // TODO(vmpstr): add serialization of these shader types.  For the moment
+  // pretend that these shaders don't exist and that the serialization is
+  // successful.  Valid ops pre-serialization should not cause deserialization
+  // failures.
+  if (shader_type == PaintShader::Type::kPaintRecord ||
+      shader_type == PaintShader::Type::kImage) {
+    *shader = nullptr;
+    return;
+  }
+
+  if (!(*shader)->IsValid()) {
     valid_ = false;
+  }
 }
 
 bool PaintOpReader::AlignMemory(size_t alignment) {
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));
diff --git a/cc/raster/gpu_raster_buffer_provider.h b/cc/raster/gpu_raster_buffer_provider.h
index aa275da..9f08fd6 100644
--- a/cc/raster/gpu_raster_buffer_provider.h
+++ b/cc/raster/gpu_raster_buffer_provider.h
@@ -26,7 +26,8 @@
                           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);
   ~GpuRasterBufferProvider() override;
 
   // Overridden from RasterBufferProvider:
@@ -97,6 +98,7 @@
   const int msaa_sample_count_;
   const viz::ResourceFormat preferred_tile_format_;
   const bool async_worker_context_enabled_;
+  const bool enable_oop_rasterization_;
 
   std::set<RasterBufferImpl*> pending_raster_buffers_;
 
diff --git a/cc/raster/raster_buffer_provider_perftest.cc b/cc/raster/raster_buffer_provider_perftest.cc
index 0f036e3..2e1d247 100644
--- a/cc/raster/raster_buffer_provider_perftest.cc
+++ b/cc/raster/raster_buffer_provider_perftest.cc
@@ -342,7 +342,7 @@
         raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>(
             compositor_context_provider_.get(), worker_context_provider_.get(),
             resource_provider_.get(), false, 0,
-            viz::PlatformColor::BestTextureFormat(), false);
+            viz::PlatformColor::BestTextureFormat(), false, false);
         break;
       case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
         CreateSoftwareResourceProvider();
diff --git a/cc/raster/raster_buffer_provider_unittest.cc b/cc/raster/raster_buffer_provider_unittest.cc
index 2890ec3..194a1a8 100644
--- a/cc/raster/raster_buffer_provider_unittest.cc
+++ b/cc/raster/raster_buffer_provider_unittest.cc
@@ -182,14 +182,14 @@
         raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>(
             context_provider_.get(), worker_context_provider_.get(),
             resource_provider_.get(), false, 0,
-            viz::PlatformColor::BestTextureFormat(), false);
+            viz::PlatformColor::BestTextureFormat(), false, false);
         break;
       case RASTER_BUFFER_PROVIDER_TYPE_ASYNC_GPU:
         Create3dResourceProvider();
         raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>(
             context_provider_.get(), worker_context_provider_.get(),
             resource_provider_.get(), false, 0,
-            viz::PlatformColor::BestTextureFormat(), true);
+            viz::PlatformColor::BestTextureFormat(), true, false);
         break;
       case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
         CreateSoftwareResourceProvider();
diff --git a/cc/raster/raster_source.h b/cc/raster/raster_source.h
index ee6861bd..8ee4920 100644
--- a/cc/raster/raster_source.h
+++ b/cc/raster/raster_source.h
@@ -113,6 +113,10 @@
   virtual sk_sp<SkPicture> GetFlattenedPicture();
   virtual size_t GetMemoryUsage() const;
 
+  const DisplayItemList* display_list() const { return display_list_.get(); }
+
+  SkColor background_color() const { return background_color_; }
+
  protected:
   // RecordingSource is the only class that can create a raster source.
   friend class RecordingSource;
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 7719a37..b0580ed 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -1070,6 +1070,10 @@
   allocated_ = resource->allocated;
 }
 
+GrPixelConfig ResourceProvider::ScopedWriteLockGL::PixelConfig() const {
+  return ToGrPixelConfig(format());
+}
+
 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
   Resource* resource = resource_provider_->GetResource(resource_id_);
   DCHECK(resource->locked_for_write);
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index a1ef96b..733bac0d 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -256,6 +256,8 @@
       has_sync_token_ = true;
     }
 
+    GrPixelConfig PixelConfig() const;
+
     void set_synchronized() { synchronized_ = true; }
 
     // Returns texture id on compositor context, allocating if necessary.
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index f42b857..930c874 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -157,7 +157,7 @@
       *raster_buffer_provider = std::make_unique<GpuRasterBufferProvider>(
           compositor_context_provider, worker_context_provider,
           resource_provider, false, 0, viz::PlatformColor::BestTextureFormat(),
-          false);
+          false, false);
       break;
     case RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY:
       EXPECT_TRUE(compositor_context_provider);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 931b123..9cb0d9f 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2393,7 +2393,8 @@
         compositor_context_provider, worker_context_provider,
         resource_provider_.get(), settings_.use_distance_field_text,
         msaa_sample_count, settings_.preferred_tile_format,
-        settings_.async_worker_context_enabled);
+        settings_.async_worker_context_enabled,
+        settings_.enable_oop_rasterization);
     return;
   }
 
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 3c394d0..0749320 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -143,6 +143,10 @@
   // which LayerTreeHost synchronizes. If |true| LayerTreeHostImpl
   // produces the active tree as its 'sync tree'.
   bool commit_to_active_tree = true;
+
+  // Whether to use out of process raster.  If true, whenever gpu raster
+  // would have been used, out of process gpu raster will be used instead.
+  bool enable_oop_rasterization = false;
 };
 
 }  // namespace cc
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 99cad43..761a240 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -114,6 +114,7 @@
     ::switches::kEnableLogging,
     ::switches::kEnableLowResTiling,
     ::switches::kEnableNativeGpuMemoryBuffers,
+    ::switches::kEnableOOPRasterization,
     ::switches::kDisablePartialRaster,
     ::switches::kEnablePartialRaster,
     ::switches::kEnablePinch,
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index b3a74d8..5d376045 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -132,6 +132,7 @@
     switches::kEnableGpuRasterization,
     switches::kEnableHeapProfiling,
     switches::kEnableLogging,
+    switches::kEnableOOPRasterization,
 #if defined(OS_CHROMEOS)
     switches::kDisableVaapiAcceleratedVideoEncode,
 #endif
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 66e8ed5..616a031a 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2547,6 +2547,7 @@
     switches::kEnableLCDText,
     switches::kEnableLogging,
     switches::kEnableNetworkInformationDownlinkMax,
+    switches::kEnableOOPRasterization,
     switches::kEnablePinch,
     switches::kEnablePluginPlaceholderTesting,
     switches::kEnablePreciseMemoryInfo,
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 3b8bfab..388344d 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -429,6 +429,8 @@
       base::FeatureList::IsEnabled(features::kColorCorrectRendering);
   settings.resource_settings.buffer_to_texture_target_map =
       compositor_deps->GetBufferToTextureTargetMap();
+  settings.enable_oop_rasterization =
+      cmd.HasSwitch(switches::kEnableOOPRasterization);
 
   // Build LayerTreeSettings from command line args.
   LayerTreeSettingsFactory::SetBrowserControlsSettings(settings, cmd);
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index b3c683e..3034a337d 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -138,6 +138,7 @@
 #include "gin/public/debug.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/shared_memory_limits.h"
+#include "gpu/config/gpu_switches.h"
 #include "gpu/ipc/client/command_buffer_proxy_impl.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "ipc/ipc_channel_handle.h"
@@ -374,6 +375,7 @@
     scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
     const gpu::SharedMemoryLimits& limits,
     bool support_locking,
+    bool support_oop_rasterization,
     ui::command_buffer_metrics::ContextType type,
     int32_t stream_id,
     gpu::SchedulingPriority stream_priority) {
@@ -391,6 +393,8 @@
   attributes.sample_buffers = 0;
   attributes.bind_generates_resource = false;
   attributes.lose_context_when_out_of_memory = true;
+  attributes.enable_oop_rasterization = support_oop_rasterization;
+
   const bool automatic_flushes = false;
   return make_scoped_refptr(new ui::ContextProviderCommandBuffer(
       std::move(gpu_channel_host), stream_id, stream_priority,
@@ -1437,8 +1441,10 @@
   // use lower limits than the default.
   gpu::SharedMemoryLimits limits = gpu::SharedMemoryLimits::ForMailboxContext();
   bool support_locking = true;
+  bool support_oop_rasterization = false;
   scoped_refptr<ui::ContextProviderCommandBuffer> media_context_provider =
       CreateOffscreenContext(gpu_channel_host, limits, support_locking,
+                             support_oop_rasterization,
                              ui::command_buffer_metrics::MEDIA_CONTEXT,
                              kGpuStreamIdDefault, kGpuStreamPriorityDefault);
   if (!media_context_provider->BindToCurrentThread())
@@ -1490,8 +1496,10 @@
   }
 
   bool support_locking = false;
+  bool support_oop_rasterization = false;
   shared_main_thread_contexts_ = CreateOffscreenContext(
       std::move(gpu_channel_host), gpu::SharedMemoryLimits(), support_locking,
+      support_oop_rasterization,
       ui::command_buffer_metrics::RENDERER_MAINTHREAD_CONTEXT,
       kGpuStreamIdDefault, kGpuStreamPriorityDefault);
   if (!shared_main_thread_contexts_->BindToCurrentThread())
@@ -2410,8 +2418,12 @@
   }
 
   bool support_locking = true;
+  bool support_oop_rasterization =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableOOPRasterization);
   shared_worker_context_provider_ = CreateOffscreenContext(
       std::move(gpu_channel_host), gpu::SharedMemoryLimits(), support_locking,
+      support_oop_rasterization,
       ui::command_buffer_metrics::RENDER_WORKER_CONTEXT, stream_id,
       stream_priority);
   if (!shared_worker_context_provider_->BindToCurrentThread())
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index 3fcb446..a33d7ba1 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -399,5 +399,8 @@
   GLES2_GET_FUN(UnlockDiscardableTextureCHROMIUM)
 #define glLockDiscardableTextureCHROMIUM \
   GLES2_GET_FUN(LockDiscardableTextureCHROMIUM)
+#define glBeginRasterCHROMIUM GLES2_GET_FUN(BeginRasterCHROMIUM)
+#define glRasterCHROMIUM GLES2_GET_FUN(RasterCHROMIUM)
+#define glEndRasterCHROMIUM GLES2_GET_FUN(EndRasterCHROMIUM)
 
 #endif  // GPU_GLES2_GL2CHROMIUM_AUTOGEN_H_
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 384892e..b97139e3 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -4590,6 +4590,30 @@
     'client_test': False,
     'extension': True,
   },
+  'BeginRasterCHROMIUM': {
+    'decoder_func': 'DoBeginRasterCHROMIUM',
+    'impl_func': True,
+    'unit_test': False,
+    'extension': 'CHROMIUM_raster_transport',
+    'extension_flag': 'chromium_raster_transport',
+  },
+  'RasterCHROMIUM': {
+    'type': 'Custom',
+    'decoder_func': 'DoRasterCHROMIUM',
+    'impl_func': False,
+    'immediate': False,
+    'data_transfer_methods': ['shm'],
+    'needs_size': True,
+    'extension': 'CHROMIUM_raster_transport',
+    'extension_flag': 'chromium_raster_transport',
+  },
+  'EndRasterCHROMIUM': {
+    'decoder_func': 'DoEndRasterCHROMIUM',
+    'impl_func': True,
+    'unit_test': False,
+    'extension': 'CHROMIUM_raster_transport',
+    'extension_flag': 'chromium_raster_transport',
+  },
 }
 
 
diff --git a/gpu/command_buffer/client/BUILD.gn b/gpu/command_buffer/client/BUILD.gn
index 98e165d..45919991 100644
--- a/gpu/command_buffer/client/BUILD.gn
+++ b/gpu/command_buffer/client/BUILD.gn
@@ -15,6 +15,13 @@
       ":client_sources",
     ]
   }
+
+  if (!is_nacl) {
+    deps = [
+      "//cc/paint",
+      "//skia",
+    ]
+  }
 }
 
 group("gles2_cmd_helper") {
diff --git a/gpu/command_buffer/client/DEPS b/gpu/command_buffer/client/DEPS
index 867a547a..58bc085 100644
--- a/gpu/command_buffer/client/DEPS
+++ b/gpu/command_buffer/client/DEPS
@@ -1,3 +1,5 @@
 include_rules = [
   "+ui/latency",
+  "+cc/paint",
+  "+third_party/skia",
 ]
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index b4f08d75..f0d6e36 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1777,6 +1777,26 @@
 bool GL_APIENTRY GLES2LockDiscardableTextureCHROMIUM(GLuint texture_id) {
   return gles2::GetGLContext()->LockDiscardableTextureCHROMIUM(texture_id);
 }
+void GL_APIENTRY GLES2BeginRasterCHROMIUM(GLuint texture_id,
+                                          GLuint sk_color,
+                                          GLuint msaa_sample_count,
+                                          GLboolean can_use_lcd_text,
+                                          GLboolean use_distance_field_text,
+                                          GLint pixel_config) {
+  gles2::GetGLContext()->BeginRasterCHROMIUM(
+      texture_id, sk_color, msaa_sample_count, can_use_lcd_text,
+      use_distance_field_text, pixel_config);
+}
+void GL_APIENTRY GLES2RasterCHROMIUM(const cc::DisplayItemList* list,
+                                     GLint x,
+                                     GLint y,
+                                     GLint w,
+                                     GLint h) {
+  gles2::GetGLContext()->RasterCHROMIUM(list, x, y, w, h);
+}
+void GL_APIENTRY GLES2EndRasterCHROMIUM() {
+  gles2::GetGLContext()->EndRasterCHROMIUM();
+}
 
 namespace gles2 {
 
@@ -3122,6 +3142,18 @@
             glLockDiscardableTextureCHROMIUM),
     },
     {
+        "glBeginRasterCHROMIUM",
+        reinterpret_cast<GLES2FunctionPointer>(glBeginRasterCHROMIUM),
+    },
+    {
+        "glRasterCHROMIUM",
+        reinterpret_cast<GLES2FunctionPointer>(glRasterCHROMIUM),
+    },
+    {
+        "glEndRasterCHROMIUM",
+        reinterpret_cast<GLES2FunctionPointer>(glEndRasterCHROMIUM),
+    },
+    {
         NULL, NULL,
     },
 };
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index adf0baa..b4ee0e9e 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -3289,4 +3289,39 @@
   }
 }
 
+void BeginRasterCHROMIUM(GLuint texture_id,
+                         GLuint sk_color,
+                         GLuint msaa_sample_count,
+                         GLboolean can_use_lcd_text,
+                         GLboolean use_distance_field_text,
+                         GLint pixel_config) {
+  gles2::cmds::BeginRasterCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::BeginRasterCHROMIUM>();
+  if (c) {
+    c->Init(texture_id, sk_color, msaa_sample_count, can_use_lcd_text,
+            use_distance_field_text, pixel_config);
+  }
+}
+
+void RasterCHROMIUM(uint32_t list_shm_id,
+                    uint32_t list_shm_offset,
+                    GLint x,
+                    GLint y,
+                    GLint w,
+                    GLint h,
+                    uint32_t data_size) {
+  gles2::cmds::RasterCHROMIUM* c = GetCmdSpace<gles2::cmds::RasterCHROMIUM>();
+  if (c) {
+    c->Init(list_shm_id, list_shm_offset, x, y, w, h, data_size);
+  }
+}
+
+void EndRasterCHROMIUM() {
+  gles2::cmds::EndRasterCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::EndRasterCHROMIUM>();
+  if (c) {
+    c->Init();
+  }
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index c36dc63..9d63f5f 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -29,6 +29,7 @@
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
 #include "gpu/command_buffer/client/buffer_tracker.h"
 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
 #include "gpu/command_buffer/client/gpu_control.h"
@@ -48,6 +49,10 @@
 #include "gpu/command_buffer/client/gpu_switches.h"
 #endif
 
+#if !defined(OS_NACL)
+#include "cc/paint/display_item_list.h"  // nogncheck
+#endif
+
 #if !defined(__native_client__)
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/ipc/color/gfx_param_traits.h"
@@ -7131,6 +7136,73 @@
   CheckGLError();
 }
 
+void GLES2Implementation::RasterCHROMIUM(const cc::DisplayItemList* list,
+                                         GLint x,
+                                         GLint y,
+                                         GLint w,
+                                         GLint h) {
+#if defined(OS_NACL)
+  NOTREACHED();
+#else
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRasterChromium(" << list << ", "
+                     << x << ", " << y << ", " << w << ", " << h << ")");
+
+  // TODO(enne): tune these numbers
+  // TODO(enne): convert these types here and in transfer buffer to be size_t.
+  static constexpr unsigned int kMinAlloc = 16 * 1024;
+  static constexpr unsigned int kBlockAlloc = 512 * 1024;
+
+  unsigned int free_size = std::max(transfer_buffer_->GetFreeSize(), kMinAlloc);
+  ScopedTransferBufferPtr buffer(free_size, helper_, transfer_buffer_);
+  DCHECK(buffer.valid());
+
+  char* memory = static_cast<char*>(buffer.address());
+  size_t written_bytes = 0;
+  size_t free_bytes = buffer.size();
+
+  cc::PaintOp::SerializeOptions options;
+
+  // TODO(enne): need to implement alpha folding optimization from POB.
+  // TODO(enne): don't access private members of DisplayItemList.
+  gfx::Rect playback_rect(x, y, w, h);
+  std::vector<size_t> indices = list->rtree_.Search(playback_rect);
+  for (cc::PaintOpBuffer::FlatteningIterator iter(&list->paint_op_buffer_,
+                                                  &indices);
+       iter; ++iter) {
+    const cc::PaintOp* op = *iter;
+    size_t size = op->Serialize(memory + written_bytes, free_bytes, options);
+    if (!size) {
+      buffer.Shrink(written_bytes);
+      helper_->RasterCHROMIUM(buffer.shm_id(), buffer.offset(), x, y, w, h,
+                              written_bytes);
+      buffer.Reset(kBlockAlloc);
+      memory = static_cast<char*>(buffer.address());
+      written_bytes = 0;
+      free_bytes = buffer.size();
+
+      size = op->Serialize(memory + written_bytes, free_bytes, options);
+    }
+    DCHECK_GE(size, 4u);
+    DCHECK_EQ(size % cc::PaintOpBuffer::PaintOpAlign, 0u);
+    DCHECK_LE(size, free_bytes);
+    DCHECK_EQ(free_bytes + written_bytes, buffer.size());
+
+    written_bytes += size;
+    free_bytes -= size;
+  }
+
+  buffer.Shrink(written_bytes);
+
+  if (!written_bytes)
+    return;
+  helper_->RasterCHROMIUM(buffer.shm_id(), buffer.offset(), x, y, w, h,
+                          buffer.size());
+
+  CheckGLError();
+#endif
+}
+
 // Include the auto-generated part of this file. We split this because it means
 // we can easily edit the non-auto generated parts right here in this file
 // instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 220e26d..0540db6 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1244,4 +1244,19 @@
 
 bool LockDiscardableTextureCHROMIUM(GLuint texture_id) override;
 
+void BeginRasterCHROMIUM(GLuint texture_id,
+                         GLuint sk_color,
+                         GLuint msaa_sample_count,
+                         GLboolean can_use_lcd_text,
+                         GLboolean use_distance_field_text,
+                         GLint pixel_config) override;
+
+void RasterCHROMIUM(const cc::DisplayItemList* list,
+                    GLint x,
+                    GLint y,
+                    GLint w,
+                    GLint h) override;
+
+void EndRasterCHROMIUM() override;
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index 71a6edb0..e5655de7 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -3547,4 +3547,31 @@
   CheckGLError();
 }
 
+void GLES2Implementation::BeginRasterCHROMIUM(GLuint texture_id,
+                                              GLuint sk_color,
+                                              GLuint msaa_sample_count,
+                                              GLboolean can_use_lcd_text,
+                                              GLboolean use_distance_field_text,
+                                              GLint pixel_config) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBeginRasterCHROMIUM("
+                     << texture_id << ", " << sk_color << ", "
+                     << msaa_sample_count << ", "
+                     << GLES2Util::GetStringBool(can_use_lcd_text) << ", "
+                     << GLES2Util::GetStringBool(use_distance_field_text)
+                     << ", " << pixel_config << ")");
+  helper_->BeginRasterCHROMIUM(texture_id, sk_color, msaa_sample_count,
+                               can_use_lcd_text, use_distance_field_text,
+                               pixel_config);
+  CheckGLError();
+}
+
+void GLES2Implementation::EndRasterCHROMIUM() {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEndRasterCHROMIUM("
+                     << ")");
+  helper_->EndRasterCHROMIUM();
+  CheckGLError();
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index e157a11..95c61b3 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -3081,4 +3081,26 @@
   gl_->SetEnableDCLayersCHROMIUM(true);
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
+
+TEST_F(GLES2ImplementationTest, BeginRasterCHROMIUM) {
+  struct Cmds {
+    cmds::BeginRasterCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(1, 2, 3, true, true, 6);
+
+  gl_->BeginRasterCHROMIUM(1, 2, 3, true, true, 6);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, EndRasterCHROMIUM) {
+  struct Cmds {
+    cmds::EndRasterCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init();
+
+  gl_->EndRasterCHROMIUM();
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_UNITTEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface.h b/gpu/command_buffer/client/gles2_interface.h
index 2dd040a..030ecdf 100644
--- a/gpu/command_buffer/client/gles2_interface.h
+++ b/gpu/command_buffer/client/gles2_interface.h
@@ -9,6 +9,10 @@
 
 #include "base/compiler_specific.h"
 
+namespace cc {
+class DisplayItemList;
+}
+
 extern "C" typedef struct _ClientBuffer* ClientBuffer;
 extern "C" typedef struct _GLColorSpace* GLColorSpace;
 
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 6c2a551..2469875 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -922,4 +922,16 @@
 virtual void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) = 0;
 virtual void UnlockDiscardableTextureCHROMIUM(GLuint texture_id) = 0;
 virtual bool LockDiscardableTextureCHROMIUM(GLuint texture_id) = 0;
+virtual void BeginRasterCHROMIUM(GLuint texture_id,
+                                 GLuint sk_color,
+                                 GLuint msaa_sample_count,
+                                 GLboolean can_use_lcd_text,
+                                 GLboolean use_distance_field_text,
+                                 GLint pixel_config) = 0;
+virtual void RasterCHROMIUM(const cc::DisplayItemList* list,
+                            GLint x,
+                            GLint y,
+                            GLint w,
+                            GLint h) = 0;
+virtual void EndRasterCHROMIUM() = 0;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index dbe13d1..c810f9e3 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -895,4 +895,16 @@
 void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) override;
 void UnlockDiscardableTextureCHROMIUM(GLuint texture_id) override;
 bool LockDiscardableTextureCHROMIUM(GLuint texture_id) override;
+void BeginRasterCHROMIUM(GLuint texture_id,
+                         GLuint sk_color,
+                         GLuint msaa_sample_count,
+                         GLboolean can_use_lcd_text,
+                         GLboolean use_distance_field_text,
+                         GLint pixel_config) override;
+void RasterCHROMIUM(const cc::DisplayItemList* list,
+                    GLint x,
+                    GLint y,
+                    GLint w,
+                    GLint h) override;
+void EndRasterCHROMIUM() override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index abdbd078..ab4e8d0 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -1207,4 +1207,17 @@
     GLuint /* texture_id */) {
   return 0;
 }
+void GLES2InterfaceStub::BeginRasterCHROMIUM(
+    GLuint /* texture_id */,
+    GLuint /* sk_color */,
+    GLuint /* msaa_sample_count */,
+    GLboolean /* can_use_lcd_text */,
+    GLboolean /* use_distance_field_text */,
+    GLint /* pixel_config */) {}
+void GLES2InterfaceStub::RasterCHROMIUM(const cc::DisplayItemList* /* list */,
+                                        GLint /* x */,
+                                        GLint /* y */,
+                                        GLint /* w */,
+                                        GLint /* h */) {}
+void GLES2InterfaceStub::EndRasterCHROMIUM() {}
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index bdcc2ef..45300bf 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -895,4 +895,16 @@
 void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) override;
 void UnlockDiscardableTextureCHROMIUM(GLuint texture_id) override;
 bool LockDiscardableTextureCHROMIUM(GLuint texture_id) override;
+void BeginRasterCHROMIUM(GLuint texture_id,
+                         GLuint sk_color,
+                         GLuint msaa_sample_count,
+                         GLboolean can_use_lcd_text,
+                         GLboolean use_distance_field_text,
+                         GLint pixel_config) override;
+void RasterCHROMIUM(const cc::DisplayItemList* list,
+                    GLint x,
+                    GLint y,
+                    GLint w,
+                    GLint h) override;
+void EndRasterCHROMIUM() override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index b0cf7a8b..83bff0b5 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -2584,4 +2584,31 @@
   return gl_->LockDiscardableTextureCHROMIUM(texture_id);
 }
 
+void GLES2TraceImplementation::BeginRasterCHROMIUM(
+    GLuint texture_id,
+    GLuint sk_color,
+    GLuint msaa_sample_count,
+    GLboolean can_use_lcd_text,
+    GLboolean use_distance_field_text,
+    GLint pixel_config) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BeginRasterCHROMIUM");
+  gl_->BeginRasterCHROMIUM(texture_id, sk_color, msaa_sample_count,
+                           can_use_lcd_text, use_distance_field_text,
+                           pixel_config);
+}
+
+void GLES2TraceImplementation::RasterCHROMIUM(const cc::DisplayItemList* list,
+                                              GLint x,
+                                              GLint y,
+                                              GLint w,
+                                              GLint h) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::RasterCHROMIUM");
+  gl_->RasterCHROMIUM(list, x, y, w, h);
+}
+
+void GLES2TraceImplementation::EndRasterCHROMIUM() {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::EndRasterCHROMIUM");
+  gl_->EndRasterCHROMIUM();
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 6b32f39..d8f976f 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -379,3 +379,7 @@
 GL_APICALL void         GL_APIENTRY glUnlockDiscardableTextureCHROMIUM (GLuint texture_id);
 GL_APICALL bool         GL_APIENTRY glLockDiscardableTextureCHROMIUM (GLuint texture_id);
 
+// Extension CHROMIUM_raster_transport
+GL_APICALL void         GL_APIENTRY glBeginRasterCHROMIUM (GLuint texture_id, GLuint sk_color, GLuint msaa_sample_count, GLboolean can_use_lcd_text, GLboolean use_distance_field_text, GLint pixel_config);
+GL_APICALL void         GL_APIENTRY glRasterCHROMIUM (const cc::DisplayItemList* list, GLint x, GLint y, GLint w, GLint h);
+GL_APICALL void         GL_APIENTRY glEndRasterCHROMIUM (void);
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index 8ea10c5..22636d1b 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -16138,4 +16138,169 @@
     offsetof(LockDiscardableTextureCHROMIUM, texture_id) == 4,
     "offset of LockDiscardableTextureCHROMIUM texture_id should be 4");
 
+struct BeginRasterCHROMIUM {
+  typedef BeginRasterCHROMIUM ValueType;
+  static const CommandId kCmdId = kBeginRasterCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _texture_id,
+            GLuint _sk_color,
+            GLuint _msaa_sample_count,
+            GLboolean _can_use_lcd_text,
+            GLboolean _use_distance_field_text,
+            GLint _pixel_config) {
+    SetHeader();
+    texture_id = _texture_id;
+    sk_color = _sk_color;
+    msaa_sample_count = _msaa_sample_count;
+    can_use_lcd_text = _can_use_lcd_text;
+    use_distance_field_text = _use_distance_field_text;
+    pixel_config = _pixel_config;
+  }
+
+  void* Set(void* cmd,
+            GLuint _texture_id,
+            GLuint _sk_color,
+            GLuint _msaa_sample_count,
+            GLboolean _can_use_lcd_text,
+            GLboolean _use_distance_field_text,
+            GLint _pixel_config) {
+    static_cast<ValueType*>(cmd)->Init(_texture_id, _sk_color,
+                                       _msaa_sample_count, _can_use_lcd_text,
+                                       _use_distance_field_text, _pixel_config);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t texture_id;
+  uint32_t sk_color;
+  uint32_t msaa_sample_count;
+  uint32_t can_use_lcd_text;
+  uint32_t use_distance_field_text;
+  int32_t pixel_config;
+};
+
+static_assert(sizeof(BeginRasterCHROMIUM) == 28,
+              "size of BeginRasterCHROMIUM should be 28");
+static_assert(offsetof(BeginRasterCHROMIUM, header) == 0,
+              "offset of BeginRasterCHROMIUM header should be 0");
+static_assert(offsetof(BeginRasterCHROMIUM, texture_id) == 4,
+              "offset of BeginRasterCHROMIUM texture_id should be 4");
+static_assert(offsetof(BeginRasterCHROMIUM, sk_color) == 8,
+              "offset of BeginRasterCHROMIUM sk_color should be 8");
+static_assert(offsetof(BeginRasterCHROMIUM, msaa_sample_count) == 12,
+              "offset of BeginRasterCHROMIUM msaa_sample_count should be 12");
+static_assert(offsetof(BeginRasterCHROMIUM, can_use_lcd_text) == 16,
+              "offset of BeginRasterCHROMIUM can_use_lcd_text should be 16");
+static_assert(
+    offsetof(BeginRasterCHROMIUM, use_distance_field_text) == 20,
+    "offset of BeginRasterCHROMIUM use_distance_field_text should be 20");
+static_assert(offsetof(BeginRasterCHROMIUM, pixel_config) == 24,
+              "offset of BeginRasterCHROMIUM pixel_config should be 24");
+
+struct RasterCHROMIUM {
+  typedef RasterCHROMIUM ValueType;
+  static const CommandId kCmdId = kRasterCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(uint32_t _list_shm_id,
+            uint32_t _list_shm_offset,
+            GLint _x,
+            GLint _y,
+            GLint _w,
+            GLint _h,
+            uint32_t _data_size) {
+    SetHeader();
+    list_shm_id = _list_shm_id;
+    list_shm_offset = _list_shm_offset;
+    x = _x;
+    y = _y;
+    w = _w;
+    h = _h;
+    data_size = _data_size;
+  }
+
+  void* Set(void* cmd,
+            uint32_t _list_shm_id,
+            uint32_t _list_shm_offset,
+            GLint _x,
+            GLint _y,
+            GLint _w,
+            GLint _h,
+            uint32_t _data_size) {
+    static_cast<ValueType*>(cmd)->Init(_list_shm_id, _list_shm_offset, _x, _y,
+                                       _w, _h, _data_size);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t list_shm_id;
+  uint32_t list_shm_offset;
+  int32_t x;
+  int32_t y;
+  int32_t w;
+  int32_t h;
+  uint32_t data_size;
+};
+
+static_assert(sizeof(RasterCHROMIUM) == 32,
+              "size of RasterCHROMIUM should be 32");
+static_assert(offsetof(RasterCHROMIUM, header) == 0,
+              "offset of RasterCHROMIUM header should be 0");
+static_assert(offsetof(RasterCHROMIUM, list_shm_id) == 4,
+              "offset of RasterCHROMIUM list_shm_id should be 4");
+static_assert(offsetof(RasterCHROMIUM, list_shm_offset) == 8,
+              "offset of RasterCHROMIUM list_shm_offset should be 8");
+static_assert(offsetof(RasterCHROMIUM, x) == 12,
+              "offset of RasterCHROMIUM x should be 12");
+static_assert(offsetof(RasterCHROMIUM, y) == 16,
+              "offset of RasterCHROMIUM y should be 16");
+static_assert(offsetof(RasterCHROMIUM, w) == 20,
+              "offset of RasterCHROMIUM w should be 20");
+static_assert(offsetof(RasterCHROMIUM, h) == 24,
+              "offset of RasterCHROMIUM h should be 24");
+static_assert(offsetof(RasterCHROMIUM, data_size) == 28,
+              "offset of RasterCHROMIUM data_size should be 28");
+
+struct EndRasterCHROMIUM {
+  typedef EndRasterCHROMIUM ValueType;
+  static const CommandId kCmdId = kEndRasterCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init() { SetHeader(); }
+
+  void* Set(void* cmd) {
+    static_cast<ValueType*>(cmd)->Init();
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+};
+
+static_assert(sizeof(EndRasterCHROMIUM) == 4,
+              "size of EndRasterCHROMIUM should be 4");
+static_assert(offsetof(EndRasterCHROMIUM, header) == 0,
+              "offset of EndRasterCHROMIUM header should be 0");
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 8e1d11c..860ff54 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -5399,4 +5399,50 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, BeginRasterCHROMIUM) {
+  cmds::BeginRasterCHROMIUM& cmd = *GetBufferAs<cmds::BeginRasterCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12),
+              static_cast<GLuint>(13), static_cast<GLboolean>(14),
+              static_cast<GLboolean>(15), static_cast<GLint>(16));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BeginRasterCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.texture_id);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.sk_color);
+  EXPECT_EQ(static_cast<GLuint>(13), cmd.msaa_sample_count);
+  EXPECT_EQ(static_cast<GLboolean>(14), cmd.can_use_lcd_text);
+  EXPECT_EQ(static_cast<GLboolean>(15), cmd.use_distance_field_text);
+  EXPECT_EQ(static_cast<GLint>(16), cmd.pixel_config);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, RasterCHROMIUM) {
+  cmds::RasterCHROMIUM& cmd = *GetBufferAs<cmds::RasterCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<uint32_t>(11),
+                           static_cast<uint32_t>(12), static_cast<GLint>(13),
+                           static_cast<GLint>(14), static_cast<GLint>(15),
+                           static_cast<GLint>(16), static_cast<uint32_t>(17));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::RasterCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<uint32_t>(11), cmd.list_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.list_shm_offset);
+  EXPECT_EQ(static_cast<GLint>(13), cmd.x);
+  EXPECT_EQ(static_cast<GLint>(14), cmd.y);
+  EXPECT_EQ(static_cast<GLint>(15), cmd.w);
+  EXPECT_EQ(static_cast<GLint>(16), cmd.h);
+  EXPECT_EQ(static_cast<uint32_t>(17), cmd.data_size);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, EndRasterCHROMIUM) {
+  cmds::EndRasterCHROMIUM& cmd = *GetBufferAs<cmds::EndRasterCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::EndRasterCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 0ae5f00..c5eb174 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -338,7 +338,10 @@
   OP(SetEnableDCLayersCHROMIUM)                            /* 579 */ \
   OP(InitializeDiscardableTextureCHROMIUM)                 /* 580 */ \
   OP(UnlockDiscardableTextureCHROMIUM)                     /* 581 */ \
-  OP(LockDiscardableTextureCHROMIUM)                       /* 582 */
+  OP(LockDiscardableTextureCHROMIUM)                       /* 582 */ \
+  OP(BeginRasterCHROMIUM)                                  /* 583 */ \
+  OP(RasterCHROMIUM)                                       /* 584 */ \
+  OP(EndRasterCHROMIUM)                                    /* 585 */
 
 enum CommandId {
   kOneBeforeStartPoint =
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 0a451f6..6a52eca7c 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -1896,24 +1896,7 @@
   return false;
 }
 
-ContextCreationAttribHelper::ContextCreationAttribHelper()
-    : gpu_preference(gl::PreferIntegratedGpu),
-      alpha_size(-1),
-      blue_size(-1),
-      green_size(-1),
-      red_size(-1),
-      depth_size(-1),
-      stencil_size(-1),
-      samples(-1),
-      sample_buffers(-1),
-      buffer_preserved(true),
-      bind_generates_resource(true),
-      fail_if_major_perf_caveat(false),
-      lose_context_when_out_of_memory(false),
-      should_use_native_gmb_for_backbuffer(false),
-      own_offscreen_surface(false),
-      single_buffer(false),
-      context_type(CONTEXT_TYPE_OPENGLES2) {}
+ContextCreationAttribHelper::ContextCreationAttribHelper() = default;
 
 ContextCreationAttribHelper::ContextCreationAttribHelper(
     const ContextCreationAttribHelper& other) = default;
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index 9ae3f2a..c6230a5 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -326,25 +326,26 @@
   bool Parse(const std::vector<int32_t>& attribs);
 
   gfx::Size offscreen_framebuffer_size;
-  gl::GpuPreference gpu_preference;
+  gl::GpuPreference gpu_preference = gl::PreferIntegratedGpu;
   // -1 if invalid or unspecified.
-  int32_t alpha_size;
-  int32_t blue_size;
-  int32_t green_size;
-  int32_t red_size;
-  int32_t depth_size;
-  int32_t stencil_size;
-  int32_t samples;
-  int32_t sample_buffers;
-  bool buffer_preserved;
-  bool bind_generates_resource;
-  bool fail_if_major_perf_caveat;
-  bool lose_context_when_out_of_memory;
-  bool should_use_native_gmb_for_backbuffer;
-  bool own_offscreen_surface;
-  bool single_buffer;
+  int32_t alpha_size = -1;
+  int32_t blue_size = -1;
+  int32_t green_size = -1;
+  int32_t red_size = -1;
+  int32_t depth_size = -1;
+  int32_t stencil_size = -1;
+  int32_t samples = -1;
+  int32_t sample_buffers = -1;
+  bool buffer_preserved = true;
+  bool bind_generates_resource = true;
+  bool fail_if_major_perf_caveat = false;
+  bool lose_context_when_out_of_memory = false;
+  bool should_use_native_gmb_for_backbuffer = false;
+  bool own_offscreen_surface = false;
+  bool single_buffer = false;
+  bool enable_oop_rasterization = false;
 
-  ContextType context_type;
+  ContextType context_type = CONTEXT_TYPE_OPENGLES2;
   ColorSpace color_space = COLOR_SPACE_UNSPECIFIED;
 };
 
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index b4b40b9..c3f63e3 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -167,6 +167,7 @@
     ":disk_cache_proto",
     "//base",
     "//base/third_party/dynamic_annotations",
+    "//cc/paint",
     "//crypto",
     "//gpu/command_buffer/client:client_sources",
     "//gpu/command_buffer/common:gles2_utils",
diff --git a/gpu/command_buffer/service/DEPS b/gpu/command_buffer/service/DEPS
index d1cd8cd..831a3d2 100644
--- a/gpu/command_buffer/service/DEPS
+++ b/gpu/command_buffer/service/DEPS
@@ -1,3 +1,5 @@
 include_rules = [
+  "+cc/paint",
   "+media/media_features.h",
+  "+third_party/skia",
 ]
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index c640145..e94e662 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -251,6 +251,9 @@
       (command_line->GetSwitchValueASCII(switches::kUseGL) ==
        gl::kGLImplementationSwiftShaderName);
 
+  feature_flags_.chromium_raster_transport =
+      command_line->HasSwitch(switches::kEnableOOPRasterization);
+
   // The shader translator is needed to translate from WebGL-conformant GLES SL
   // to normal GLES SL, enforce WebGL conformance, translate from GLES SL 1.0 to
   // target context GLSL, implement emulation of OpenGL ES features on OpenGL,
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 6a51ce6..2124d4d 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -84,6 +84,7 @@
     bool angle_texture_usage = false;
     bool ext_texture_storage = false;
     bool chromium_path_rendering = false;
+    bool chromium_raster_transport = false;
     bool chromium_framebuffer_mixed_samples = false;
     bool blend_equation_advanced = false;
     bool blend_equation_advanced_coherent = false;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index c059361..49eef3a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -26,6 +26,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "cc/paint/paint_op_buffer.h"
 #include "gpu/command_buffer/common/debug_marker_manager.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
@@ -68,6 +69,14 @@
 #include "gpu/command_buffer/service/vertex_array_manager.h"
 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
 #include "third_party/angle/src/image_util/loadimage.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/core/SkSurfaceProps.h"
+#include "third_party/skia/include/core/SkTypeface.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
 #include "third_party/smhasher/src/City.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/color_space.h"
@@ -101,6 +110,11 @@
 
 namespace {
 
+static GrGLFuncPtr get_gl_proc(void* ctx, const char name[]) {
+  DCHECK(!ctx);
+  return static_cast<GrGLFuncPtr>(gl::GetGLProcAddress(name));
+}
+
 const char kOESDerivativeExtension[] = "GL_OES_standard_derivatives";
 const char kEXTFragDepthExtension[] = "GL_EXT_frag_depth";
 const char kEXTDrawBuffersExtension[] = "GL_EXT_draw_buffers";
@@ -1941,6 +1955,14 @@
                                     GLenum textarget,
                                     GLuint texture_unit);
 
+  void DoBeginRasterCHROMIUM(GLuint texture_id,
+                             GLuint sk_color,
+                             GLuint msaa_sample_count,
+                             GLboolean can_use_lcd_text,
+                             GLboolean use_distance_field_text,
+                             GLint pixel_config);
+  void DoEndRasterCHROMIUM();
+
   // Returns false if textures were replaced.
   bool PrepareTexturesForRender();
   void RestoreStateForTextures();
@@ -2496,6 +2518,10 @@
   std::unique_ptr<CALayerSharedState> ca_layer_shared_state_;
   std::unique_ptr<DCLayerSharedState> dc_layer_shared_state_;
 
+  // Raster helpers.
+  sk_sp<GrContext> gr_context_;
+  sk_sp<SkSurface> sk_surface_;
+
   base::WeakPtrFactory<GLES2DecoderImpl> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
@@ -3689,6 +3715,33 @@
     glHint(GL_TEXTURE_FILTERING_HINT_CHROMIUM, GL_NICEST);
   }
 
+  if (attrib_helper.enable_oop_rasterization) {
+    if (!features().chromium_raster_transport)
+      return false;
+    sk_sp<const GrGLInterface> interface(
+        GrGLAssembleInterface(nullptr, get_gl_proc));
+    // TODO(enne): if this or gr_context creation below fails in practice for
+    // different reasons than the ones the renderer would fail on for gpu
+    // raster, expose this in gpu::Capabilities so the renderer can handle it.
+    if (!interface)
+      return false;
+    gr_context_ = sk_sp<GrContext>(
+        GrContext::Create(kOpenGL_GrBackend,
+                          reinterpret_cast<GrBackendContext>(interface.get())));
+    if (!gr_context_)
+      return false;
+
+    // TODO(enne): this cache is for this decoder only and each decoder has
+    // its own cache.  This is pretty unfortunate.  This really needs to be
+    // rethought before shipping.  Most likely a different command buffer
+    // context for raster-in-gpu, with a shared gl context / gr context
+    // that different decoders can use.
+    static const int kMaxGaneshResourceCacheCount = 8196;
+    static const size_t kMaxGaneshResourceCacheBytes = 96 * 1024 * 1024;
+    gr_context_->setResourceCacheLimits(kMaxGaneshResourceCacheCount,
+                                        kMaxGaneshResourceCacheBytes);
+  }
+
   return true;
 }
 
@@ -19910,6 +19963,177 @@
   return error::kNoError;
 }
 
+void GLES2DecoderImpl::DoBeginRasterCHROMIUM(GLuint texture_id,
+                                             GLuint sk_color,
+                                             GLuint msaa_sample_count,
+                                             GLboolean can_use_lcd_text,
+                                             GLboolean use_distance_field_text,
+                                             GLint pixel_config) {
+  if (!gr_context_) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                       "chromium_raster_transport not enabled via attribs");
+    return;
+  }
+  if (sk_surface_) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                       "BeginRasterCHROMIUM without EndRasterCHROMIUM");
+    return;
+  }
+
+  gr_context_->resetContext();
+
+  // This function should look identical to
+  // ResourceProvider::ScopedSkSurfaceProvider.
+  GrGLTextureInfo texture_info;
+  auto* texture_ref = GetTexture(texture_id);
+  if (!texture_ref) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                       "unknown texture id");
+    return;
+  }
+  auto* texture = texture_ref->texture();
+  int width;
+  int height;
+  int depth;
+  if (!texture->GetLevelSize(texture->target(), 0, &width, &height, &depth)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                       "missing texture size info");
+    return;
+  }
+  GLenum type;
+  GLenum internal_format;
+  if (!texture->GetLevelType(texture->target(), 0, &type, &internal_format)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                       "missing texture type info");
+    return;
+  }
+  texture_info.fID = texture_ref->service_id();
+  texture_info.fTarget = texture->target();
+
+  if (texture->target() != GL_TEXTURE_2D &&
+      texture->target() != GL_TEXTURE_RECTANGLE_ARB) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                       "invalid texture target");
+    return;
+  }
+
+  switch (pixel_config) {
+    case kRGBA_4444_GrPixelConfig:
+    case kRGBA_8888_GrPixelConfig:
+    case kSRGBA_8888_GrPixelConfig:
+      if (internal_format != GL_RGBA8_OES && internal_format != GL_RGBA) {
+        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                           "pixel config mismatch");
+        return;
+      }
+      break;
+    case kBGRA_8888_GrPixelConfig:
+    case kSBGRA_8888_GrPixelConfig:
+      if (internal_format != GL_BGRA_EXT && internal_format != GL_BGRA8_EXT) {
+        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                           "pixel config mismatch");
+        return;
+      }
+      break;
+    default:
+      LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                         "unsupported pixel config");
+      return;
+  }
+
+  GrBackendTexture gr_texture(
+      width, height, static_cast<GrPixelConfig>(pixel_config), texture_info);
+
+  uint32_t flags =
+      use_distance_field_text ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
+  // Use unknown pixel geometry to disable LCD text.
+  SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
+  if (can_use_lcd_text) {
+    // LegacyFontHost will get LCD text and skia figures out what type to use.
+    surface_props =
+        SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
+  }
+
+  // Resolve requested msaa samples with GrGpu capabilities.
+  int final_msaa_count = gr_context_->caps()->getSampleCount(
+      msaa_sample_count, gr_texture.config());
+  sk_surface_ = SkSurface::MakeFromBackendTextureAsRenderTarget(
+      gr_context_.get(), gr_texture, kTopLeft_GrSurfaceOrigin, final_msaa_count,
+      nullptr, &surface_props);
+
+  if (!sk_surface_) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                       "failed to create surface");
+    return;
+  }
+
+  // All or nothing clearing, as no way to validate the client's input on what
+  // is the "used" part of the texture.
+  if (texture->IsLevelCleared(texture->target(), 0))
+    return;
+
+  // TODO(enne): this doesn't handle the case where the background color
+  // changes and so any extra pixels outside the raster area that get
+  // sampled may be incorrect.
+  sk_surface_->getCanvas()->drawColor(sk_color);
+  texture_manager()->SetLevelCleared(texture_ref, texture->target(), 0, true);
+}
+
+error::Error GLES2DecoderImpl::HandleRasterCHROMIUM(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  if (!sk_surface_) {
+    LOG(ERROR) << "RasterCHROMIUM without BeginRasterCHROMIUM";
+    return error::kInvalidArguments;
+  }
+
+  alignas(
+      cc::PaintOpBuffer::PaintOpAlign) char data[sizeof(cc::LargestPaintOp)];
+  auto& c = *static_cast<const volatile gles2::cmds::RasterCHROMIUM*>(cmd_data);
+  size_t size = c.data_size;
+  char* buffer =
+      GetSharedMemoryAs<char*>(c.list_shm_id, c.list_shm_offset, size);
+  if (!buffer)
+    return error::kOutOfBounds;
+
+  SkCanvas* canvas = sk_surface_->getCanvas();
+  SkMatrix original_ctm;
+  cc::PlaybackParams playback_params(nullptr, original_ctm);
+
+  int op_idx = 0;
+  while (size > 4) {
+    size_t skip = 0;
+    cc::PaintOp* deserialized_op = cc::PaintOp::Deserialize(
+        buffer, size, &data[0], sizeof(cc::LargestPaintOp), &skip);
+    if (!deserialized_op) {
+      LOG(ERROR) << "RasterCHROMIUM: bad op: " << op_idx;
+      return error::kInvalidArguments;
+    }
+
+    deserialized_op->Raster(canvas, playback_params);
+    deserialized_op->DestroyThis();
+
+    size -= skip;
+    buffer += skip;
+    op_idx++;
+  }
+
+  return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoEndRasterCHROMIUM() {
+  if (!sk_surface_) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
+                       "EndRasterCHROMIUM without BeginRasterCHROMIUM");
+    return;
+  }
+
+  sk_surface_->prepareForExternalIO();
+  sk_surface_.reset();
+
+  RestoreState(nullptr);
+}
+
 // Include the auto-generated part of this file. We split this because it means
 // we can easily edit the non-auto generated parts right here in this file
 // instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 1109545..9bbab23 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -5206,6 +5206,39 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleBeginRasterCHROMIUM(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  const volatile gles2::cmds::BeginRasterCHROMIUM& c =
+      *static_cast<const volatile gles2::cmds::BeginRasterCHROMIUM*>(cmd_data);
+  if (!features().chromium_raster_transport) {
+    return error::kUnknownCommand;
+  }
+
+  GLuint texture_id = static_cast<GLuint>(c.texture_id);
+  GLuint sk_color = static_cast<GLuint>(c.sk_color);
+  GLuint msaa_sample_count = static_cast<GLuint>(c.msaa_sample_count);
+  GLboolean can_use_lcd_text = static_cast<GLboolean>(c.can_use_lcd_text);
+  GLboolean use_distance_field_text =
+      static_cast<GLboolean>(c.use_distance_field_text);
+  GLint pixel_config = static_cast<GLint>(c.pixel_config);
+  DoBeginRasterCHROMIUM(texture_id, sk_color, msaa_sample_count,
+                        can_use_lcd_text, use_distance_field_text,
+                        pixel_config);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleEndRasterCHROMIUM(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  if (!features().chromium_raster_transport) {
+    return error::kUnknownCommand;
+  }
+
+  DoEndRasterCHROMIUM();
+  return error::kNoError;
+}
+
 bool GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) {
   switch (cap) {
     case GL_BLEND:
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index 4eadf413..f033ced3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -304,6 +304,11 @@
     return false;
   }
 
+  if (attrib_helper.enable_oop_rasterization) {
+    Destroy(true);
+    return false;
+  }
+
   bind_generates_resource_ = group_->bind_generates_resource();
 
   resources_ = group_->passthrough_resources();
@@ -1256,6 +1261,15 @@
   }
 }
 
+error::Error GLES2DecoderPassthroughImpl::HandleRasterCHROMIUM(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  // TODO(enne): Add CHROMIUM_raster_transport extension support to the
+  // passthrough command buffer.
+  NOTIMPLEMENTED();
+  return error::kNoError;
+}
+
 #define GLES2_CMD_OP(name)                                               \
   {                                                                      \
       &GLES2DecoderPassthroughImpl::Handle##name, cmds::name::kArgFlags, \
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
index 9c4d670..a598f902 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
@@ -988,3 +988,10 @@
                                         GLint width,
                                         GLint height);
 error::Error DoSetEnableDCLayersCHROMIUM(GLboolean enable);
+error::Error DoBeginRasterCHROMIUM(GLuint texture_id,
+                                   GLuint sk_color,
+                                   GLuint msaa_sample_count,
+                                   GLboolean can_use_lcd_text,
+                                   GLboolean use_distance_field_text,
+                                   GLint pixel_config);
+error::Error DoEndRasterCHROMIUM();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index 6863bef..e08bc97 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -4336,5 +4336,21 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderPassthroughImpl::DoBeginRasterCHROMIUM(
+    GLuint texture_id,
+    GLuint sk_color,
+    GLuint msaa_sample_count,
+    GLboolean can_use_lcd_text,
+    GLboolean use_distance_field_text,
+    GLint pixel_config) {
+  NOTIMPLEMENTED();
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderPassthroughImpl::DoEndRasterCHROMIUM() {
+  NOTIMPLEMENTED();
+  return error::kNoError;
+}
+
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
index 2256a806..3c805fa 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
@@ -4406,5 +4406,36 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderPassthroughImpl::HandleBeginRasterCHROMIUM(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  const volatile gles2::cmds::BeginRasterCHROMIUM& c =
+      *static_cast<const volatile gles2::cmds::BeginRasterCHROMIUM*>(cmd_data);
+  GLuint texture_id = static_cast<GLuint>(c.texture_id);
+  GLuint sk_color = static_cast<GLuint>(c.sk_color);
+  GLuint msaa_sample_count = static_cast<GLuint>(c.msaa_sample_count);
+  GLboolean can_use_lcd_text = static_cast<GLboolean>(c.can_use_lcd_text);
+  GLboolean use_distance_field_text =
+      static_cast<GLboolean>(c.use_distance_field_text);
+  GLint pixel_config = static_cast<GLint>(c.pixel_config);
+  error::Error error = DoBeginRasterCHROMIUM(
+      texture_id, sk_color, msaa_sample_count, can_use_lcd_text,
+      use_distance_field_text, pixel_config);
+  if (error != error::kNoError) {
+    return error;
+  }
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderPassthroughImpl::HandleEndRasterCHROMIUM(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  error::Error error = DoEndRasterCHROMIUM();
+  if (error != error::kNoError) {
+    return error;
+  }
+  return error::kNoError;
+}
+
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc
index 7e080f1..7812a2d9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc
@@ -1724,6 +1724,26 @@
   EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
 }
 
+class GLES2DecoderTestWithCHROMIUMRasterTransport : public GLES2DecoderTest {
+ public:
+  GLES2DecoderTestWithCHROMIUMRasterTransport() {}
+  void SetUp() override {
+    InitState init;
+    init.gl_version = "opengl es 2.0";
+    init.has_alpha = true;
+    init.has_depth = true;
+    init.request_alpha = true;
+    init.request_depth = true;
+    init.bind_generates_resource = true;
+    init.extensions = "chromium_raster_transport";
+    InitDecoder(init);
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(Service,
+                        GLES2DecoderTestWithCHROMIUMRasterTransport,
+                        ::testing::Bool());
+
 #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h"
 
 }  // namespace gles2
diff --git a/gpu/config/gpu_switches.cc b/gpu/config/gpu_switches.cc
index 19f4680..fc37290 100644
--- a/gpu/config/gpu_switches.cc
+++ b/gpu/config/gpu_switches.cc
@@ -19,6 +19,10 @@
 // impl-side painting.
 const char kEnableGpuRasterization[] = "enable-gpu-rasterization";
 
+// Turns on out of process raster for the renderer whenever gpu raster
+// would have been used.  Enables the chromium_raster_transport extension.
+const char kEnableOOPRasterization[] = "enable-oop-rasterization";
+
 // Passes active gpu vendor id from browser process to GPU process.
 const char kGpuActiveVendorID[] = "gpu-active-vendor-id";
 
diff --git a/gpu/config/gpu_switches.h b/gpu/config/gpu_switches.h
index 9925ad2..69d642b 100644
--- a/gpu/config/gpu_switches.h
+++ b/gpu/config/gpu_switches.h
@@ -12,6 +12,7 @@
 GPU_EXPORT extern const char kDisableGpuDriverBugWorkarounds[];
 GPU_EXPORT extern const char kDisableGpuRasterization[];
 GPU_EXPORT extern const char kEnableGpuRasterization[];
+GPU_EXPORT extern const char kEnableOOPRasterization[];
 GPU_EXPORT extern const char kGpuActiveVendorID[];
 GPU_EXPORT extern const char kGpuActiveDeviceID[];
 GPU_EXPORT extern const char kGpuDeviceID[];
diff --git a/gpu/ipc/common/gpu_command_buffer_traits_multi.h b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
index fa535af..a7145c0 100644
--- a/gpu/ipc/common/gpu_command_buffer_traits_multi.h
+++ b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
@@ -173,4 +173,5 @@
   IPC_STRUCT_TRAITS_MEMBER(own_offscreen_surface)
   IPC_STRUCT_TRAITS_MEMBER(single_buffer)
   IPC_STRUCT_TRAITS_MEMBER(color_space)
+  IPC_STRUCT_TRAITS_MEMBER(enable_oop_rasterization)
 IPC_STRUCT_TRAITS_END()