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 "include/core/SkCanvas.h"
9 #include "include/core/SkSurfaceCharacterization.h"
10 #include "include/gpu/GrBackendSurface.h"
11 #include "include/gpu/GrTexture.h"
12 #include "include/private/GrRecordingContext.h"
13 #include "include/private/SkDeferredDisplayList.h"
14 #include "src/core/SkImagePriv.h"
15 #include "src/gpu/GrAHardwareBufferUtils.h"
16 #include "src/gpu/GrCaps.h"
17 #include "src/gpu/GrContextPriv.h"
18 #include "src/gpu/GrContextThreadSafeProxyPriv.h"
19 #include "src/gpu/GrRecordingContextPriv.h"
20 #include "src/gpu/GrRenderTarget.h"
21 #include "src/gpu/GrRenderTargetContextPriv.h"
22 #include "src/gpu/GrRenderTargetProxyPriv.h"
23 #include "src/gpu/SkGpuDevice.h"
24 #include "src/image/SkImage_Base.h"
25 #include "src/image/SkImage_Gpu.h"
26 #include "src/image/SkSurface_Base.h"
27 #include "src/image/SkSurface_Gpu.h"
28
29 #if SK_SUPPORT_GPU
30
SkSurface_Gpu(sk_sp<SkGpuDevice> device)31 SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
32 : INHERITED(device->width(), device->height(), &device->surfaceProps())
33 , fDevice(std::move(device)) {
34 SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
35 }
36
~SkSurface_Gpu()37 SkSurface_Gpu::~SkSurface_Gpu() {
38 }
39
prepare_rt_for_external_access(SkSurface_Gpu * surface,SkSurface::BackendHandleAccess access)40 static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
41 SkSurface::BackendHandleAccess access) {
42 switch (access) {
43 case SkSurface::kFlushRead_BackendHandleAccess:
44 break;
45 case SkSurface::kFlushWrite_BackendHandleAccess:
46 case SkSurface::kDiscardWrite_BackendHandleAccess:
47 // for now we don't special-case on Discard, but we may in the future.
48 surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
49 break;
50 }
51
52 // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
53 surface->getDevice()->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo());
54 GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
55 return rtc->accessRenderTarget();
56 }
57
onGetBackendTexture(BackendHandleAccess access)58 GrBackendTexture SkSurface_Gpu::onGetBackendTexture(BackendHandleAccess access) {
59 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
60 if (!rt) {
61 return GrBackendTexture(); // invalid
62 }
63 GrTexture* texture = rt->asTexture();
64 if (texture) {
65 return texture->getBackendTexture();
66 }
67 return GrBackendTexture(); // invalid
68 }
69
onGetBackendRenderTarget(BackendHandleAccess access)70 GrBackendRenderTarget SkSurface_Gpu::onGetBackendRenderTarget(BackendHandleAccess access) {
71 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
72 if (!rt) {
73 return GrBackendRenderTarget(); // invalid
74 }
75
76 return rt->getBackendRenderTarget();
77 }
78
onNewCanvas()79 SkCanvas* SkSurface_Gpu::onNewCanvas() { return new SkCanvas(fDevice); }
80
onNewSurface(const SkImageInfo & info)81 sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
82 int sampleCount = fDevice->accessRenderTargetContext()->numSamples();
83 GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin();
84 // TODO: Make caller specify this (change virtual signature of onNewSurface).
85 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
86 return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
87 origin, &this->props());
88 }
89
onNewImageSnapshot(const SkIRect * subset)90 sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot(const SkIRect* subset) {
91 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
92 if (!rtc) {
93 return nullptr;
94 }
95
96 GrContext* ctx = fDevice->context();
97
98 if (!rtc->asSurfaceProxy()) {
99 return nullptr;
100 }
101
102 SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
103
104 sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
105
106 if (subset) {
107 srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->colorInfo().colorType(),
108 rtc->mipMapped(), *subset, SkBackingFit::kExact, budgeted);
109 } else if (!srcProxy || rtc->priv().refsWrappedObjects()) {
110 // If the original render target is a buffer originally created by the client, then we don't
111 // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
112 // copy-on-write.
113 SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
114
115 srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->colorInfo().colorType(),
116 rtc->mipMapped(), SkBackingFit::kExact, budgeted);
117 }
118
119 const SkImageInfo info = fDevice->imageInfo();
120 sk_sp<SkImage> image;
121 if (srcProxy) {
122 // The renderTargetContext coming out of SkGpuDevice should always be exact and the
123 // above copy creates a kExact surfaceContext.
124 SkASSERT(srcProxy->priv().isExact());
125 image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, info.alphaType(),
126 std::move(srcProxy), info.refColorSpace());
127 }
128 return image;
129 }
130
onWritePixels(const SkPixmap & src,int x,int y)131 void SkSurface_Gpu::onWritePixels(const SkPixmap& src, int x, int y) {
132 fDevice->writePixels(src, x, y);
133 }
134
onAsyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,SkFilterQuality rescaleQuality,ReadPixelsCallback callback,ReadPixelsContext context)135 void SkSurface_Gpu::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
136 const SkIRect& srcRect,
137 RescaleGamma rescaleGamma,
138 SkFilterQuality rescaleQuality,
139 ReadPixelsCallback callback,
140 ReadPixelsContext context) {
141 auto* rtc = this->fDevice->accessRenderTargetContext();
142 rtc->asyncRescaleAndReadPixels(info, srcRect, rescaleGamma, rescaleQuality, callback, context);
143 }
144
onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,RescaleGamma rescaleGamma,SkFilterQuality rescaleQuality,ReadPixelsCallback callback,ReadPixelsContext context)145 void SkSurface_Gpu::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
146 sk_sp<SkColorSpace> dstColorSpace,
147 const SkIRect& srcRect,
148 const SkISize& dstSize,
149 RescaleGamma rescaleGamma,
150 SkFilterQuality rescaleQuality,
151 ReadPixelsCallback callback,
152 ReadPixelsContext context) {
153 auto* rtc = this->fDevice->accessRenderTargetContext();
154 rtc->asyncRescaleAndReadPixelsYUV420(yuvColorSpace,
155 std::move(dstColorSpace),
156 srcRect,
157 dstSize,
158 rescaleGamma,
159 rescaleQuality,
160 callback,
161 context);
162 }
163
164 // Create a new render target and, if necessary, copy the contents of the old
165 // render target into it. Note that this flushes the SkGpuDevice but
166 // doesn't force an OpenGL flush.
onCopyOnWrite(ContentChangeMode mode)167 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
168 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
169
170 // are we sharing our backing proxy with the image? Note this call should never create a new
171 // image because onCopyOnWrite is only called when there is a cached image.
172 sk_sp<SkImage> image(this->refCachedImage());
173 SkASSERT(image);
174
175 GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
176 SkASSERT(imageProxy);
177
178 if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
179 fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
180 } else if (kDiscard_ContentChangeMode == mode) {
181 this->SkSurface_Gpu::onDiscard();
182 }
183 }
184
onDiscard()185 void SkSurface_Gpu::onDiscard() {
186 fDevice->accessRenderTargetContext()->discard();
187 }
188
onFlush(BackendSurfaceAccess access,const GrFlushInfo & info)189 GrSemaphoresSubmitted SkSurface_Gpu::onFlush(BackendSurfaceAccess access,
190 const GrFlushInfo& info) {
191 return fDevice->flush(access, info);
192 }
193
onWait(int numSemaphores,const GrBackendSemaphore * waitSemaphores)194 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
195 return fDevice->wait(numSemaphores, waitSemaphores);
196 }
197
onCharacterize(SkSurfaceCharacterization * characterization) const198 bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* characterization) const {
199 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
200 GrContext* ctx = fDevice->context();
201
202 size_t maxResourceBytes = ctx->getResourceCacheLimit();
203
204 bool mipmapped = rtc->asTextureProxy() ? GrMipMapped::kYes == rtc->asTextureProxy()->mipMapped()
205 : false;
206
207 SkColorType ct = GrColorTypeToSkColorType(rtc->colorInfo().colorType());
208 if (ct == kUnknown_SkColorType) {
209 return false;
210 }
211
212 bool usesGLFBO0 = rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0();
213 // We should never get in the situation where we have a texture render target that is also
214 // backend by FBO 0.
215 SkASSERT(!usesGLFBO0 || !SkToBool(rtc->asTextureProxy()));
216
217 SkImageInfo ii = SkImageInfo::Make(rtc->width(), rtc->height(), ct, kPremul_SkAlphaType,
218 rtc->colorInfo().refColorSpace());
219
220 GrBackendFormat format = rtc->asSurfaceProxy()->backendFormat();
221
222 characterization->set(ctx->threadSafeProxy(), maxResourceBytes, ii, format,
223 rtc->origin(), rtc->numSamples(),
224 SkSurfaceCharacterization::Textureable(SkToBool(rtc->asTextureProxy())),
225 SkSurfaceCharacterization::MipMapped(mipmapped),
226 SkSurfaceCharacterization::UsesGLFBO0(usesGLFBO0),
227 SkSurfaceCharacterization::VulkanSecondaryCBCompatible(false),
228 GrProtected(rtc->asRenderTargetProxy()->isProtected()),
229 this->props());
230 return true;
231 }
232
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkPaint * paint)233 void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
234 // If the dst is also GPU we try to not force a new image snapshot (by calling the base class
235 // onDraw) since that may not always perform the copy-on-write optimization.
236 auto tryDraw = [&] {
237 SkASSERT(fDevice->context()->priv().asDirectContext());
238 GrContext* context = fDevice->context();
239 GrContext* canvasContext = canvas->getGrContext();
240 if (!canvasContext) {
241 return false;
242 }
243 if (!canvasContext->priv().asDirectContext() ||
244 canvasContext->priv().contextID() != context->priv().contextID()) {
245 return false;
246 }
247 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
248 if (!rtc) {
249 return false;
250 }
251 sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
252 if (!srcProxy) {
253 return false;
254 }
255 // Possibly we could skip making an image here if SkGpuDevice exposed a lower level way
256 // of drawing a texture proxy.
257 const SkImageInfo info = fDevice->imageInfo();
258 sk_sp<SkImage> image;
259 image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, info.alphaType(),
260 std::move(srcProxy), info.refColorSpace());
261 canvas->drawImage(image, x, y, paint);
262 return true;
263 };
264 if (!tryDraw()) {
265 INHERITED::onDraw(canvas, x, y, paint);
266 }
267 }
268
onIsCompatible(const SkSurfaceCharacterization & characterization) const269 bool SkSurface_Gpu::onIsCompatible(const SkSurfaceCharacterization& characterization) const {
270 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
271 GrContext* ctx = fDevice->context();
272
273 if (!characterization.isValid()) {
274 return false;
275 }
276
277 if (characterization.vulkanSecondaryCBCompatible()) {
278 return false;
279 }
280
281 // As long as the current state if the context allows for greater or equal resources,
282 // we allow the DDL to be replayed.
283 // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
284 size_t maxResourceBytes = ctx->getResourceCacheLimit();
285
286 if (characterization.isTextureable()) {
287 if (!rtc->asTextureProxy()) {
288 // If the characterization was textureable we require the replay dest to also be
289 // textureable. If the characterized surface wasn't textureable we allow the replay
290 // dest to be textureable.
291 return false;
292 }
293
294 if (characterization.isMipMapped() &&
295 GrMipMapped::kNo == rtc->asTextureProxy()->mipMapped()) {
296 // Fail if the DDL's surface was mipmapped but the replay surface is not.
297 // Allow drawing to proceed if the DDL was not mipmapped but the replay surface is.
298 return false;
299 }
300 }
301
302 if (characterization.usesGLFBO0() != rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0()) {
303 return false;
304 }
305
306 SkColorType rtcColorType = GrColorTypeToSkColorType(rtc->colorInfo().colorType());
307 if (rtcColorType == kUnknown_SkColorType) {
308 return false;
309 }
310
311 GrProtected isProtected = GrProtected(rtc->asSurfaceProxy()->isProtected());
312
313 return characterization.contextInfo() && characterization.contextInfo()->priv().matches(ctx) &&
314 characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
315 characterization.origin() == rtc->origin() &&
316 characterization.backendFormat() == rtc->asSurfaceProxy()->backendFormat() &&
317 characterization.width() == rtc->width() && characterization.height() == rtc->height() &&
318 characterization.colorType() == rtcColorType &&
319 characterization.sampleCount() == rtc->numSamples() &&
320 SkColorSpace::Equals(characterization.colorSpace(), rtc->colorInfo().colorSpace()) &&
321 characterization.isProtected() == isProtected &&
322 characterization.surfaceProps() == rtc->surfaceProps();
323 }
324
onDraw(const SkDeferredDisplayList * ddl)325 bool SkSurface_Gpu::onDraw(const SkDeferredDisplayList* ddl) {
326 if (!ddl || !this->isCompatible(ddl->characterization())) {
327 return false;
328 }
329
330 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
331 GrContext* ctx = fDevice->context();
332
333 ctx->priv().copyRenderTasksFromDDL(ddl, rtc->asRenderTargetProxy());
334 return true;
335 }
336
337
338 ///////////////////////////////////////////////////////////////////////////////
339
MakeRenderTarget(GrRecordingContext * context,const SkSurfaceCharacterization & c,SkBudgeted budgeted)340 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext* context,
341 const SkSurfaceCharacterization& c,
342 SkBudgeted budgeted) {
343 if (!context || !c.isValid()) {
344 return nullptr;
345 }
346
347 if (c.usesGLFBO0()) {
348 // If we are making the surface we will never use FBO0.
349 return nullptr;
350 }
351
352 if (c.vulkanSecondaryCBCompatible()) {
353 return nullptr;
354 }
355
356 GrColorType grColorType = SkColorTypeToGrColorType(c.colorType());
357
358 auto rtc = context->priv().makeDeferredRenderTargetContext(SkBackingFit::kExact,
359 c.width(),
360 c.height(),
361 grColorType,
362 c.refColorSpace(),
363 c.sampleCount(),
364 GrMipMapped(c.isMipMapped()),
365 c.origin(),
366 &c.surfaceProps(),
367 budgeted,
368 c.isProtected());
369 if (!rtc) {
370 return nullptr;
371 }
372
373 // CONTEXT TODO: remove this use of 'backdoor' to create an SkGpuDevice
374 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context->priv().backdoor(), std::move(rtc),
375 SkGpuDevice::kClear_InitContents));
376 if (!device) {
377 return nullptr;
378 }
379
380 sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
381 #ifdef SK_DEBUG
382 if (result) {
383 SkASSERT(result->isCompatible(c));
384 }
385 #endif
386
387 return result;
388 }
389
validate_backend_texture(const GrCaps * caps,const GrBackendTexture & tex,int sampleCnt,GrColorType grCT,bool texturable)390 static bool validate_backend_texture(const GrCaps* caps, const GrBackendTexture& tex,
391 int sampleCnt, GrColorType grCT,
392 bool texturable) {
393 if (!tex.isValid()) {
394 return false;
395 }
396
397 GrBackendFormat backendFormat = tex.getBackendFormat();
398 if (!backendFormat.isValid()) {
399 return false;
400 }
401
402 if (!caps->areColorTypeAndFormatCompatible(grCT, backendFormat)) {
403 return false;
404 }
405
406 if (!caps->isFormatAsColorTypeRenderable(grCT, backendFormat, sampleCnt)) {
407 return false;
408 }
409
410 if (texturable && !caps->isFormatTexturable(backendFormat)) {
411 return false;
412 }
413
414 return true;
415 }
416
MakeFromBackendTexture(GrContext * context,const SkSurfaceCharacterization & c,const GrBackendTexture & backendTexture,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)417 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context,
418 const SkSurfaceCharacterization& c,
419 const GrBackendTexture& backendTexture,
420 TextureReleaseProc textureReleaseProc,
421 ReleaseContext releaseContext) {
422 if (!context || !c.isValid()) {
423 return nullptr;
424 }
425
426 if (c.usesGLFBO0()) {
427 // If we are making the surface we will never use FBO0.
428 return nullptr;
429 }
430
431 if (!c.isCompatible(backendTexture)) {
432 return nullptr;
433 }
434
435 GrColorType grCT = SkColorTypeAndFormatToGrColorType(context->priv().caps(), c.colorType(),
436 backendTexture.getBackendFormat());
437 if (grCT == GrColorType::kUnknown) {
438 return nullptr;
439 }
440
441 if (!validate_backend_texture(context->priv().caps(), backendTexture,
442 c.sampleCount(), grCT, true)) {
443 return nullptr;
444 }
445
446 auto rtc = context->priv().makeBackendTextureRenderTargetContext(
447 backendTexture, c.origin(), c.sampleCount(), grCT, c.refColorSpace(), &c.surfaceProps(),
448 textureReleaseProc, releaseContext);
449 if (!rtc) {
450 return nullptr;
451 }
452
453 auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
454 if (!device) {
455 return nullptr;
456 }
457
458 sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
459 #ifdef SK_DEBUG
460 if (result) {
461 SkASSERT(result->isCompatible(c));
462 }
463 #endif
464
465 return result;
466 }
467
MakeRenderTarget(GrContext * ctx,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,bool shouldCreateWithMips)468 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
469 const SkImageInfo& info, int sampleCount,
470 GrSurfaceOrigin origin, const SkSurfaceProps* props,
471 bool shouldCreateWithMips) {
472 if (!ctx) {
473 return nullptr;
474 }
475 sampleCount = SkTMax(1, sampleCount);
476 GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
477
478 if (!ctx->priv().caps()->mipMapSupport()) {
479 mipMapped = GrMipMapped::kNo;
480 }
481
482 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
483 ctx, budgeted, info, sampleCount, origin, props, mipMapped,
484 SkGpuDevice::kClear_InitContents));
485 if (!device) {
486 return nullptr;
487 }
488 return sk_make_sp<SkSurface_Gpu>(std::move(device));
489 }
490
MakeWrappedRenderTarget(GrContext * context,std::unique_ptr<GrRenderTargetContext> rtc)491 sk_sp<SkSurface> SkSurface_Gpu::MakeWrappedRenderTarget(
492 GrContext* context, std::unique_ptr<GrRenderTargetContext> rtc) {
493 if (!context) {
494 return nullptr;
495 }
496
497 auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
498 if (!device) {
499 return nullptr;
500 }
501
502 return sk_make_sp<SkSurface_Gpu>(std::move(device));
503 }
504
MakeFromBackendTexture(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,SkSurface::TextureReleaseProc textureReleaseProc,SkSurface::ReleaseContext releaseContext)505 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
506 GrSurfaceOrigin origin, int sampleCnt,
507 SkColorType colorType,
508 sk_sp<SkColorSpace> colorSpace,
509 const SkSurfaceProps* props,
510 SkSurface::TextureReleaseProc textureReleaseProc,
511 SkSurface::ReleaseContext releaseContext) {
512 if (!context) {
513 return nullptr;
514 }
515 sampleCnt = SkTMax(1, sampleCnt);
516
517 GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(), colorType,
518 tex.getBackendFormat());
519 if (grColorType == GrColorType::kUnknown) {
520 return nullptr;
521 }
522
523 if (!validate_backend_texture(context->priv().caps(), tex, sampleCnt, grColorType, true)) {
524 return nullptr;
525 }
526
527 auto rtc = context->priv().makeBackendTextureRenderTargetContext(
528 tex, origin, sampleCnt, grColorType, std::move(colorSpace), props, textureReleaseProc,
529 releaseContext);
530 if (!rtc) {
531 return nullptr;
532 }
533
534 auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
535 if (!device) {
536 return nullptr;
537 }
538 return sk_make_sp<SkSurface_Gpu>(std::move(device));
539 }
540
onReplaceBackendTexture(const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,TextureReleaseProc releaseProc,ReleaseContext releaseContext)541 bool SkSurface_Gpu::onReplaceBackendTexture(const GrBackendTexture& backendTexture,
542 GrSurfaceOrigin origin, TextureReleaseProc releaseProc,
543 ReleaseContext releaseContext) {
544 auto context = this->fDevice->context();
545 if (context->abandoned()) {
546 return false;
547 }
548 if (!backendTexture.isValid()) {
549 return false;
550 }
551 if (backendTexture.width() != this->width() || backendTexture.height() != this->height()) {
552 return false;
553 }
554 auto* oldRTC = fDevice->accessRenderTargetContext();
555 auto oldProxy = sk_ref_sp(oldRTC->asTextureProxy());
556 if (!oldProxy) {
557 return false;
558 }
559 auto* oldTexture = oldProxy->peekTexture();
560 if (!oldTexture) {
561 return false;
562 }
563 if (!oldTexture->resourcePriv().refsWrappedObjects()) {
564 return false;
565 }
566 if (oldTexture->backendFormat() != backendTexture.getBackendFormat()) {
567 return false;
568 }
569 if (oldTexture->getBackendTexture().isSameTexture(backendTexture)) {
570 return false;
571 }
572 SkASSERT(oldTexture->asRenderTarget());
573 int sampleCnt = oldTexture->asRenderTarget()->numSamples();
574 GrColorType grColorType = SkColorTypeToGrColorType(this->getCanvas()->imageInfo().colorType());
575 auto colorSpace = sk_ref_sp(oldRTC->colorInfo().colorSpace());
576 if (!validate_backend_texture(context->priv().caps(), backendTexture,
577 sampleCnt, grColorType, true)) {
578 return false;
579 }
580 auto rtc =
581 context->priv().makeBackendTextureRenderTargetContext(backendTexture,
582 origin,
583 sampleCnt,
584 oldRTC->colorInfo().colorType(),
585 std::move(colorSpace),
586 &this->props(),
587 releaseProc,
588 releaseContext);
589 if (!rtc) {
590 return false;
591 }
592 fDevice->replaceRenderTargetContext(std::move(rtc), true);
593 return true;
594 }
595
validate_backend_render_target(const GrCaps * caps,const GrBackendRenderTarget & rt,GrColorType grCT)596 bool validate_backend_render_target(const GrCaps* caps, const GrBackendRenderTarget& rt,
597 GrColorType grCT) {
598 if (!caps->areColorTypeAndFormatCompatible(grCT, rt.getBackendFormat())) {
599 return false;
600 }
601
602 if (!caps->isFormatAsColorTypeRenderable(grCT, rt.getBackendFormat(), rt.sampleCnt())) {
603 return false;
604 }
605 return true;
606 }
607
MakeFromBackendRenderTarget(GrContext * context,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,SkSurface::RenderTargetReleaseProc relProc,SkSurface::ReleaseContext releaseContext)608 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
609 const GrBackendRenderTarget& rt,
610 GrSurfaceOrigin origin,
611 SkColorType colorType,
612 sk_sp<SkColorSpace> colorSpace,
613 const SkSurfaceProps* props,
614 SkSurface::RenderTargetReleaseProc relProc,
615 SkSurface::ReleaseContext releaseContext) {
616 if (!context) {
617 return nullptr;
618 }
619
620 GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(), colorType,
621 rt.getBackendFormat());
622 if (grColorType == GrColorType::kUnknown) {
623 return nullptr;
624 }
625
626 if (!validate_backend_render_target(context->priv().caps(), rt, grColorType)) {
627 return nullptr;
628 }
629
630 auto rtc = context->priv().makeBackendRenderTargetRenderTargetContext(
631 rt, origin, grColorType, std::move(colorSpace), props, relProc, releaseContext);
632 if (!rtc) {
633 return nullptr;
634 }
635
636 auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
637 if (!device) {
638 return nullptr;
639 }
640
641 return sk_make_sp<SkSurface_Gpu>(std::move(device));
642 }
643
MakeFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)644 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
645 const GrBackendTexture& tex,
646 GrSurfaceOrigin origin,
647 int sampleCnt,
648 SkColorType colorType,
649 sk_sp<SkColorSpace> colorSpace,
650 const SkSurfaceProps* props) {
651 if (!context) {
652 return nullptr;
653 }
654
655 sampleCnt = SkTMax(1, sampleCnt);
656 GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(), colorType,
657 tex.getBackendFormat());
658 if (grColorType == GrColorType::kUnknown) {
659 return nullptr;
660 }
661 if (!validate_backend_texture(context->priv().caps(), tex, sampleCnt, grColorType, false)) {
662 return nullptr;
663 }
664
665 auto rtc = context->priv().makeBackendTextureAsRenderTargetRenderTargetContext(
666 tex, origin, sampleCnt, grColorType, std::move(colorSpace), props);
667 if (!rtc) {
668 return nullptr;
669 }
670
671 auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
672 if (!device) {
673 return nullptr;
674 }
675 return sk_make_sp<SkSurface_Gpu>(std::move(device));
676 }
677
678 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
MakeFromAHardwareBuffer(GrContext * context,AHardwareBuffer * hardwareBuffer,GrSurfaceOrigin origin,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps)679 sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrContext* context,
680 AHardwareBuffer* hardwareBuffer,
681 GrSurfaceOrigin origin,
682 sk_sp<SkColorSpace> colorSpace,
683 const SkSurfaceProps* surfaceProps) {
684 AHardwareBuffer_Desc bufferDesc;
685 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
686
687 if (!SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT)) {
688 return nullptr;
689 }
690
691 bool isTextureable = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE);
692 bool isProtectedContent = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
693
694 // We currently don't support protected content
695 if (isProtectedContent) {
696 SkDebugf("We currently don't support protected content on android\n");
697 return nullptr;
698 }
699
700 GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(context,
701 hardwareBuffer,
702 bufferDesc.format,
703 true);
704 if (!backendFormat.isValid()) {
705 return nullptr;
706 }
707
708 if (isTextureable) {
709 GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
710 GrAHardwareBufferUtils::UpdateImageProc updateImageProc = nullptr;
711 GrAHardwareBufferUtils::TexImageCtx deleteImageCtx = nullptr;
712
713 GrBackendTexture backendTexture =
714 GrAHardwareBufferUtils::MakeBackendTexture(context, hardwareBuffer,
715 bufferDesc.width, bufferDesc.height,
716 &deleteImageProc, &updateImageProc,
717 &deleteImageCtx, isProtectedContent,
718 backendFormat, true);
719 if (!backendTexture.isValid()) {
720 return nullptr;
721 }
722
723 SkColorType colorType =
724 GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
725
726 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(context, backendTexture,
727 origin, 0, colorType, std::move(colorSpace), surfaceProps, deleteImageProc,
728 deleteImageCtx);
729
730 if (!surface) {
731 SkASSERT(deleteImageProc);
732 deleteImageProc(deleteImageCtx);
733 }
734 return surface;
735 } else {
736 return nullptr;
737 }
738 }
739 #endif
740
741 #endif
742