1 of 13

Out of Process Rasterization

enne@

2 of 13

What is OOP-R?

Previous GPU raster pipeline:

paint (SkPicture) → raster task → raster (Skia) → gles2 command buffer → gl

Current OOP raster pipeline:

paint (paint ops) → raster task → raster command bufferraster (Skia) → gl

3 of 13

Why OOP-R?

Top Level Goal: use Vulkan instead of OpenGL (for performance / stability)

Problem: command buffer has OpenGL baked in

Solution: create a new command buffer interface and serialization format, run raster (Skia) in the gpu process

Bonus goals: OpenGL is chatty; serializing paint data structures is faster

4 of 13

Data Structures

Why?

  • Differing security needs
  • Image replacement
  • Mutability / updatability
  • Project differences

Mappings from analogous Skia classes:

  • SkCanvas -> PaintCanvas
  • SkPaint -> PaintFlags
  • SkPicture -> PaintRecord (== PaintOpBuffer)
  • SkShader -> PaintShader
  • SkImage -> PaintImage

PaintCanvas subclasses:

SkiaPaintCanvas is PaintCanvas -> SkCanvas

RecordPaintCanvas is PaintCanvas -> PaintRecord

5 of 13

PaintOpBuffer / PaintRecord dissection

class CC_PAINT_EXPORT PaintOp {

public:

uint32_t type : 8;

uint32_t skip : 24; // size of this serialized op

};

PaintOps = heterogenous types serialized in a flat buffer, e.g.:

enum class PaintOpType : uint8_t {

Annotate,

ClipPath,

ClipRect,

ClipRRect,

Concat,

CustomData,

DrawColor,

DrawDRRect,

DrawImage,

DrawImageRect,

DrawIRect,

DrawLine,

DrawOval,

DrawPath,

DrawRecord,

DrawRect,

DrawRRect,

DrawSkottie,

DrawTextBlob,

Noop,

Restore,

Rotate,

Save,

SaveLayer,

SaveLayerAlpha,

Scale,

SetMatrix,

Translate,

};

SaveOp

DrawRectOp

DrawColorOp

RestoreOp

&c &c &c

6 of 13

Serialization Overview

command buffer

transfer buffer

mapped memory

GPURasterBufferProvider

RI::BeginRasterCHROMIUM(mailbox, etc)

RI::RasterCHROMIUM(record, settings)

Grab all transfer buffer space

POBSerializer::Serialize(paint record)

SerializePreamble()

for each op in record:

serialize op into transfer buffer

if it doesn’t fit:

SendSerializedData()

Allocate/wait until tb space available

Shrink transfer buffer to space used

SendSerializedData()

RI::EndRasterCHROMIUM()

rough call stack / psuedocode

BeginRC

RC

RC

Create�TCEntry

RC

RC

EndRC

(serialized ops)

image

data

glyph

data

7 of 13

Command Buffer Changes

GL Command Buffer:

GLES2Interface + GLES2Implementation

  • Renderer side
  • All GL functions plus Chromium extensions

GLES2Decoder(Impl)

  • GPU side of gl command buffer

Raster Command Buffer:

RasterInterface + RasterImplementation

  • RasterCHROMIUM functions, sync tokens, also some texture functions

RasterInterface + RasterImplementationGLES

  • Allows using RasterInterface backed by GLES2 (for the non-OOPR functions)

RasterDecoder(Impl)

  • SharedContextState maintains shared GrContext + ServiceTransferCache + shader cache among all RasterDecoders

8 of 13

Transfer Cache Overview

Coordinates caching of data between the renderer and gpu.

Entries don’t depend on other entries.

Types: images, paint shaders, raw memory

Depends on discardable gpu memory system via gpu::(Client|Service)DiscardableManager. (Note: not the same as base::DiscardableMemoryAllocator!)

Create/Lock/Unlock commands in command buffer, issued by client but processed on service side.

Lock on client side and unlock on service side access shared memory, so no need for ipc to check availability.

GPU side can purge unlocked items freely so long as the client locks before using.

9 of 13

Image Serialization Details

Transfer cache used for all image types:�pre-decoded, at raster, lazy, non-lazy

ServiceImageTransferCacheEntry handles uploading, software vs hardware images, color space conversion

Serializing an image is just serializing its transfer cache id

10 of 13

(Client|Server)PaintCache

Questions:

  • Yikes, why another type of caching?
  • Gosh, why cache small objects at all?

Implementation Details:

  • Used for paths and blobs, currently
  • Client side manages memory and budget
  • Paint cache insertion is part of serializing
  • Deserializer creates service side entries
  • Separate command buffer commands for deletion of entries
  • Cleared during raster context idle cleanup, so only a working set cache

11 of 13

Typeface and Glyph Serialization

Renderer Side

While serializing, draw all PaintOps into a SkTextBlobCacheDiffCanvas to find blobs.

SkStrikeServer + ClientFontManager find new typefaces and strikes, lock any strikes needed using discardable handles.

Prior to a RasterCHROMIUM command, serialize new typefaces and strikes into mapped memory.

GPU Side

When receiving a RasterCHROMIUM command, add all new typefaces and strikes to the SkStrikeClient + ServiceFontManager.

When rastering to a Ganesh-backed SkCanvas, look up any glyphs needed from the SkStrikeClient.

12 of 13

Unexpected

Hurdles

  • Shader caching
  • Command buffer workarounds
  • gles3 vs gles2
  • Skia path renderers
  • Mac driver bugs

13 of 13

Follow-up Work

  • Ship OOP-R everywhere
  • Clean up temp Skia objects
  • Canvas OOP-R
  • Parallelize GPU main thread
  • Software raster