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