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