1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkSurface_Gpu.h"
9 #include "GrBackendSurface.h"
10 #include "GrCaps.h"
11 #include "GrContextPriv.h"
12 #include "GrRenderTarget.h"
13 #include "GrRenderTargetContextPriv.h"
14 #include "GrRenderTargetProxyPriv.h"
15 #include "GrTexture.h"
16 #include "SkCanvas.h"
17 #include "SkDeferredDisplayList.h"
18 #include "SkGpuDevice.h"
19 #include "SkImagePriv.h"
20 #include "SkImage_Base.h"
21 #include "SkImage_Gpu.h"
22 #include "SkSurfaceCharacterization.h"
23 #include "SkSurface_Base.h"
24 
25 #if SK_SUPPORT_GPU
26 
SkSurface_Gpu(sk_sp<SkGpuDevice> device)27 SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
28     : INHERITED(device->width(), device->height(), &device->surfaceProps())
29     , fDevice(std::move(device)) {
30     SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
31 }
32 
~SkSurface_Gpu()33 SkSurface_Gpu::~SkSurface_Gpu() {
34 }
35 
prepare_rt_for_external_access(SkSurface_Gpu * surface,SkSurface::BackendHandleAccess access)36 static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
37                                                       SkSurface::BackendHandleAccess access) {
38     switch (access) {
39         case SkSurface::kFlushRead_BackendHandleAccess:
40             break;
41         case SkSurface::kFlushWrite_BackendHandleAccess:
42         case SkSurface::kDiscardWrite_BackendHandleAccess:
43             // for now we don't special-case on Discard, but we may in the future.
44             surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
45             break;
46     }
47 
48     // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
49     surface->getDevice()->flush();
50     GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
51     return rtc->accessRenderTarget();
52 }
53 
onGetBackendTexture(BackendHandleAccess access)54 GrBackendTexture SkSurface_Gpu::onGetBackendTexture(BackendHandleAccess access) {
55     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
56     if (!rt) {
57         return GrBackendTexture(); // invalid
58     }
59     GrTexture* texture = rt->asTexture();
60     if (texture) {
61         return texture->getBackendTexture();
62     }
63     return GrBackendTexture(); // invalid
64 }
65 
onGetBackendRenderTarget(BackendHandleAccess access)66 GrBackendRenderTarget SkSurface_Gpu::onGetBackendRenderTarget(BackendHandleAccess access) {
67     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
68     if (!rt) {
69         return GrBackendRenderTarget(); // invalid
70     }
71 
72     return rt->getBackendRenderTarget();
73 }
74 
onNewCanvas()75 SkCanvas* SkSurface_Gpu::onNewCanvas() { return new SkCanvas(fDevice); }
76 
onNewSurface(const SkImageInfo & info)77 sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
78     int sampleCount = fDevice->accessRenderTargetContext()->numColorSamples();
79     GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin();
80     // TODO: Make caller specify this (change virtual signature of onNewSurface).
81     static const SkBudgeted kBudgeted = SkBudgeted::kNo;
82     return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
83                                        origin, &this->props());
84 }
85 
onNewImageSnapshot(const SkIRect * subset)86 sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot(const SkIRect* subset) {
87     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
88     if (!rtc) {
89         return nullptr;
90     }
91 
92     GrContext* ctx = fDevice->context();
93 
94     if (!rtc->asSurfaceProxy()) {
95         return nullptr;
96     }
97 
98     SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
99 
100     sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
101 
102     if (subset) {
103         srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(), *subset,
104                                         SkBackingFit::kExact, budgeted);
105     } else if (!srcProxy || rtc->priv().refsWrappedObjects()) {
106         // If the original render target is a buffer originally created by the client, then we don't
107         // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
108         // copy-on-write.
109         SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
110 
111         srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(),
112                                         SkBackingFit::kExact, budgeted);
113     }
114 
115     const SkImageInfo info = fDevice->imageInfo();
116     sk_sp<SkImage> image;
117     if (srcProxy) {
118         // The renderTargetContext coming out of SkGpuDevice should always be exact and the
119         // above copy creates a kExact surfaceContext.
120         SkASSERT(srcProxy->priv().isExact());
121         image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, info.alphaType(),
122                                         std::move(srcProxy), info.refColorSpace());
123     }
124     return image;
125 }
126 
onWritePixels(const SkPixmap & src,int x,int y)127 void SkSurface_Gpu::onWritePixels(const SkPixmap& src, int x, int y) {
128     fDevice->writePixels(src, x, y);
129 }
130 
131 // Create a new render target and, if necessary, copy the contents of the old
132 // render target into it. Note that this flushes the SkGpuDevice but
133 // doesn't force an OpenGL flush.
onCopyOnWrite(ContentChangeMode mode)134 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
135     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
136 
137     // are we sharing our backing proxy with the image? Note this call should never create a new
138     // image because onCopyOnWrite is only called when there is a cached image.
139     sk_sp<SkImage> image(this->refCachedImage());
140     SkASSERT(image);
141 
142     GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
143     SkASSERT(imageProxy);
144 
145     if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
146         fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
147     } else if (kDiscard_ContentChangeMode == mode) {
148         this->SkSurface_Gpu::onDiscard();
149     }
150 }
151 
onDiscard()152 void SkSurface_Gpu::onDiscard() {
153     fDevice->accessRenderTargetContext()->discard();
154 }
155 
onFlush(int numSemaphores,GrBackendSemaphore signalSemaphores[])156 GrSemaphoresSubmitted SkSurface_Gpu::onFlush(int numSemaphores,
157                                              GrBackendSemaphore signalSemaphores[]) {
158     return fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
159 }
160 
onWait(int numSemaphores,const GrBackendSemaphore * waitSemaphores)161 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
162     return fDevice->wait(numSemaphores, waitSemaphores);
163 }
164 
onCharacterize(SkSurfaceCharacterization * characterization) const165 bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* characterization) const {
166     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
167     GrContext* ctx = fDevice->context();
168 
169     int maxResourceCount;
170     size_t maxResourceBytes;
171     ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
172 
173     bool mipmapped = rtc->asTextureProxy() ? GrMipMapped::kYes == rtc->asTextureProxy()->mipMapped()
174                                            : false;
175 
176     // TODO: the addition of colorType to the surfaceContext should remove this calculation
177     SkColorType ct;
178     if (!GrPixelConfigToColorType(rtc->colorSpaceInfo().config(), &ct)) {
179         return false;
180     }
181 
182     bool usesGLFBO0 = rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0();
183     // We should never get in the situation where we have a texture render target that is also
184     // backend by FBO 0.
185     SkASSERT(!usesGLFBO0 || !SkToBool(rtc->asTextureProxy()));
186 
187     SkImageInfo ii = SkImageInfo::Make(rtc->width(), rtc->height(), ct, kPremul_SkAlphaType,
188                                        rtc->colorSpaceInfo().refColorSpace());
189 
190     characterization->set(ctx->threadSafeProxy(), maxResourceBytes, ii, rtc->origin(),
191                           rtc->colorSpaceInfo().config(), rtc->fsaaType(), rtc->numStencilSamples(),
192                           SkSurfaceCharacterization::Textureable(SkToBool(rtc->asTextureProxy())),
193                           SkSurfaceCharacterization::MipMapped(mipmapped),
194                           SkSurfaceCharacterization::UsesGLFBO0(usesGLFBO0),
195                           SkSurfaceCharacterization::VulkanSecondaryCBCompatible(false),
196                           this->props());
197 
198     return true;
199 }
200 
isCompatible(const SkSurfaceCharacterization & characterization) const201 bool SkSurface_Gpu::isCompatible(const SkSurfaceCharacterization& characterization) const {
202     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
203     GrContext* ctx = fDevice->context();
204 
205     if (!characterization.isValid()) {
206         return false;
207     }
208 
209     // As long as the current state if the context allows for greater or equal resources,
210     // we allow the DDL to be replayed.
211     // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
212     int maxResourceCount;
213     size_t maxResourceBytes;
214     ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
215 
216     if (characterization.isTextureable()) {
217         if (!rtc->asTextureProxy()) {
218             // If the characterization was textureable we require the replay dest to also be
219             // textureable. If the characterized surface wasn't textureable we allow the replay
220             // dest to be textureable.
221             return false;
222         }
223 
224         if (characterization.isMipMapped() &&
225             GrMipMapped::kNo == rtc->asTextureProxy()->mipMapped()) {
226             // Fail if the DDL's surface was mipmapped but the replay surface is not.
227             // Allow drawing to proceed if the DDL was not mipmapped but the replay surface is.
228             return false;
229         }
230     }
231 
232     if (characterization.usesGLFBO0() != rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0()) {
233         return false;
234     }
235 
236     // TODO: the addition of colorType to the surfaceContext should remove this calculation
237     SkColorType rtcColorType;
238     if (!GrPixelConfigToColorType(rtc->colorSpaceInfo().config(), &rtcColorType)) {
239         return false;
240     }
241 
242     return characterization.contextInfo() && characterization.contextInfo()->matches(ctx) &&
243            characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
244            characterization.origin() == rtc->origin() &&
245            characterization.config() == rtc->colorSpaceInfo().config() &&
246            characterization.width() == rtc->width() &&
247            characterization.height() == rtc->height() &&
248            characterization.colorType() == rtcColorType &&
249            characterization.fsaaType() == rtc->fsaaType() &&
250            characterization.stencilCount() == rtc->numStencilSamples() &&
251            SkColorSpace::Equals(characterization.colorSpace(),
252                                 rtc->colorSpaceInfo().colorSpace()) &&
253            characterization.surfaceProps() == rtc->surfaceProps();
254 }
255 
onDraw(const SkDeferredDisplayList * ddl)256 bool SkSurface_Gpu::onDraw(const SkDeferredDisplayList* ddl) {
257     if (!ddl || !this->isCompatible(ddl->characterization())) {
258         return false;
259     }
260 
261     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
262     GrContext* ctx = fDevice->context();
263 
264     ctx->contextPriv().copyOpListsFromDDL(ddl, rtc->asRenderTargetProxy());
265     return true;
266 }
267 
268 
269 ///////////////////////////////////////////////////////////////////////////////
270 
Valid(const SkImageInfo & info)271 bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
272     return true;
273 }
274 
Valid(const GrCaps * caps,GrPixelConfig config,SkColorSpace * colorSpace)275 bool SkSurface_Gpu::Valid(const GrCaps* caps, GrPixelConfig config, SkColorSpace* colorSpace) {
276     switch (config) {
277         case kSRGBA_8888_GrPixelConfig:
278         case kSBGRA_8888_GrPixelConfig:
279             return caps->srgbSupport();
280         default:
281             return true;
282     }
283 }
284 
MakeRenderTarget(GrContext * context,const SkSurfaceCharacterization & c,SkBudgeted budgeted)285 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* context,
286                                              const SkSurfaceCharacterization& c,
287                                              SkBudgeted budgeted) {
288     if (!context || !c.isValid()) {
289         return nullptr;
290     }
291 
292     if (c.usesGLFBO0()) {
293         // If we are making the surface we will never use FBO0.
294         return nullptr;
295     }
296 
297     if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), c.config(), c.colorSpace())) {
298         return nullptr;
299     }
300 
301     // In order to ensure compatibility we have to match the backend format (i.e. the GrPixelConfig
302     // of the characterization)
303     GrSurfaceDesc desc;
304     desc.fFlags = kRenderTarget_GrSurfaceFlag;
305     desc.fWidth = c.width();
306     desc.fHeight = c.height();
307     desc.fConfig = c.config();
308     desc.fSampleCnt = c.stencilCount();
309 
310     const GrBackendFormat format =
311             context->contextPriv().caps()->getBackendFormatFromColorType(c.colorType());
312 
313     sk_sp<GrSurfaceContext> sc(
314             context->contextPriv().makeDeferredSurfaceContext(format, desc, c.origin(),
315                                                               GrMipMapped(c.isMipMapped()),
316                                                               SkBackingFit::kExact, budgeted,
317                                                               c.refColorSpace(),
318                                                               &c.surfaceProps()));
319     if (!sc || !sc->asRenderTargetContext()) {
320         return nullptr;
321     }
322 
323     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, sk_ref_sp(sc->asRenderTargetContext()),
324                                                 c.width(), c.height(),
325                                                 SkGpuDevice::kClear_InitContents));
326     if (!device) {
327         return nullptr;
328     }
329 
330     sk_sp<SkSurface> s = sk_make_sp<SkSurface_Gpu>(std::move(device));
331 #ifdef SK_DEBUG
332     if (s) {
333         SkSurface_Gpu* gpuSurface = static_cast<SkSurface_Gpu*>(s.get());
334         SkASSERT(gpuSurface->isCompatible(c));
335     }
336 #endif
337 
338     return s;
339 }
340 
341 
MakeRenderTarget(GrContext * ctx,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,bool shouldCreateWithMips)342 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
343                                              const SkImageInfo& info, int sampleCount,
344                                              GrSurfaceOrigin origin, const SkSurfaceProps* props,
345                                              bool shouldCreateWithMips) {
346     if (!ctx) {
347         return nullptr;
348     }
349     if (!SkSurface_Gpu::Valid(info)) {
350         return nullptr;
351     }
352     sampleCount = SkTMax(1, sampleCount);
353     GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
354 
355     if (!ctx->contextPriv().caps()->mipMapSupport()) {
356         mipMapped = GrMipMapped::kNo;
357     }
358 
359     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
360             ctx, budgeted, info, sampleCount, origin, props, mipMapped,
361             SkGpuDevice::kClear_InitContents));
362     if (!device) {
363         return nullptr;
364     }
365     return sk_make_sp<SkSurface_Gpu>(std::move(device));
366 }
367 
MakeWrappedRenderTarget(GrContext * context,sk_sp<GrRenderTargetContext> rtc)368 sk_sp<SkSurface> SkSurface_Gpu::MakeWrappedRenderTarget(GrContext* context,
369                                                         sk_sp<GrRenderTargetContext> rtc) {
370     if (!context) {
371         return nullptr;
372     }
373 
374     int w = rtc->width();
375     int h = rtc->height();
376     sk_sp<SkGpuDevice> device(
377             SkGpuDevice::Make(context, std::move(rtc), w, h, SkGpuDevice::kUninit_InitContents));
378     if (!device) {
379         return nullptr;
380     }
381 
382     return sk_make_sp<SkSurface_Gpu>(std::move(device));
383 }
384 
validate_backend_texture(GrContext * ctx,const GrBackendTexture & tex,GrPixelConfig * config,int sampleCnt,SkColorType ct,sk_sp<SkColorSpace> cs,bool texturable)385 bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
386                               int sampleCnt, SkColorType ct, sk_sp<SkColorSpace> cs,
387                               bool texturable) {
388     if (!tex.isValid()) {
389         return false;
390     }
391     // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
392     // create a fake image info here.
393     SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
394 
395     if (!SkSurface_Gpu::Valid(info)) {
396         return false;
397     }
398 
399     GrBackendFormat backendFormat = tex.getBackendFormat();
400     if (!backendFormat.isValid()) {
401         return false;
402     }
403     *config = ctx->contextPriv().caps()->getConfigFromBackendFormat(backendFormat, ct);
404     if (*config == kUnknown_GrPixelConfig) {
405         return false;
406     }
407 
408     // We don't require that the client gave us an exact valid sample cnt. However, it must be
409     // less than the max supported sample count and 1 if MSAA is unsupported for the color type.
410     if (!ctx->contextPriv().caps()->getRenderTargetSampleCount(sampleCnt, *config)) {
411         return false;
412     }
413 
414     if (texturable && !ctx->contextPriv().caps()->isConfigTexturable(*config)) {
415         return false;
416     }
417     return true;
418 }
419 
MakeFromBackendTexture(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)420 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
421                                                    GrSurfaceOrigin origin, int sampleCnt,
422                                                    SkColorType colorType,
423                                                    sk_sp<SkColorSpace> colorSpace,
424                                                    const SkSurfaceProps* props) {
425     if (!context) {
426         return nullptr;
427     }
428     sampleCnt = SkTMax(1, sampleCnt);
429     GrBackendTexture texCopy = tex;
430     if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
431                                   sampleCnt, colorType, colorSpace, true)) {
432         return nullptr;
433     }
434 
435     if (!context) {
436         return nullptr;
437     }
438     if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), texCopy.config(), colorSpace.get())) {
439         return nullptr;
440     }
441     sampleCnt = SkTMax(1, sampleCnt);
442 
443     sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext(
444         texCopy,
445         origin,
446         sampleCnt,
447         std::move(colorSpace),
448         props));
449     if (!rtc) {
450         return nullptr;
451     }
452 
453     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), texCopy.width(),
454                                                 texCopy.height(),
455                                                 SkGpuDevice::kUninit_InitContents));
456     if (!device) {
457         return nullptr;
458     }
459     return sk_make_sp<SkSurface_Gpu>(std::move(device));
460 }
461 
validate_backend_render_target(GrContext * ctx,const GrBackendRenderTarget & rt,GrPixelConfig * config,SkColorType ct,sk_sp<SkColorSpace> cs)462 bool validate_backend_render_target(GrContext* ctx, const GrBackendRenderTarget& rt,
463                                     GrPixelConfig* config, SkColorType ct, sk_sp<SkColorSpace> cs) {
464     // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
465     // create a fake image info here.
466     SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
467 
468     if (!SkSurface_Gpu::Valid(info)) {
469         return false;
470     }
471 
472     *config = ctx->contextPriv().caps()->validateBackendRenderTarget(rt, ct);
473     if (*config == kUnknown_GrPixelConfig) {
474         return false;
475     }
476 
477     if (rt.sampleCnt() > 1) {
478         if (ctx->contextPriv().caps()->maxRenderTargetSampleCount(*config) <= 1) {
479             return false;
480         }
481     } else if (!ctx->contextPriv().caps()->isConfigRenderable(*config)) {
482         return false;
483     }
484 
485     return true;
486 }
487 
MakeFromBackendRenderTarget(GrContext * context,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)488 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
489                                                         const GrBackendRenderTarget& rt,
490                                                         GrSurfaceOrigin origin,
491                                                         SkColorType colorType,
492                                                         sk_sp<SkColorSpace> colorSpace,
493                                                         const SkSurfaceProps* props) {
494     if (!context) {
495         return nullptr;
496     }
497 
498     GrBackendRenderTarget rtCopy = rt;
499     if (!validate_backend_render_target(context, rtCopy, &rtCopy.fConfig, colorType, colorSpace)) {
500         return nullptr;
501     }
502     if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), rtCopy.config(), colorSpace.get())) {
503         return nullptr;
504     }
505 
506     if (!context) {
507         return nullptr;
508     }
509 
510     sk_sp<GrRenderTargetContext> rtc(
511             context->contextPriv().makeBackendRenderTargetRenderTargetContext(
512                     rtCopy, origin, std::move(colorSpace), props));
513     if (!rtc) {
514         return nullptr;
515     }
516 
517     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), rtCopy.width(),
518                                                 rtCopy.height(),
519                                                 SkGpuDevice::kUninit_InitContents));
520     if (!device) {
521         return nullptr;
522     }
523 
524     return sk_make_sp<SkSurface_Gpu>(std::move(device));
525 }
526 
MakeFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)527 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
528                                                                  const GrBackendTexture& tex,
529                                                                  GrSurfaceOrigin origin,
530                                                                  int sampleCnt,
531                                                                  SkColorType colorType,
532                                                                  sk_sp<SkColorSpace> colorSpace,
533                                                                  const SkSurfaceProps* props) {
534     if (!context) {
535         return nullptr;
536     }
537 
538     sampleCnt = SkTMax(1, sampleCnt);
539     GrBackendTexture texCopy = tex;
540     if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
541                                   sampleCnt, colorType, colorSpace, false)) {
542         return nullptr;
543     }
544 
545     if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), texCopy.config(), colorSpace.get())) {
546         return nullptr;
547     }
548 
549     sk_sp<GrRenderTargetContext> rtc(
550         context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext(
551             texCopy,
552             origin,
553             sampleCnt,
554             std::move(colorSpace),
555             props));
556     if (!rtc) {
557         return nullptr;
558     }
559 
560     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
561                                                 SkGpuDevice::kUninit_InitContents));
562     if (!device) {
563         return nullptr;
564     }
565     return sk_make_sp<SkSurface_Gpu>(std::move(device));
566 }
567 
568 #endif
569