blob: c0c4042accf25840ad4f5da0a6d42a5bf5f02606 [file] [log] [blame]
reed@google.com5d4ba882012-07-31 15:45:27 +00001/*
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
bsalomonafe30052015-01-16 07:32:33 -08008#include "SkSurface_Gpu.h"
Greg Daniel173464d2019-02-06 15:30:34 -05009#include "GrAHardwareBufferUtils.h"
Greg Daniel7ef28f32017-04-20 16:41:55 +000010#include "GrBackendSurface.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040011#include "GrCaps.h"
robertphillips15c42ca2016-08-04 08:45:02 -070012#include "GrContextPriv.h"
Robert Phillipsfe0963c2019-02-07 13:25:07 -050013#include "GrContextThreadSafeProxyPriv.h"
Robert Phillips9338c602019-02-19 12:52:29 -050014#include "GrRecordingContext.h"
15#include "GrRecordingContextPriv.h"
Robert Phillips2890fbf2017-07-26 15:48:41 -040016#include "GrRenderTarget.h"
Robert Phillips0ae6faa2017-03-21 16:22:00 -040017#include "GrRenderTargetContextPriv.h"
Greg Daniela070ed72018-04-26 16:31:38 -040018#include "GrRenderTargetProxyPriv.h"
Robert Phillips646e4292017-06-13 12:44:56 -040019#include "GrTexture.h"
reed@google.com5d4ba882012-07-31 15:45:27 +000020#include "SkCanvas.h"
Robert Phillipsad8a43f2017-08-30 12:06:35 -040021#include "SkDeferredDisplayList.h"
robertphillips@google.com97b6b072012-10-31 14:48:39 +000022#include "SkGpuDevice.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040023#include "SkImagePriv.h"
bsalomonafe30052015-01-16 07:32:33 -080024#include "SkImage_Base.h"
reed8b26b992015-05-07 15:36:17 -070025#include "SkImage_Gpu.h"
Robert Phillipsad8a43f2017-08-30 12:06:35 -040026#include "SkSurfaceCharacterization.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040027#include "SkSurface_Base.h"
reed@google.com5d4ba882012-07-31 15:45:27 +000028
reedf037e0b2014-10-30 11:34:15 -070029#if SK_SUPPORT_GPU
30
robertphillips24e91282016-04-29 06:46:36 -070031SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
bsalomonafe30052015-01-16 07:32:33 -080032 : INHERITED(device->width(), device->height(), &device->surfaceProps())
robertphillips24e91282016-04-29 06:46:36 -070033 , fDevice(std::move(device)) {
Robert Phillips0ae6faa2017-03-21 16:22:00 -040034 SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
robertphillips@google.com97b6b072012-10-31 14:48:39 +000035}
reed@google.com5d4ba882012-07-31 15:45:27 +000036
robertphillips@google.com97b6b072012-10-31 14:48:39 +000037SkSurface_Gpu::~SkSurface_Gpu() {
reed@google.com5d4ba882012-07-31 15:45:27 +000038}
39
joshualitt81793412015-07-08 12:54:04 -070040static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
41 SkSurface::BackendHandleAccess access) {
reedfa5e68e2015-06-29 07:37:01 -070042 switch (access) {
joshualitt81793412015-07-08 12:54:04 -070043 case SkSurface::kFlushRead_BackendHandleAccess:
reedfa5e68e2015-06-29 07:37:01 -070044 break;
joshualitt81793412015-07-08 12:54:04 -070045 case SkSurface::kFlushWrite_BackendHandleAccess:
46 case SkSurface::kDiscardWrite_BackendHandleAccess:
reed884200e2015-06-29 09:00:20 -070047 // for now we don't special-case on Discard, but we may in the future.
joshualitt81793412015-07-08 12:54:04 -070048 surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
reedfa5e68e2015-06-29 07:37:01 -070049 break;
reedfa5e68e2015-06-29 07:37:01 -070050 }
fmalitae2639082015-08-06 07:04:51 -070051
52 // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
Robert Phillips9882dae2019-03-04 11:00:10 -050053 surface->getDevice()->flushAndSignalSemaphores(SkSurface::BackendSurfaceAccess::kNoAccess,
Greg Danielb9990e42019-04-10 16:28:52 -040054 kNone_GrFlushFlags, 0, nullptr);
Brian Osman11052242016-10-27 14:47:55 -040055 GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
56 return rtc->accessRenderTarget();
joshualitt81793412015-07-08 12:54:04 -070057}
58
Robert Phillips8caf85f2018-04-05 09:30:38 -040059GrBackendTexture SkSurface_Gpu::onGetBackendTexture(BackendHandleAccess access) {
60 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
61 if (!rt) {
62 return GrBackendTexture(); // invalid
63 }
64 GrTexture* texture = rt->asTexture();
65 if (texture) {
66 return texture->getBackendTexture();
67 }
68 return GrBackendTexture(); // invalid
69}
70
71GrBackendRenderTarget SkSurface_Gpu::onGetBackendRenderTarget(BackendHandleAccess access) {
72 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
73 if (!rt) {
74 return GrBackendRenderTarget(); // invalid
75 }
76
77 return rt->getBackendRenderTarget();
78}
79
Hal Canary363a3f82018-10-04 11:04:48 -040080SkCanvas* SkSurface_Gpu::onNewCanvas() { return new SkCanvas(fDevice); }
reed@google.com5d4ba882012-07-31 15:45:27 +000081
reede8f30622016-03-23 18:59:25 -070082sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
Brian Osman11052242016-10-27 14:47:55 -040083 int sampleCount = fDevice->accessRenderTargetContext()->numColorSamples();
84 GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin();
bsalomonafe30052015-01-16 07:32:33 -080085 // TODO: Make caller specify this (change virtual signature of onNewSurface).
bsalomon5ec26ae2016-02-25 08:33:02 -080086 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
reede8f30622016-03-23 18:59:25 -070087 return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
robertphillips7e922762016-07-26 11:38:17 -070088 origin, &this->props());
reed@google.com5d4ba882012-07-31 15:45:27 +000089}
90
Mike Reed114bde82018-11-21 09:12:09 -050091sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot(const SkIRect* subset) {
Robert Phillipse2f7d182016-12-15 09:23:05 -050092 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
93 if (!rtc) {
Robert Phillipse60ad622016-11-17 10:22:48 -050094 return nullptr;
95 }
96
Robert Phillipse2f7d182016-12-15 09:23:05 -050097 GrContext* ctx = fDevice->context();
98
Robert Phillips0ae6faa2017-03-21 16:22:00 -040099 if (!rtc->asSurfaceProxy()) {
100 return nullptr;
101 }
102
103 SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
104
105 sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
Mike Reed114bde82018-11-21 09:12:09 -0500106
107 if (subset) {
108 srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(), *subset,
Brian Salomonfee3f9b2018-12-19 12:34:12 -0500109 SkBackingFit::kExact, budgeted);
Mike Reed114bde82018-11-21 09:12:09 -0500110 } else if (!srcProxy || rtc->priv().refsWrappedObjects()) {
111 // If the original render target is a buffer originally created by the client, then we don't
112 // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
113 // copy-on-write.
Robert Phillips81dd3e02017-06-23 11:59:24 -0400114 SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
Robert Phillipse2f7d182016-12-15 09:23:05 -0500115
Brian Salomonfee3f9b2018-12-19 12:34:12 -0500116 srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(),
117 SkBackingFit::kExact, budgeted);
bsalomonf47b9a32016-02-22 11:02:58 -0800118 }
Robert Phillipse2f7d182016-12-15 09:23:05 -0500119
reed8b26b992015-05-07 15:36:17 -0700120 const SkImageInfo info = fDevice->imageInfo();
reede8f30622016-03-23 18:59:25 -0700121 sk_sp<SkImage> image;
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400122 if (srcProxy) {
123 // The renderTargetContext coming out of SkGpuDevice should always be exact and the
124 // above copy creates a kExact surfaceContext.
125 SkASSERT(srcProxy->priv().isExact());
Brian Salomon8a8dd332018-05-24 14:08:31 -0400126 image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, info.alphaType(),
Brian Salomonf05e6d32018-12-20 08:41:41 -0500127 std::move(srcProxy), info.refColorSpace());
reed8b26b992015-05-07 15:36:17 -0700128 }
reed4af267b2014-11-21 08:46:37 -0800129 return image;
reed@google.com5d4ba882012-07-31 15:45:27 +0000130}
131
Mike Reed4c790bd2018-02-08 14:10:40 -0500132void SkSurface_Gpu::onWritePixels(const SkPixmap& src, int x, int y) {
133 fDevice->writePixels(src, x, y);
134}
135
kkinnunenabcfab42015-02-22 22:53:44 -0800136// Create a new render target and, if necessary, copy the contents of the old
137// render target into it. Note that this flushes the SkGpuDevice but
robertphillips@google.com97b6b072012-10-31 14:48:39 +0000138// doesn't force an OpenGL flush.
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000139void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
Robert Phillips602b79c2017-06-23 11:26:28 -0400140 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
141
142 // are we sharing our backing proxy with the image? Note this call should never create a new
bsalomoneaaaf0b2015-01-23 08:08:04 -0800143 // image because onCopyOnWrite is only called when there is a cached image.
Robert Phillipsac6b1fa2017-03-20 08:38:50 -0400144 sk_sp<SkImage> image(this->refCachedImage());
bsalomoneaaaf0b2015-01-23 08:08:04 -0800145 SkASSERT(image);
Robert Phillips602b79c2017-06-23 11:26:28 -0400146
147 GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
148 SkASSERT(imageProxy);
149
150 if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
Robert Phillips6de99042017-01-31 11:31:39 -0500151 fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +0000152 } else if (kDiscard_ContentChangeMode == mode) {
153 this->SkSurface_Gpu::onDiscard();
robertphillips@google.com97b6b072012-10-31 14:48:39 +0000154 }
reed@google.com5d4ba882012-07-31 15:45:27 +0000155}
156
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +0000157void SkSurface_Gpu::onDiscard() {
Brian Osman11052242016-10-27 14:47:55 -0400158 fDevice->accessRenderTargetContext()->discard();
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +0000159}
160
Greg Danielb9990e42019-04-10 16:28:52 -0400161GrSemaphoresSubmitted SkSurface_Gpu::onFlush(BackendSurfaceAccess access, GrFlushFlags flags,
Greg Danielbae71212019-03-01 15:24:35 -0500162 int numSemaphores,
Greg Daniel51316782017-08-02 15:10:09 +0000163 GrBackendSemaphore signalSemaphores[]) {
Greg Danielbae71212019-03-01 15:24:35 -0500164 return fDevice->flushAndSignalSemaphores(access, flags, numSemaphores, signalSemaphores);
Greg Daniela5cb7812017-06-16 09:45:32 -0400165}
166
Greg Danielc64ee462017-06-15 16:59:49 -0400167bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
168 return fDevice->wait(numSemaphores, waitSemaphores);
ericrkf7b8b8a2016-02-24 14:49:51 -0800169}
170
Robert Phillipsbe77a022018-04-03 17:17:05 -0400171bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* characterization) const {
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400172 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
Robert Phillips8def8bf2017-11-30 08:46:03 -0500173 GrContext* ctx = fDevice->context();
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400174
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500175 int maxResourceCount;
176 size_t maxResourceBytes;
177 ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
178
Robert Phillipse8fabb22018-02-04 14:33:21 -0500179 bool mipmapped = rtc->asTextureProxy() ? GrMipMapped::kYes == rtc->asTextureProxy()->mipMapped()
180 : false;
181
Robert Phillipsbe77a022018-04-03 17:17:05 -0400182 // TODO: the addition of colorType to the surfaceContext should remove this calculation
183 SkColorType ct;
184 if (!GrPixelConfigToColorType(rtc->colorSpaceInfo().config(), &ct)) {
185 return false;
186 }
187
Greg Daniela070ed72018-04-26 16:31:38 -0400188 bool usesGLFBO0 = rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0();
189 // We should never get in the situation where we have a texture render target that is also
190 // backend by FBO 0.
191 SkASSERT(!usesGLFBO0 || !SkToBool(rtc->asTextureProxy()));
192
Robert Phillipsbe77a022018-04-03 17:17:05 -0400193 SkImageInfo ii = SkImageInfo::Make(rtc->width(), rtc->height(), ct, kPremul_SkAlphaType,
194 rtc->colorSpaceInfo().refColorSpace());
195
196 characterization->set(ctx->threadSafeProxy(), maxResourceBytes, ii, rtc->origin(),
197 rtc->colorSpaceInfo().config(), rtc->fsaaType(), rtc->numStencilSamples(),
198 SkSurfaceCharacterization::Textureable(SkToBool(rtc->asTextureProxy())),
Greg Daniela070ed72018-04-26 16:31:38 -0400199 SkSurfaceCharacterization::MipMapped(mipmapped),
Greg Danielb46add82019-01-02 14:51:29 -0500200 SkSurfaceCharacterization::UsesGLFBO0(usesGLFBO0),
201 SkSurfaceCharacterization::VulkanSecondaryCBCompatible(false),
202 this->props());
Robert Phillips8def8bf2017-11-30 08:46:03 -0500203
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400204 return true;
205}
206
Brian Salomonc552eaf2019-03-20 15:45:50 -0400207void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
208 // If the dst is also GPU we try to not force a new image snapshot (by calling the base class
209 // onDraw) since that may not always perform the copy-on-write optimization.
210 auto tryDraw = [&] {
211 SkASSERT(fDevice->context()->priv().asDirectContext());
212 GrContext* context = fDevice->context();
213 GrContext* canvasContext = canvas->getGrContext();
214 if (!canvasContext) {
215 return false;
216 }
217 if (!canvasContext->priv().asDirectContext() ||
218 canvasContext->priv().contextID() != context->priv().contextID()) {
219 return false;
220 }
221 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
222 if (!rtc) {
223 return false;
224 }
225 sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
226 if (!srcProxy) {
227 return false;
228 }
229 // Possibly we could skip making an image here if SkGpuDevice exposed a lower level way
230 // of drawing a texture proxy.
231 const SkImageInfo info = fDevice->imageInfo();
232 sk_sp<SkImage> image;
233 image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, info.alphaType(),
234 std::move(srcProxy), info.refColorSpace());
235 canvas->drawImage(image, x, y, paint);
236 return true;
237 };
238 if (!tryDraw()) {
239 INHERITED::onDraw(canvas, x, y, paint);
240 }
241}
242
Robert Phillipsbe77a022018-04-03 17:17:05 -0400243bool SkSurface_Gpu::isCompatible(const SkSurfaceCharacterization& characterization) const {
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400244 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
Robert Phillips8def8bf2017-11-30 08:46:03 -0500245 GrContext* ctx = fDevice->context();
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400246
Robert Phillipsbe77a022018-04-03 17:17:05 -0400247 if (!characterization.isValid()) {
Robert Phillipsfc711a22018-02-13 17:03:00 -0500248 return false;
249 }
250
Greg Danielb085fa92019-03-05 16:55:12 -0500251 if (characterization.vulkanSecondaryCBCompatible()) {
252 return false;
253 }
254
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500255 // As long as the current state if the context allows for greater or equal resources,
256 // we allow the DDL to be replayed.
Robert Phillipsfc711a22018-02-13 17:03:00 -0500257 // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500258 int maxResourceCount;
259 size_t maxResourceBytes;
260 ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
261
Robert Phillipsbe77a022018-04-03 17:17:05 -0400262 if (characterization.isTextureable()) {
Robert Phillipse8fabb22018-02-04 14:33:21 -0500263 if (!rtc->asTextureProxy()) {
264 // If the characterization was textureable we require the replay dest to also be
265 // textureable. If the characterized surface wasn't textureable we allow the replay
266 // dest to be textureable.
267 return false;
268 }
269
Robert Phillipsbe77a022018-04-03 17:17:05 -0400270 if (characterization.isMipMapped() &&
271 GrMipMapped::kNo == rtc->asTextureProxy()->mipMapped()) {
Robert Phillipse8fabb22018-02-04 14:33:21 -0500272 // Fail if the DDL's surface was mipmapped but the replay surface is not.
273 // Allow drawing to proceed if the DDL was not mipmapped but the replay surface is.
274 return false;
275 }
276 }
277
Greg Daniela070ed72018-04-26 16:31:38 -0400278 if (characterization.usesGLFBO0() != rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0()) {
279 return false;
280 }
281
Robert Phillipsbe77a022018-04-03 17:17:05 -0400282 // TODO: the addition of colorType to the surfaceContext should remove this calculation
283 SkColorType rtcColorType;
284 if (!GrPixelConfigToColorType(rtc->colorSpaceInfo().config(), &rtcColorType)) {
285 return false;
286 }
287
Robert Phillipsfe0963c2019-02-07 13:25:07 -0500288 return characterization.contextInfo() && characterization.contextInfo()->priv().matches(ctx) &&
Robert Phillipsbe77a022018-04-03 17:17:05 -0400289 characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
290 characterization.origin() == rtc->origin() &&
291 characterization.config() == rtc->colorSpaceInfo().config() &&
292 characterization.width() == rtc->width() &&
293 characterization.height() == rtc->height() &&
294 characterization.colorType() == rtcColorType &&
295 characterization.fsaaType() == rtc->fsaaType() &&
296 characterization.stencilCount() == rtc->numStencilSamples() &&
297 SkColorSpace::Equals(characterization.colorSpace(),
298 rtc->colorSpaceInfo().colorSpace()) &&
299 characterization.surfaceProps() == rtc->surfaceProps();
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400300}
301
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500302bool SkSurface_Gpu::onDraw(const SkDeferredDisplayList* ddl) {
Robert Phillipsfc711a22018-02-13 17:03:00 -0500303 if (!ddl || !this->isCompatible(ddl->characterization())) {
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500304 return false;
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400305 }
306
Robert Phillips62000362018-02-01 09:10:04 -0500307 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
308 GrContext* ctx = fDevice->context();
309
Robert Phillips9da87e02019-02-04 13:26:26 -0500310 ctx->priv().copyOpListsFromDDL(ddl, rtc->asRenderTargetProxy());
Robert Phillips62000362018-02-01 09:10:04 -0500311 return true;
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400312}
313
314
reed@google.com5d4ba882012-07-31 15:45:27 +0000315///////////////////////////////////////////////////////////////////////////////
316
brianosman0e22eb82016-08-30 07:07:59 -0700317bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
Brian Osman38a62bd2018-10-11 14:45:07 -0400318 return true;
brianosman0e22eb82016-08-30 07:07:59 -0700319}
320
Robert Phillipsbe77a022018-04-03 17:17:05 -0400321bool SkSurface_Gpu::Valid(const GrCaps* caps, GrPixelConfig config, SkColorSpace* colorSpace) {
brianosman0e22eb82016-08-30 07:07:59 -0700322 switch (config) {
brianosman0e22eb82016-08-30 07:07:59 -0700323 case kSRGBA_8888_GrPixelConfig:
324 case kSBGRA_8888_GrPixelConfig:
Brian Osman2b23c4b2018-06-01 12:25:08 -0400325 return caps->srgbSupport();
Greg Danielf4216852018-10-11 17:47:17 +0000326 default:
Brian Osman38a62bd2018-10-11 14:45:07 -0400327 return true;
brianosman0e22eb82016-08-30 07:07:59 -0700328 }
329}
330
Robert Phillips9338c602019-02-19 12:52:29 -0500331sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext* context,
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400332 const SkSurfaceCharacterization& c,
333 SkBudgeted budgeted) {
Robert Phillipsbe77a022018-04-03 17:17:05 -0400334 if (!context || !c.isValid()) {
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400335 return nullptr;
336 }
337
Greg Daniela070ed72018-04-26 16:31:38 -0400338 if (c.usesGLFBO0()) {
339 // If we are making the surface we will never use FBO0.
340 return nullptr;
341 }
342
Robert Phillips9da87e02019-02-04 13:26:26 -0500343 if (!SkSurface_Gpu::Valid(context->priv().caps(), c.config(), c.colorSpace())) {
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400344 return nullptr;
345 }
346
Robert Phillipsbe77a022018-04-03 17:17:05 -0400347 // In order to ensure compatibility we have to match the backend format (i.e. the GrPixelConfig
348 // of the characterization)
349 GrSurfaceDesc desc;
350 desc.fFlags = kRenderTarget_GrSurfaceFlag;
351 desc.fWidth = c.width();
352 desc.fHeight = c.height();
353 desc.fConfig = c.config();
354 desc.fSampleCnt = c.stencilCount();
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400355
Greg Daniel4065d452018-11-16 15:43:41 -0500356 const GrBackendFormat format =
Robert Phillips9da87e02019-02-04 13:26:26 -0500357 context->priv().caps()->getBackendFormatFromColorType(c.colorType());
Greg Daniel4065d452018-11-16 15:43:41 -0500358
Robert Phillipsbe77a022018-04-03 17:17:05 -0400359 sk_sp<GrSurfaceContext> sc(
Robert Phillips9da87e02019-02-04 13:26:26 -0500360 context->priv().makeDeferredSurfaceContext(format, desc, c.origin(),
361 GrMipMapped(c.isMipMapped()),
362 SkBackingFit::kExact, budgeted,
363 c.refColorSpace(),
364 &c.surfaceProps()));
Robert Phillipsbe77a022018-04-03 17:17:05 -0400365 if (!sc || !sc->asRenderTargetContext()) {
366 return nullptr;
367 }
368
Robert Phillips9338c602019-02-19 12:52:29 -0500369 // CONTEXT TODO: remove this use of 'backdoor' to create an SkGpuDevice
370 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context->priv().backdoor(),
371 sk_ref_sp(sc->asRenderTargetContext()),
Robert Phillipsbe77a022018-04-03 17:17:05 -0400372 c.width(), c.height(),
373 SkGpuDevice::kClear_InitContents));
374 if (!device) {
375 return nullptr;
376 }
377
378 sk_sp<SkSurface> s = sk_make_sp<SkSurface_Gpu>(std::move(device));
379#ifdef SK_DEBUG
380 if (s) {
381 SkSurface_Gpu* gpuSurface = static_cast<SkSurface_Gpu*>(s.get());
382 SkASSERT(gpuSurface->isCompatible(c));
383 }
384#endif
385
386 return s;
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400387}
388
389
reede8f30622016-03-23 18:59:25 -0700390sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
391 const SkImageInfo& info, int sampleCount,
Greg Daniele252f082017-10-23 16:05:23 -0400392 GrSurfaceOrigin origin, const SkSurfaceProps* props,
393 bool shouldCreateWithMips) {
Greg Danielf47069c2017-10-24 11:57:01 -0400394 if (!ctx) {
395 return nullptr;
396 }
brianosman0e22eb82016-08-30 07:07:59 -0700397 if (!SkSurface_Gpu::Valid(info)) {
398 return nullptr;
399 }
Brian Salomonbdecacf2018-02-02 20:32:49 -0500400 sampleCount = SkTMax(1, sampleCount);
Greg Daniele252f082017-10-23 16:05:23 -0400401 GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
402
Robert Phillips9da87e02019-02-04 13:26:26 -0500403 if (!ctx->priv().caps()->mipMapSupport()) {
Greg Danielf47069c2017-10-24 11:57:01 -0400404 mipMapped = GrMipMapped::kNo;
405 }
406
robertphillips24e91282016-04-29 06:46:36 -0700407 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
Greg Daniele252f082017-10-23 16:05:23 -0400408 ctx, budgeted, info, sampleCount, origin, props, mipMapped,
409 SkGpuDevice::kClear_InitContents));
bsalomonafe30052015-01-16 07:32:33 -0800410 if (!device) {
halcanary96fcdcc2015-08-27 07:41:13 -0700411 return nullptr;
reed@google.com5d4ba882012-07-31 15:45:27 +0000412 }
robertphillips24e91282016-04-29 06:46:36 -0700413 return sk_make_sp<SkSurface_Gpu>(std::move(device));
reed@google.com5d4ba882012-07-31 15:45:27 +0000414}
reedf037e0b2014-10-30 11:34:15 -0700415
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500416sk_sp<SkSurface> SkSurface_Gpu::MakeWrappedRenderTarget(GrContext* context,
417 sk_sp<GrRenderTargetContext> rtc) {
418 if (!context) {
419 return nullptr;
420 }
421
Brian Salomonf7778972018-03-08 10:13:17 -0500422 int w = rtc->width();
423 int h = rtc->height();
424 sk_sp<SkGpuDevice> device(
425 SkGpuDevice::Make(context, std::move(rtc), w, h, SkGpuDevice::kUninit_InitContents));
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500426 if (!device) {
427 return nullptr;
428 }
429
430 return sk_make_sp<SkSurface_Gpu>(std::move(device));
431}
432
Greg Danielfaa095e2017-12-19 13:15:02 -0500433bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
434 int sampleCnt, SkColorType ct, sk_sp<SkColorSpace> cs,
435 bool texturable) {
Greg Daniel66aebf32018-04-09 09:15:56 -0400436 if (!tex.isValid()) {
437 return false;
438 }
Greg Danielfaa095e2017-12-19 13:15:02 -0500439 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
440 // create a fake image info here.
441 SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
442
443 if (!SkSurface_Gpu::Valid(info)) {
444 return false;
445 }
446
Brian Salomonf391d0f2018-12-14 09:18:50 -0500447 GrBackendFormat backendFormat = tex.getBackendFormat();
448 if (!backendFormat.isValid()) {
449 return false;
450 }
Robert Phillips9da87e02019-02-04 13:26:26 -0500451 *config = ctx->priv().caps()->getConfigFromBackendFormat(backendFormat, ct);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500452 if (*config == kUnknown_GrPixelConfig) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500453 return false;
454 }
455
Brian Salomonbdecacf2018-02-02 20:32:49 -0500456 // We don't require that the client gave us an exact valid sample cnt. However, it must be
457 // less than the max supported sample count and 1 if MSAA is unsupported for the color type.
Robert Phillips9da87e02019-02-04 13:26:26 -0500458 if (!ctx->priv().caps()->getRenderTargetSampleCount(sampleCnt, *config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500459 return false;
460 }
461
Robert Phillips9da87e02019-02-04 13:26:26 -0500462 if (texturable && !ctx->priv().caps()->isConfigTexturable(*config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500463 return false;
464 }
465 return true;
466}
467
468sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
469 GrSurfaceOrigin origin, int sampleCnt,
470 SkColorType colorType,
471 sk_sp<SkColorSpace> colorSpace,
Greg Daniel8ce79912019-02-05 10:08:43 -0500472 const SkSurfaceProps* props,
473 SkSurface::TextureReleaseProc textureReleaseProc,
474 SkSurface::ReleaseContext releaseContext) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500475 if (!context) {
476 return nullptr;
477 }
Brian Salomonbdecacf2018-02-02 20:32:49 -0500478 sampleCnt = SkTMax(1, sampleCnt);
Greg Danielfaa095e2017-12-19 13:15:02 -0500479 GrBackendTexture texCopy = tex;
480 if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
481 sampleCnt, colorType, colorSpace, true)) {
482 return nullptr;
483 }
484
Brian Salomon53706772018-03-19 14:18:08 -0400485 if (!context) {
486 return nullptr;
487 }
Robert Phillips9da87e02019-02-04 13:26:26 -0500488 if (!SkSurface_Gpu::Valid(context->priv().caps(), texCopy.config(), colorSpace.get())) {
Brian Salomon53706772018-03-19 14:18:08 -0400489 return nullptr;
490 }
491 sampleCnt = SkTMax(1, sampleCnt);
492
Robert Phillips9da87e02019-02-04 13:26:26 -0500493 sk_sp<GrRenderTargetContext> rtc(context->priv().makeBackendTextureRenderTargetContext(
Brian Salomon53706772018-03-19 14:18:08 -0400494 texCopy,
495 origin,
496 sampleCnt,
497 std::move(colorSpace),
Greg Daniel8ce79912019-02-05 10:08:43 -0500498 props,
499 textureReleaseProc,
500 releaseContext));
Brian Salomon53706772018-03-19 14:18:08 -0400501 if (!rtc) {
502 return nullptr;
503 }
504
505 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), texCopy.width(),
506 texCopy.height(),
507 SkGpuDevice::kUninit_InitContents));
508 if (!device) {
509 return nullptr;
510 }
511 return sk_make_sp<SkSurface_Gpu>(std::move(device));
Greg Danielfaa095e2017-12-19 13:15:02 -0500512}
513
Greg Danielfaa095e2017-12-19 13:15:02 -0500514bool validate_backend_render_target(GrContext* ctx, const GrBackendRenderTarget& rt,
515 GrPixelConfig* config, SkColorType ct, sk_sp<SkColorSpace> cs) {
516 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
517 // create a fake image info here.
518 SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
519
520 if (!SkSurface_Gpu::Valid(info)) {
521 return false;
522 }
523
Robert Phillips9da87e02019-02-04 13:26:26 -0500524 *config = ctx->priv().caps()->validateBackendRenderTarget(rt, ct);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500525 if (*config == kUnknown_GrPixelConfig) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500526 return false;
527 }
528
Brian Salomonbdecacf2018-02-02 20:32:49 -0500529 if (rt.sampleCnt() > 1) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500530 if (ctx->priv().caps()->maxRenderTargetSampleCount(*config) <= 1) {
Brian Salomonbdecacf2018-02-02 20:32:49 -0500531 return false;
532 }
Robert Phillips9da87e02019-02-04 13:26:26 -0500533 } else if (!ctx->priv().caps()->isConfigRenderable(*config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500534 return false;
535 }
536
537 return true;
538}
539
540sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
541 const GrBackendRenderTarget& rt,
542 GrSurfaceOrigin origin,
543 SkColorType colorType,
544 sk_sp<SkColorSpace> colorSpace,
Greg Daniel8ce79912019-02-05 10:08:43 -0500545 const SkSurfaceProps* props,
546 SkSurface::RenderTargetReleaseProc relProc,
547 SkSurface::ReleaseContext releaseContext) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500548 if (!context) {
549 return nullptr;
550 }
Brian Salomon49edccd2018-03-23 15:31:32 -0400551
Greg Danielfaa095e2017-12-19 13:15:02 -0500552 GrBackendRenderTarget rtCopy = rt;
553 if (!validate_backend_render_target(context, rtCopy, &rtCopy.fConfig, colorType, colorSpace)) {
554 return nullptr;
555 }
Robert Phillips9da87e02019-02-04 13:26:26 -0500556 if (!SkSurface_Gpu::Valid(context->priv().caps(), rtCopy.config(), colorSpace.get())) {
Brian Salomon49edccd2018-03-23 15:31:32 -0400557 return nullptr;
558 }
Greg Danielfaa095e2017-12-19 13:15:02 -0500559
Brian Salomon49edccd2018-03-23 15:31:32 -0400560 if (!context) {
561 return nullptr;
562 }
563
564 sk_sp<GrRenderTargetContext> rtc(
Robert Phillips9da87e02019-02-04 13:26:26 -0500565 context->priv().makeBackendRenderTargetRenderTargetContext(
Greg Daniel8ce79912019-02-05 10:08:43 -0500566 rtCopy, origin, std::move(colorSpace), props, relProc, releaseContext));
Brian Salomon49edccd2018-03-23 15:31:32 -0400567 if (!rtc) {
568 return nullptr;
569 }
570
571 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), rtCopy.width(),
572 rtCopy.height(),
573 SkGpuDevice::kUninit_InitContents));
574 if (!device) {
575 return nullptr;
576 }
577
578 return sk_make_sp<SkSurface_Gpu>(std::move(device));
Greg Danielfaa095e2017-12-19 13:15:02 -0500579}
580
reede8f30622016-03-23 18:59:25 -0700581sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
Greg Daniel7ef28f32017-04-20 16:41:55 +0000582 const GrBackendTexture& tex,
583 GrSurfaceOrigin origin,
584 int sampleCnt,
Brian Salomoncb884702018-03-19 14:01:21 -0400585 SkColorType colorType,
Greg Daniel7ef28f32017-04-20 16:41:55 +0000586 sk_sp<SkColorSpace> colorSpace,
587 const SkSurfaceProps* props) {
588 if (!context) {
589 return nullptr;
590 }
Justin Novosad21a99d42018-07-17 16:53:43 -0400591
Brian Salomonbdecacf2018-02-02 20:32:49 -0500592 sampleCnt = SkTMax(1, sampleCnt);
Brian Salomoncb884702018-03-19 14:01:21 -0400593 GrBackendTexture texCopy = tex;
594 if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
595 sampleCnt, colorType, colorSpace, false)) {
596 return nullptr;
597 }
robertphillips15c42ca2016-08-04 08:45:02 -0700598
Robert Phillips9da87e02019-02-04 13:26:26 -0500599 if (!SkSurface_Gpu::Valid(context->priv().caps(), texCopy.config(), colorSpace.get())) {
Justin Novosad21a99d42018-07-17 16:53:43 -0400600 return nullptr;
601 }
602
Brian Osman11052242016-10-27 14:47:55 -0400603 sk_sp<GrRenderTargetContext> rtc(
Robert Phillips9da87e02019-02-04 13:26:26 -0500604 context->priv().makeBackendTextureAsRenderTargetRenderTargetContext(
Brian Salomoncb884702018-03-19 14:01:21 -0400605 texCopy,
606 origin,
607 sampleCnt,
608 std::move(colorSpace),
609 props));
Brian Osman11052242016-10-27 14:47:55 -0400610 if (!rtc) {
ericrkf7b8b8a2016-02-24 14:49:51 -0800611 return nullptr;
612 }
robertphillips15c42ca2016-08-04 08:45:02 -0700613
Greg Daniel7ef28f32017-04-20 16:41:55 +0000614 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
robertphillips24e91282016-04-29 06:46:36 -0700615 SkGpuDevice::kUninit_InitContents));
ericrkf7b8b8a2016-02-24 14:49:51 -0800616 if (!device) {
617 return nullptr;
618 }
robertphillips24e91282016-04-29 06:46:36 -0700619 return sk_make_sp<SkSurface_Gpu>(std::move(device));
ericrkf7b8b8a2016-02-24 14:49:51 -0800620}
621
Greg Daniel173464d2019-02-06 15:30:34 -0500622#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
623sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrContext* context,
624 AHardwareBuffer* hardwareBuffer,
625 GrSurfaceOrigin origin,
626 sk_sp<SkColorSpace> colorSpace,
627 const SkSurfaceProps* surfaceProps) {
628 AHardwareBuffer_Desc bufferDesc;
629 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
630
631 if (!SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT)) {
632 return nullptr;
633 }
634
635 bool isTextureable = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE);
636 bool isProtectedContent = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
637
638 // We currently don't support protected content
639 if (isProtectedContent) {
640 return nullptr;
641 }
642
643 GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(context,
644 hardwareBuffer,
645 bufferDesc.format,
646 true);
647 if (!backendFormat.isValid()) {
648 return nullptr;
649 }
650
651 if (isTextureable) {
652 GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
653 GrAHardwareBufferUtils::DeleteImageCtx deleteImageCtx = nullptr;
654
655 GrBackendTexture backendTexture =
656 GrAHardwareBufferUtils::MakeBackendTexture(context, hardwareBuffer,
657 bufferDesc.width, bufferDesc.height,
658 &deleteImageProc, &deleteImageCtx,
659 isProtectedContent, backendFormat,
660 true);
661 if (!backendTexture.isValid()) {
662 return nullptr;
663 }
664
665 SkColorType colorType =
666 GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
667
Greg Danielb6c15ba2019-03-04 13:08:25 -0500668 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(context, backendTexture,
669 origin, 0, colorType, std::move(colorSpace), surfaceProps, deleteImageProc,
670 deleteImageCtx);
671
672 if (!surface) {
673 SkASSERT(deleteImageProc);
674 deleteImageProc(deleteImageCtx);
675 }
676 return surface;
Greg Daniel173464d2019-02-06 15:30:34 -0500677 } else {
678 return nullptr;
679 }
680}
681#endif
682
reedf037e0b2014-10-30 11:34:15 -0700683#endif