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