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