Update DDL test harness to use backendTextures to back tiles (take 2)

This better matches Chrome's use of DDLs.

With path, image, and text draws stripped out, here is the perf impact of this change:

           before CL   after CL
w/ DDLs      7.792      1.038
w/o DDLs     0.800      0.876

This perf improvement (in the DDL case) is from backend texture wrapping SkSurfaces being created w/o initialization. The prior method of SkSurface creation was resulting in double clearing of all the surfaces.

This perf improvement won't be seen by Chrome since they've always being using wrapped backend texture SkSurfaces.

TBR=bsalomon@google.com

Bug: 1056730
Change-Id: Ic04d322cad96df845e75437211208495862c6555
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/283866
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/tools/DDLTileHelper.cpp b/tools/DDLTileHelper.cpp
index d5d0045..8477b1f 100644
--- a/tools/DDLTileHelper.cpp
+++ b/tools/DDLTileHelper.cpp
@@ -28,6 +28,7 @@
 
     fCharacterization = dstSurfaceCharacterization.createResized(clip.width(), clip.height());
     SkASSERT(fCharacterization.isValid());
+    SkASSERT(!fBackendTexture.isValid());
 }
 
 DDLTileHelper::TileData::~TileData() {}
@@ -91,51 +92,100 @@
     }
 }
 
-void DDLTileHelper::TileData::drawSKPDirectly(GrContext* context) {
-    SkASSERT(!fDisplayList && !fImage && fReconstitutedPicture);
+sk_sp<SkSurface> DDLTileHelper::TileData::makeWrappedTileDest(GrContext* context) {
+    if (!fBackendTexture.isValid()) {
+        return nullptr;
+    }
 
-    sk_sp<SkSurface> tileSurface = SkSurface::MakeRenderTarget(context, fCharacterization,
-                                                               SkBudgeted::kYes);
-    if (tileSurface) {
-        SkCanvas* tileCanvas = tileSurface->getCanvas();
+    return SkSurface::MakeFromBackendTexture(context,
+                                             fBackendTexture,
+                                             fCharacterization.origin(),
+                                             fCharacterization.sampleCount(),
+                                             fCharacterization.colorType(),
+                                             fCharacterization.refColorSpace(),
+                                             &fCharacterization.surfaceProps());
+}
+
+void DDLTileHelper::TileData::drawSKPDirectly(GrContext* context) {
+    SkASSERT(!fDisplayList && !fTileSurface && fReconstitutedPicture);
+
+    fTileSurface = this->makeWrappedTileDest(context);
+    if (fTileSurface) {
+        SkCanvas* tileCanvas = fTileSurface->getCanvas();
 
         tileCanvas->clipRect(SkRect::MakeWH(fClip.width(), fClip.height()));
         tileCanvas->translate(-fClip.fLeft, -fClip.fTop);
 
         tileCanvas->drawPicture(fReconstitutedPicture);
 
-        fImage = tileSurface->makeImageSnapshot();
+        // We can't snap an image here bc, since we're using wrapped backend textures for the
+        // surfaces, that would incur a copy.
     }
 }
 
 void DDLTileHelper::TileData::draw(GrContext* context) {
-    SkASSERT(fDisplayList && !fImage);
+    SkASSERT(fDisplayList && !fTileSurface);
 
-    sk_sp<SkSurface> tileSurface = SkSurface::MakeRenderTarget(context, fCharacterization,
-                                                               SkBudgeted::kYes);
-    if (tileSurface) {
-        tileSurface->draw(fDisplayList.get());
+    // The tile's surface needs to be held until after the DDL is flushed
+    fTileSurface = this->makeWrappedTileDest(context);
+    if (fTileSurface) {
+        fTileSurface->draw(fDisplayList.get());
 
-        fImage = tileSurface->makeImageSnapshot();
+        // We can't snap an image here bc, since we're using wrapped backend textures for the
+        // surfaces, that would incur a copy.
     }
 }
 
 // TODO: We should create a single DDL for the composition step and just add replaying it
 // as the last GPU task
-void DDLTileHelper::TileData::compose() {
-    SkASSERT(fDstSurface && fImage);
+void DDLTileHelper::TileData::compose(GrContext* context) {
+    SkASSERT(context->priv().asDirectContext());
+    SkASSERT(fDstSurface);
+
+    if (!fBackendTexture.isValid()) {
+        return;
+    }
+
+    // Here we are, unfortunately, aliasing 'fBackendTexture'. It is backing both 'fTileSurface'
+    // and 'tmp'.
+    sk_sp<SkImage> tmp = SkImage::MakeFromTexture(context,
+                                                  fBackendTexture,
+                                                  fCharacterization.origin(),
+                                                  fCharacterization.colorType(),
+                                                  kPremul_SkAlphaType,
+                                                  fCharacterization.refColorSpace());
 
     SkCanvas* canvas = fDstSurface->getCanvas();
     canvas->save();
     canvas->clipRect(SkRect::Make(fClip));
-    canvas->drawImage(fImage, fClip.fLeft, fClip.fTop);
+    canvas->drawImage(tmp, fClip.fLeft, fClip.fTop);
     canvas->restore();
 }
 
 void DDLTileHelper::TileData::reset() {
     // TODO: when DDLs are re-renderable we don't need to do this
     fDisplayList = nullptr;
-    fImage = nullptr;
+    fTileSurface = nullptr;
+}
+
+void DDLTileHelper::TileData::CreateBackendTexture(GrContext* context, TileData* tile) {
+    SkASSERT(context->priv().asDirectContext());
+    SkASSERT(!tile->fBackendTexture.isValid());
+
+    tile->fBackendTexture = context->createBackendTexture(tile->fCharacterization);
+    // TODO: it seems that, on the Linux bots, backend texture creation is failing
+    // a lot (skbug.com/10142)
+    //SkASSERT(tile->fBackendTexture.isValid());
+}
+
+void DDLTileHelper::TileData::DeleteBackendTexture(GrContext* context, TileData* tile) {
+    SkASSERT(context->priv().asDirectContext());
+    // TODO: it seems that, on the Linux bots, backend texture creation is failing
+    // a lot (skbug.com/10142)
+    //SkASSERT(tile->fBackendTexture.isValid());
+
+    tile->fTileSurface = nullptr;
+    context->deleteBackendTexture(tile->fBackendTexture);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -199,7 +249,7 @@
 
     // TODO: we should actually have a separate DDL that does
     // the final composition draw
-    tile->compose();
+    tile->compose(context);
 }
 
 // We expect to have more than one recording thread but just one gpu thread
@@ -246,9 +296,9 @@
     }
 }
 
-void DDLTileHelper::composeAllTiles() {
+void DDLTileHelper::composeAllTiles(GrContext* context) {
     for (int i = 0; i < this->numTiles(); ++i) {
-        fTiles[i].compose();
+        fTiles[i].compose(context);
     }
 }
 
@@ -257,3 +307,35 @@
         fTiles[i].reset();
     }
 }
+
+void DDLTileHelper::createBackendTextures(SkTaskGroup* taskGroup, GrContext* context) {
+    SkASSERT(context->priv().asDirectContext());
+
+    if (taskGroup) {
+        for (int i = 0; i < this->numTiles(); ++i) {
+            TileData* tile = &fTiles[i];
+
+            taskGroup->add([context, tile]() { TileData::CreateBackendTexture(context, tile); });
+        }
+    } else {
+        for (int i = 0; i < this->numTiles(); ++i) {
+            TileData::CreateBackendTexture(context, &fTiles[i]);
+        }
+    }
+}
+
+void DDLTileHelper::deleteBackendTextures(SkTaskGroup* taskGroup, GrContext* context) {
+    SkASSERT(context->priv().asDirectContext());
+
+    if (taskGroup) {
+        for (int i = 0; i < this->numTiles(); ++i) {
+            TileData* tile = &fTiles[i];
+
+            taskGroup->add([context, tile]() { TileData::DeleteBackendTexture(context, tile); });
+        }
+    } else {
+        for (int i = 0; i < this->numTiles(); ++i) {
+            TileData::DeleteBackendTexture(context, &fTiles[i]);
+        }
+    }
+}