Add bridge between GrContext::createBackendTexture and SkSurface::MakeFromBackendTexture

In order to effectively use the explicit backend texture allocation API Chrome needs a way to use them with surface characterizations

Change-Id: Ic61eff9f3b6b0e8280481149d7c08d37a2fe7ec0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/222781
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 3a3f43d..604eab0 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -363,6 +363,83 @@
     return this->createBackendTexture(width, height, format, mipMapped, renderable, isProtected);
 }
 
+GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization& c) {
+    const GrCaps* caps = this->caps();
+
+    if (!this->asDirectContext() || !c.isValid()) {
+        return GrBackendTexture();
+    }
+
+    if (this->abandoned()) {
+        return GrBackendTexture();
+    }
+
+    if (c.usesGLFBO0()) {
+        // If we are making the surface we will never use FBO0.
+        return GrBackendTexture();
+    }
+
+    if (c.vulkanSecondaryCBCompatible()) {
+        return {};
+    }
+
+    const GrBackendFormat format = caps->getBackendFormatFromColorType(c.colorType());
+    if (!format.isValid()) {
+        return GrBackendTexture();
+    }
+
+    if (!SkSurface_Gpu::Valid(caps, format)) {
+        return GrBackendTexture();
+    }
+
+    // TODO (PROT-CHAR): pass in protection status once added to characterization
+    GrBackendTexture result = this->createBackendTexture(c.width(), c.height(), format,
+                                                         GrMipMapped(c.isMipMapped()),
+                                                         GrRenderable::kYes,
+                                                         GrProtected::kNo);
+    SkASSERT(c.isCompatible(result));
+    return result;
+}
+
+GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization& c,
+                                                 const SkColor4f& color) {
+    const GrCaps* caps = this->caps();
+
+    if (!this->asDirectContext() || !c.isValid()) {
+        return GrBackendTexture();
+    }
+
+    if (this->abandoned()) {
+        return GrBackendTexture();
+    }
+
+    if (c.usesGLFBO0()) {
+        // If we are making the surface we will never use FBO0.
+        return GrBackendTexture();
+    }
+
+    if (c.vulkanSecondaryCBCompatible()) {
+        return {};
+    }
+
+    const GrBackendFormat format = caps->getBackendFormatFromColorType(c.colorType());
+    if (!format.isValid()) {
+        return GrBackendTexture();
+    }
+
+    if (!SkSurface_Gpu::Valid(caps, format)) {
+        return GrBackendTexture();
+    }
+
+    // TODO (PROT-CHAR): pass in protection status once added to characterization
+    GrBackendTexture result = this->createBackendTexture(c.width(), c.height(), format, color,
+                                                         GrMipMapped(c.isMipMapped()),
+                                                         GrRenderable::kYes,
+                                                         GrProtected::kNo);
+    SkASSERT(c.isCompatible(result));
+    return result;
+}
+
 GrBackendTexture GrContext::createBackendTexture(int width, int height,
                                                  const GrBackendFormat& backendFormat,
                                                  const SkColor4f& color,
@@ -406,8 +483,8 @@
         return GrBackendTexture();
     }
 
-    return this->createBackendTexture(width, height, format, color, mipMapped, renderable,
-                                      isProtected);
+    return this->createBackendTexture(width, height, format, color,
+                                      mipMapped, renderable, isProtected);
 }
 
 void GrContext::deleteBackendTexture(GrBackendTexture backendTex) {
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 3fdf762..c30490b 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1519,7 +1519,7 @@
 
 static void set_image_layout(const GrVkInterface* vkInterface, VkCommandBuffer cmdBuffer,
                              GrVkImageInfo* info, VkImageLayout newLayout, uint32_t mipLevels,
-                             VkAccessFlagBits dstAccessMask, VkPipelineStageFlagBits dstStageMask) {
+                             VkAccessFlags dstAccessMask, VkPipelineStageFlagBits dstStageMask) {
     VkAccessFlags srcAccessMask = GrVkImage::LayoutToSrcAccessMask(info->fImageLayout);
     VkPipelineStageFlags srcStageMask = GrVkImage::LayoutToPipelineSrcStageFlags(
                                                                               info->fImageLayout);
@@ -1744,8 +1744,18 @@
     VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, info->fImage, info->fImageLayout,
                                  regions.count(), regions.begin()));
 
-    if (texturable) {
-        // Change Image layout to shader read since if we use this texture as a borrowed
+    if (!srcData && renderable) {
+        SkASSERT(color);
+
+        // Change image layout to color-attachment-optimal since if we use this texture as a
+        // borrowed texture within Ganesh we are probably going to render to it
+        set_image_layout(this->vkInterface(), cmdBuffer, info,
+                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, mipLevels,
+                         VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                         VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+    } else if (texturable) {
+        // Change image layout to shader read since if we use this texture as a borrowed
         // texture within Ganesh we require that its layout be set to that
         set_image_layout(this->vkInterface(), cmdBuffer, info,
                          VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, mipLevels,
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 81653d5..9fdc4ae 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -404,6 +404,86 @@
     return result;
 }
 
+static bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex,
+                                     GrPixelConfig* config, int sampleCnt, SkColorType ct,
+                                     bool texturable) {
+    if (!tex.isValid()) {
+        return false;
+    }
+
+    GrBackendFormat backendFormat = tex.getBackendFormat();
+    if (!backendFormat.isValid()) {
+        return false;
+    }
+    *config = ctx->priv().caps()->getConfigFromBackendFormat(backendFormat, ct);
+    if (*config == kUnknown_GrPixelConfig) {
+        return false;
+    }
+
+    // We don't require that the client gave us an exact valid sample cnt. However, it must be
+    // less than the max supported sample count and 1 if MSAA is unsupported for the color type.
+    if (!ctx->priv().caps()->getRenderTargetSampleCount(sampleCnt, ct, backendFormat)) {
+        return false;
+    }
+
+    if (texturable && !ctx->priv().caps()->isFormatTexturable(ct, backendFormat)) {
+        return false;
+    }
+    return true;
+}
+
+sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context,
+                                                   const SkSurfaceCharacterization& c,
+                                                   const GrBackendTexture& backendTexture,
+                                                   TextureReleaseProc textureReleaseProc,
+                                                   ReleaseContext releaseContext) {
+    if (!context || !c.isValid()) {
+        return nullptr;
+    }
+
+    if (c.usesGLFBO0()) {
+        // If we are making the surface we will never use FBO0.
+        return nullptr;
+    }
+
+    if (!c.isCompatible(backendTexture)) {
+        return nullptr;
+    }
+
+    GrBackendTexture texCopy = backendTexture;
+    if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
+                                  c.sampleCount(), c.colorType(), true)) {
+        return nullptr;
+    }
+
+    if (!SkSurface_Gpu::Valid(context->priv().caps(), texCopy.getBackendFormat())) {
+        return nullptr;
+    }
+
+    sk_sp<GrRenderTargetContext> rtc(context->priv().makeBackendTextureRenderTargetContext(
+                texCopy, c.origin(), c.sampleCount(), SkColorTypeToGrColorType(c.colorType()),
+                c.refColorSpace(), &c.surfaceProps(), textureReleaseProc, releaseContext));
+    if (!rtc) {
+        return nullptr;
+    }
+
+    sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc),
+                                                texCopy.width(), texCopy.height(),
+                                                SkGpuDevice::kUninit_InitContents));
+    if (!device) {
+        return nullptr;
+    }
+
+    sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
+#ifdef SK_DEBUG
+    if (result) {
+        SkASSERT(result->isCompatible(c));
+    }
+#endif
+
+    return result;
+}
+
 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
                                              const SkImageInfo& info, int sampleCount,
                                              GrSurfaceOrigin origin, const SkSurfaceProps* props,
@@ -444,34 +524,6 @@
     return sk_make_sp<SkSurface_Gpu>(std::move(device));
 }
 
-static bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex,
-                                     GrPixelConfig* config, int sampleCnt, SkColorType ct,
-                                     bool texturable) {
-    if (!tex.isValid()) {
-        return false;
-    }
-
-    GrBackendFormat backendFormat = tex.getBackendFormat();
-    if (!backendFormat.isValid()) {
-        return false;
-    }
-    *config = ctx->priv().caps()->getConfigFromBackendFormat(backendFormat, ct);
-    if (*config == kUnknown_GrPixelConfig) {
-        return false;
-    }
-
-    // We don't require that the client gave us an exact valid sample cnt. However, it must be
-    // less than the max supported sample count and 1 if MSAA is unsupported for the color type.
-    if (!ctx->priv().caps()->getRenderTargetSampleCount(sampleCnt, ct, backendFormat)) {
-        return false;
-    }
-
-    if (texturable && !ctx->priv().caps()->isFormatTexturable(ct, backendFormat)) {
-        return false;
-    }
-    return true;
-}
-
 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
                                                    GrSurfaceOrigin origin, int sampleCnt,
                                                    SkColorType colorType,