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