Remove atlas creation from GrResourceProvider

This is pulled out of: https://skia-review.googlesource.com/c/6680/ (Make SkImage_Gpu be deferred) and is only tangentially related to the goal of that CL.

Change-Id: I6b6db4869597070f85ab3b9fea178fc88c104f87
Reviewed-on: https://skia-review.googlesource.com/9106
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp
index 6661b48..e9fd356 100644
--- a/src/gpu/GrDrawOpAtlas.cpp
+++ b/src/gpu/GrDrawOpAtlas.cpp
@@ -10,8 +10,46 @@
 #include "GrContext.h"
 #include "GrOpFlushState.h"
 #include "GrRectanizer.h"
+#include "GrResourceProvider.h"
 #include "GrTracing.h"
 
+std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig config,
+                                                   int width, int height,
+                                                   int numPlotsX, int numPlotsY,
+                                                   GrDrawOpAtlas::EvictionFunc func,
+                                                   void* data) {
+    GrSurfaceDesc desc;
+    desc.fFlags = kNone_GrSurfaceFlags;
+    desc.fWidth = width;
+    desc.fHeight = height;
+    desc.fConfig = config;
+
+    // We don't want to flush the context so we claim we're in the middle of flushing so as to
+    // guarantee we do not recieve a texture with pending IO
+    // TODO: Determine how to avoid having to do this. (https://bug.skia.org/4156)
+    static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag;
+    sk_sp<GrTexture> texture(ctx->textureProvider()->createApproxTexture(desc, kFlags));
+    if (!texture) {
+        return nullptr;
+    }
+
+    // MDB TODO: for now, wrap an instantiated texture. Having the deferred instantiation
+    // possess the correct properties (e.g., no pendingIO) should fall out of the system but
+    // should receive special attention.
+    // Note: When switching over to the deferred proxy, use the kExact flag to create
+    // the atlas and assert that the width & height are powers of 2.
+    sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeWrapped(std::move(texture));
+    if (!proxy) {
+        return nullptr;
+    }
+
+    std::unique_ptr<GrDrawOpAtlas> atlas(
+            new GrDrawOpAtlas(ctx, std::move(proxy), numPlotsX, numPlotsY));
+    atlas->registerEvictionCallback(func, data);
+    return atlas;
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 
 GrDrawOpAtlas::Plot::Plot(int index, uint64_t genID, int offX, int offY, int width, int height,
@@ -160,7 +198,7 @@
     }
 }
 
-inline void GrDrawOpAtlas::updatePlot(GrDrawOp::Target* target, AtlasID* id, Plot* plot) {
+inline bool GrDrawOpAtlas::updatePlot(GrDrawOp::Target* target, AtlasID* id, Plot* plot) {
     this->makeMRU(plot);
 
     // If our most recent upload has already occurred then we have to insert a new
@@ -169,19 +207,23 @@
     if (target->hasDrawBeenFlushed(plot->lastUploadToken())) {
         // With c+14 we could move sk_sp into lamba to only ref once.
         sk_sp<Plot> plotsp(SkRef(plot));
+
         // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated.
         // Once it is deferred more care must be taken upon instantiation failure.
         GrTexture* texture = fProxy->instantiate(fContext->textureProvider());
-        if (texture) {
-            GrDrawOpUploadToken lastUploadToken = target->addAsapUpload(
-                [plotsp, texture] (GrDrawOp::WritePixelsFn& writePixels) {
-                   plotsp->uploadToTexture(writePixels, texture);
-                }
-            );
-            plot->setLastUploadToken(lastUploadToken);
+        if (!texture) {
+            return false;
         }
+
+        GrDrawOpUploadToken lastUploadToken = target->addAsapUpload(
+            [plotsp, texture] (GrDrawOp::WritePixelsFn& writePixels) {
+                plotsp->uploadToTexture(writePixels, texture);
+            }
+        );
+        plot->setLastUploadToken(lastUploadToken);
     }
     *id = plot->id();
+    return true;
 }
 
 bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, int height,
@@ -199,8 +241,7 @@
     while ((plot = plotIter.get())) {
         SkASSERT(GrBytesPerPixel(fProxy->desc().fConfig) == plot->bpp());
         if (plot->addSubImage(width, height, image, loc)) {
-            this->updatePlot(target, id, plot);
-            return true;
+            return this->updatePlot(target, id, plot);
         }
         plotIter.next();
     }
@@ -215,7 +256,10 @@
         SkASSERT(GrBytesPerPixel(fProxy->desc().fConfig) == plot->bpp());
         SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc);
         SkASSERT(verify);
-        this->updatePlot(target, id, plot);
+        if (!this->updatePlot(target, id, plot)) {
+            return false;
+        }
+
         fAtlasGeneration++;
         return true;
     }
@@ -246,15 +290,17 @@
     // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated.
     // Once it is deferred more care must be taken upon instantiation failure.
     GrTexture* texture = fProxy->instantiate(fContext->textureProvider());
-    if (texture) {
-        GrDrawOpUploadToken lastUploadToken = target->addInlineUpload(
-            [plotsp, texture] (GrDrawOp::WritePixelsFn& writePixels) {
-                plotsp->uploadToTexture(writePixels, texture);
-            }
-        );
-        newPlot->setLastUploadToken(lastUploadToken);
+    if (!texture) {
+        return false;
     }
 
+    GrDrawOpUploadToken lastUploadToken = target->addInlineUpload(
+        [plotsp, texture] (GrDrawOp::WritePixelsFn& writePixels) {
+            plotsp->uploadToTexture(writePixels, texture);
+        }
+    );
+    newPlot->setLastUploadToken(lastUploadToken);
+
     *id = newPlot->id();
 
     fAtlasGeneration++;