blob: 8f7958444dbf99f96dd1e057f375b7d572630350 [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 Daniel7ef28f32017-04-20 16:41:55 +00009#include "GrBackendSurface.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040010#include "GrCaps.h"
robertphillips15c42ca2016-08-04 08:45:02 -070011#include "GrContextPriv.h"
Robert Phillips2890fbf2017-07-26 15:48:41 -040012#include "GrRenderTarget.h"
Robert Phillips0ae6faa2017-03-21 16:22:00 -040013#include "GrRenderTargetContextPriv.h"
Greg Daniela070ed72018-04-26 16:31:38 -040014#include "GrRenderTargetProxyPriv.h"
Robert Phillips646e4292017-06-13 12:44:56 -040015#include "GrTexture.h"
reed@google.com5d4ba882012-07-31 15:45:27 +000016#include "SkCanvas.h"
Robert Phillipsad8a43f2017-08-30 12:06:35 -040017#include "SkDeferredDisplayList.h"
robertphillips@google.com97b6b072012-10-31 14:48:39 +000018#include "SkGpuDevice.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040019#include "SkImagePriv.h"
bsalomonafe30052015-01-16 07:32:33 -080020#include "SkImage_Base.h"
reed8b26b992015-05-07 15:36:17 -070021#include "SkImage_Gpu.h"
Robert Phillipsad8a43f2017-08-30 12:06:35 -040022#include "SkSurfaceCharacterization.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040023#include "SkSurface_Base.h"
reed@google.com5d4ba882012-07-31 15:45:27 +000024
reedf037e0b2014-10-30 11:34:15 -070025#if SK_SUPPORT_GPU
26
robertphillips24e91282016-04-29 06:46:36 -070027SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
bsalomonafe30052015-01-16 07:32:33 -080028 : INHERITED(device->width(), device->height(), &device->surfaceProps())
robertphillips24e91282016-04-29 06:46:36 -070029 , fDevice(std::move(device)) {
Robert Phillips0ae6faa2017-03-21 16:22:00 -040030 SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
robertphillips@google.com97b6b072012-10-31 14:48:39 +000031}
reed@google.com5d4ba882012-07-31 15:45:27 +000032
robertphillips@google.com97b6b072012-10-31 14:48:39 +000033SkSurface_Gpu::~SkSurface_Gpu() {
reed@google.com5d4ba882012-07-31 15:45:27 +000034}
35
joshualitt81793412015-07-08 12:54:04 -070036static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
37 SkSurface::BackendHandleAccess access) {
reedfa5e68e2015-06-29 07:37:01 -070038 switch (access) {
joshualitt81793412015-07-08 12:54:04 -070039 case SkSurface::kFlushRead_BackendHandleAccess:
reedfa5e68e2015-06-29 07:37:01 -070040 break;
joshualitt81793412015-07-08 12:54:04 -070041 case SkSurface::kFlushWrite_BackendHandleAccess:
42 case SkSurface::kDiscardWrite_BackendHandleAccess:
reed884200e2015-06-29 09:00:20 -070043 // for now we don't special-case on Discard, but we may in the future.
joshualitt81793412015-07-08 12:54:04 -070044 surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
reedfa5e68e2015-06-29 07:37:01 -070045 break;
reedfa5e68e2015-06-29 07:37:01 -070046 }
fmalitae2639082015-08-06 07:04:51 -070047
48 // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
robertphillipsea70c4b2016-07-20 08:54:31 -070049 surface->getDevice()->flush();
Brian Osman11052242016-10-27 14:47:55 -040050 GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
51 return rtc->accessRenderTarget();
joshualitt81793412015-07-08 12:54:04 -070052}
53
Robert Phillips8caf85f2018-04-05 09:30:38 -040054GrBackendTexture SkSurface_Gpu::onGetBackendTexture(BackendHandleAccess access) {
55 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
56 if (!rt) {
57 return GrBackendTexture(); // invalid
58 }
59 GrTexture* texture = rt->asTexture();
60 if (texture) {
61 return texture->getBackendTexture();
62 }
63 return GrBackendTexture(); // invalid
64}
65
66GrBackendRenderTarget SkSurface_Gpu::onGetBackendRenderTarget(BackendHandleAccess access) {
67 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
68 if (!rt) {
69 return GrBackendRenderTarget(); // invalid
70 }
71
72 return rt->getBackendRenderTarget();
73}
74
reed@google.com5d4ba882012-07-31 15:45:27 +000075SkCanvas* SkSurface_Gpu::onNewCanvas() {
reed4a8126e2014-09-22 07:29:03 -070076 SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
bsalomonb5b49742016-02-10 10:41:01 -080077 flags = static_cast<SkCanvas::InitFlags>(flags | SkCanvas::kConservativeRasterClip_InitFlag);
reed4a8126e2014-09-22 07:29:03 -070078
Herb Derbyefe39bc2018-05-01 17:06:20 -040079 return new SkCanvas(fDevice, flags);
reed@google.com5d4ba882012-07-31 15:45:27 +000080}
81
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
Robert Phillipsac6b1fa2017-03-20 08:38:50 -040091sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot() {
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();
bsalomonb2c01332016-02-26 10:37:26 -0800106 // If the original render target is a buffer originally created by the client, then we don't
107 // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
108 // copy-on-write.
Mike Reed7eb01f82016-12-30 06:23:12 -0500109 if (!srcProxy || rtc->priv().refsWrappedObjects()) {
Robert Phillips81dd3e02017-06-23 11:59:24 -0400110 SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
Robert Phillipse2f7d182016-12-15 09:23:05 -0500111
Greg Daniel45d63032017-10-30 13:41:26 -0400112 srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(), budgeted);
bsalomonf47b9a32016-02-22 11:02:58 -0800113 }
Robert Phillipse2f7d182016-12-15 09:23:05 -0500114
reed8b26b992015-05-07 15:36:17 -0700115 const SkImageInfo info = fDevice->imageInfo();
reede8f30622016-03-23 18:59:25 -0700116 sk_sp<SkImage> image;
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400117 if (srcProxy) {
118 // The renderTargetContext coming out of SkGpuDevice should always be exact and the
119 // above copy creates a kExact surfaceContext.
120 SkASSERT(srcProxy->priv().isExact());
Brian Salomon8a8dd332018-05-24 14:08:31 -0400121 image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, info.alphaType(),
122 std::move(srcProxy), info.refColorSpace(), budgeted);
reed8b26b992015-05-07 15:36:17 -0700123 }
reed4af267b2014-11-21 08:46:37 -0800124 return image;
reed@google.com5d4ba882012-07-31 15:45:27 +0000125}
126
Mike Reed4c790bd2018-02-08 14:10:40 -0500127void SkSurface_Gpu::onWritePixels(const SkPixmap& src, int x, int y) {
128 fDevice->writePixels(src, x, y);
129}
130
kkinnunenabcfab42015-02-22 22:53:44 -0800131// Create a new render target and, if necessary, copy the contents of the old
132// render target into it. Note that this flushes the SkGpuDevice but
robertphillips@google.com97b6b072012-10-31 14:48:39 +0000133// doesn't force an OpenGL flush.
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000134void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
Robert Phillips602b79c2017-06-23 11:26:28 -0400135 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
136
137 // are we sharing our backing proxy with the image? Note this call should never create a new
bsalomoneaaaf0b2015-01-23 08:08:04 -0800138 // image because onCopyOnWrite is only called when there is a cached image.
Robert Phillipsac6b1fa2017-03-20 08:38:50 -0400139 sk_sp<SkImage> image(this->refCachedImage());
bsalomoneaaaf0b2015-01-23 08:08:04 -0800140 SkASSERT(image);
Robert Phillips602b79c2017-06-23 11:26:28 -0400141
142 GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
143 SkASSERT(imageProxy);
144
145 if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
Robert Phillips6de99042017-01-31 11:31:39 -0500146 fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +0000147 } else if (kDiscard_ContentChangeMode == mode) {
148 this->SkSurface_Gpu::onDiscard();
robertphillips@google.com97b6b072012-10-31 14:48:39 +0000149 }
reed@google.com5d4ba882012-07-31 15:45:27 +0000150}
151
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +0000152void SkSurface_Gpu::onDiscard() {
Brian Osman11052242016-10-27 14:47:55 -0400153 fDevice->accessRenderTargetContext()->discard();
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +0000154}
155
Greg Daniel51316782017-08-02 15:10:09 +0000156GrSemaphoresSubmitted SkSurface_Gpu::onFlush(int numSemaphores,
157 GrBackendSemaphore signalSemaphores[]) {
Greg Danielc64ee462017-06-15 16:59:49 -0400158 return fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
Greg Daniela5cb7812017-06-16 09:45:32 -0400159}
160
Greg Danielc64ee462017-06-15 16:59:49 -0400161bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
162 return fDevice->wait(numSemaphores, waitSemaphores);
ericrkf7b8b8a2016-02-24 14:49:51 -0800163}
164
Robert Phillipsbe77a022018-04-03 17:17:05 -0400165bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* characterization) const {
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400166 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
Robert Phillips8def8bf2017-11-30 08:46:03 -0500167 GrContext* ctx = fDevice->context();
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400168
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500169 int maxResourceCount;
170 size_t maxResourceBytes;
171 ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
172
Robert Phillipse8fabb22018-02-04 14:33:21 -0500173 bool mipmapped = rtc->asTextureProxy() ? GrMipMapped::kYes == rtc->asTextureProxy()->mipMapped()
174 : false;
175
Robert Phillipsbe77a022018-04-03 17:17:05 -0400176 // TODO: the addition of colorType to the surfaceContext should remove this calculation
177 SkColorType ct;
178 if (!GrPixelConfigToColorType(rtc->colorSpaceInfo().config(), &ct)) {
179 return false;
180 }
181
Greg Daniela070ed72018-04-26 16:31:38 -0400182 bool usesGLFBO0 = rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0();
183 // We should never get in the situation where we have a texture render target that is also
184 // backend by FBO 0.
185 SkASSERT(!usesGLFBO0 || !SkToBool(rtc->asTextureProxy()));
186
Robert Phillipsbe77a022018-04-03 17:17:05 -0400187 SkImageInfo ii = SkImageInfo::Make(rtc->width(), rtc->height(), ct, kPremul_SkAlphaType,
188 rtc->colorSpaceInfo().refColorSpace());
189
190 characterization->set(ctx->threadSafeProxy(), maxResourceBytes, ii, rtc->origin(),
191 rtc->colorSpaceInfo().config(), rtc->fsaaType(), rtc->numStencilSamples(),
192 SkSurfaceCharacterization::Textureable(SkToBool(rtc->asTextureProxy())),
Greg Daniela070ed72018-04-26 16:31:38 -0400193 SkSurfaceCharacterization::MipMapped(mipmapped),
194 SkSurfaceCharacterization::UsesGLFBO0(usesGLFBO0), this->props());
Robert Phillips8def8bf2017-11-30 08:46:03 -0500195
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400196 return true;
197}
198
Robert Phillipsbe77a022018-04-03 17:17:05 -0400199bool SkSurface_Gpu::isCompatible(const SkSurfaceCharacterization& characterization) const {
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400200 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
Robert Phillips8def8bf2017-11-30 08:46:03 -0500201 GrContext* ctx = fDevice->context();
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400202
Robert Phillipsbe77a022018-04-03 17:17:05 -0400203 if (!characterization.isValid()) {
Robert Phillipsfc711a22018-02-13 17:03:00 -0500204 return false;
205 }
206
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500207 // As long as the current state if the context allows for greater or equal resources,
208 // we allow the DDL to be replayed.
Robert Phillipsfc711a22018-02-13 17:03:00 -0500209 // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500210 int maxResourceCount;
211 size_t maxResourceBytes;
212 ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
213
Robert Phillipsbe77a022018-04-03 17:17:05 -0400214 if (characterization.isTextureable()) {
Robert Phillipse8fabb22018-02-04 14:33:21 -0500215 if (!rtc->asTextureProxy()) {
216 // If the characterization was textureable we require the replay dest to also be
217 // textureable. If the characterized surface wasn't textureable we allow the replay
218 // dest to be textureable.
219 return false;
220 }
221
Robert Phillipsbe77a022018-04-03 17:17:05 -0400222 if (characterization.isMipMapped() &&
223 GrMipMapped::kNo == rtc->asTextureProxy()->mipMapped()) {
Robert Phillipse8fabb22018-02-04 14:33:21 -0500224 // Fail if the DDL's surface was mipmapped but the replay surface is not.
225 // Allow drawing to proceed if the DDL was not mipmapped but the replay surface is.
226 return false;
227 }
228 }
229
Greg Daniela070ed72018-04-26 16:31:38 -0400230 if (characterization.usesGLFBO0() != rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0()) {
231 return false;
232 }
233
Robert Phillipsbe77a022018-04-03 17:17:05 -0400234 // TODO: the addition of colorType to the surfaceContext should remove this calculation
235 SkColorType rtcColorType;
236 if (!GrPixelConfigToColorType(rtc->colorSpaceInfo().config(), &rtcColorType)) {
237 return false;
238 }
239
240 return characterization.contextInfo() && characterization.contextInfo()->matches(ctx) &&
241 characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
242 characterization.origin() == rtc->origin() &&
243 characterization.config() == rtc->colorSpaceInfo().config() &&
244 characterization.width() == rtc->width() &&
245 characterization.height() == rtc->height() &&
246 characterization.colorType() == rtcColorType &&
247 characterization.fsaaType() == rtc->fsaaType() &&
248 characterization.stencilCount() == rtc->numStencilSamples() &&
249 SkColorSpace::Equals(characterization.colorSpace(),
250 rtc->colorSpaceInfo().colorSpace()) &&
251 characterization.surfaceProps() == rtc->surfaceProps();
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400252}
253
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500254bool SkSurface_Gpu::onDraw(const SkDeferredDisplayList* ddl) {
Robert Phillipsfc711a22018-02-13 17:03:00 -0500255 if (!ddl || !this->isCompatible(ddl->characterization())) {
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500256 return false;
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400257 }
258
Robert Phillips62000362018-02-01 09:10:04 -0500259 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
260 GrContext* ctx = fDevice->context();
261
262 ctx->contextPriv().copyOpListsFromDDL(ddl, rtc->asRenderTargetProxy());
263 return true;
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400264}
265
266
reed@google.com5d4ba882012-07-31 15:45:27 +0000267///////////////////////////////////////////////////////////////////////////////
268
brianosman0e22eb82016-08-30 07:07:59 -0700269bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
270 switch (info.colorType()) {
271 case kRGBA_F16_SkColorType:
brianosman0e22eb82016-08-30 07:07:59 -0700272 case kRGBA_8888_SkColorType:
273 case kBGRA_8888_SkColorType:
Brian Osman2b23c4b2018-06-01 12:25:08 -0400274 return true;
brianosman0e22eb82016-08-30 07:07:59 -0700275 default:
276 return !info.colorSpace();
277 }
278}
279
Robert Phillipsbe77a022018-04-03 17:17:05 -0400280bool SkSurface_Gpu::Valid(const GrCaps* caps, GrPixelConfig config, SkColorSpace* colorSpace) {
brianosman0e22eb82016-08-30 07:07:59 -0700281 switch (config) {
brianosman0e22eb82016-08-30 07:07:59 -0700282 case kSRGBA_8888_GrPixelConfig:
283 case kSBGRA_8888_GrPixelConfig:
Brian Osman2b23c4b2018-06-01 12:25:08 -0400284 return caps->srgbSupport();
285 case kRGBA_half_GrPixelConfig:
brianosman0e22eb82016-08-30 07:07:59 -0700286 case kRGBA_8888_GrPixelConfig:
287 case kBGRA_8888_GrPixelConfig:
Brian Osman2b23c4b2018-06-01 12:25:08 -0400288 return true;
brianosman0e22eb82016-08-30 07:07:59 -0700289 default:
290 return !colorSpace;
291 }
292}
293
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400294sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* context,
295 const SkSurfaceCharacterization& c,
296 SkBudgeted budgeted) {
Robert Phillipsbe77a022018-04-03 17:17:05 -0400297 if (!context || !c.isValid()) {
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400298 return nullptr;
299 }
300
Greg Daniela070ed72018-04-26 16:31:38 -0400301 if (c.usesGLFBO0()) {
302 // If we are making the surface we will never use FBO0.
303 return nullptr;
304 }
305
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400306 if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), c.config(), c.colorSpace())) {
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400307 return nullptr;
308 }
309
Robert Phillipsbe77a022018-04-03 17:17:05 -0400310 // In order to ensure compatibility we have to match the backend format (i.e. the GrPixelConfig
311 // of the characterization)
312 GrSurfaceDesc desc;
313 desc.fFlags = kRenderTarget_GrSurfaceFlag;
314 desc.fWidth = c.width();
315 desc.fHeight = c.height();
316 desc.fConfig = c.config();
317 desc.fSampleCnt = c.stencilCount();
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400318
Robert Phillipsbe77a022018-04-03 17:17:05 -0400319 sk_sp<GrSurfaceContext> sc(
320 context->contextPriv().makeDeferredSurfaceContext(desc, c.origin(),
321 GrMipMapped(c.isMipMapped()),
322 SkBackingFit::kExact, budgeted,
323 c.refColorSpace(),
324 &c.surfaceProps()));
325 if (!sc || !sc->asRenderTargetContext()) {
326 return nullptr;
327 }
328
329 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, sk_ref_sp(sc->asRenderTargetContext()),
330 c.width(), c.height(),
331 SkGpuDevice::kClear_InitContents));
332 if (!device) {
333 return nullptr;
334 }
335
336 sk_sp<SkSurface> s = sk_make_sp<SkSurface_Gpu>(std::move(device));
337#ifdef SK_DEBUG
338 if (s) {
339 SkSurface_Gpu* gpuSurface = static_cast<SkSurface_Gpu*>(s.get());
340 SkASSERT(gpuSurface->isCompatible(c));
341 }
342#endif
343
344 return s;
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400345}
346
347
reede8f30622016-03-23 18:59:25 -0700348sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
349 const SkImageInfo& info, int sampleCount,
Greg Daniele252f082017-10-23 16:05:23 -0400350 GrSurfaceOrigin origin, const SkSurfaceProps* props,
351 bool shouldCreateWithMips) {
Greg Danielf47069c2017-10-24 11:57:01 -0400352 if (!ctx) {
353 return nullptr;
354 }
brianosman0e22eb82016-08-30 07:07:59 -0700355 if (!SkSurface_Gpu::Valid(info)) {
356 return nullptr;
357 }
Brian Salomonbdecacf2018-02-02 20:32:49 -0500358 sampleCount = SkTMax(1, sampleCount);
Greg Daniele252f082017-10-23 16:05:23 -0400359 GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
360
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400361 if (!ctx->contextPriv().caps()->mipMapSupport()) {
Greg Danielf47069c2017-10-24 11:57:01 -0400362 mipMapped = GrMipMapped::kNo;
363 }
364
robertphillips24e91282016-04-29 06:46:36 -0700365 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
Greg Daniele252f082017-10-23 16:05:23 -0400366 ctx, budgeted, info, sampleCount, origin, props, mipMapped,
367 SkGpuDevice::kClear_InitContents));
bsalomonafe30052015-01-16 07:32:33 -0800368 if (!device) {
halcanary96fcdcc2015-08-27 07:41:13 -0700369 return nullptr;
reed@google.com5d4ba882012-07-31 15:45:27 +0000370 }
robertphillips24e91282016-04-29 06:46:36 -0700371 return sk_make_sp<SkSurface_Gpu>(std::move(device));
reed@google.com5d4ba882012-07-31 15:45:27 +0000372}
reedf037e0b2014-10-30 11:34:15 -0700373
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500374sk_sp<SkSurface> SkSurface_Gpu::MakeWrappedRenderTarget(GrContext* context,
375 sk_sp<GrRenderTargetContext> rtc) {
376 if (!context) {
377 return nullptr;
378 }
379
Brian Salomonf7778972018-03-08 10:13:17 -0500380 int w = rtc->width();
381 int h = rtc->height();
382 sk_sp<SkGpuDevice> device(
383 SkGpuDevice::Make(context, std::move(rtc), w, h, SkGpuDevice::kUninit_InitContents));
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500384 if (!device) {
385 return nullptr;
386 }
387
388 return sk_make_sp<SkSurface_Gpu>(std::move(device));
389}
390
Greg Danielfaa095e2017-12-19 13:15:02 -0500391bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
392 int sampleCnt, SkColorType ct, sk_sp<SkColorSpace> cs,
393 bool texturable) {
Greg Daniel66aebf32018-04-09 09:15:56 -0400394 if (!tex.isValid()) {
395 return false;
396 }
Greg Danielfaa095e2017-12-19 13:15:02 -0500397 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
398 // create a fake image info here.
399 SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
400
401 if (!SkSurface_Gpu::Valid(info)) {
402 return false;
403 }
404
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400405 if (!ctx->contextPriv().caps()->validateBackendTexture(tex, ct, config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500406 return false;
407 }
408
Brian Salomonbdecacf2018-02-02 20:32:49 -0500409 // We don't require that the client gave us an exact valid sample cnt. However, it must be
410 // less than the max supported sample count and 1 if MSAA is unsupported for the color type.
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400411 if (!ctx->contextPriv().caps()->getRenderTargetSampleCount(sampleCnt, *config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500412 return false;
413 }
414
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400415 if (texturable && !ctx->contextPriv().caps()->isConfigTexturable(*config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500416 return false;
417 }
418 return true;
419}
420
421sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
422 GrSurfaceOrigin origin, int sampleCnt,
423 SkColorType colorType,
424 sk_sp<SkColorSpace> colorSpace,
425 const SkSurfaceProps* props) {
426 if (!context) {
427 return nullptr;
428 }
Brian Salomonbdecacf2018-02-02 20:32:49 -0500429 sampleCnt = SkTMax(1, sampleCnt);
Greg Danielfaa095e2017-12-19 13:15:02 -0500430 GrBackendTexture texCopy = tex;
431 if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
432 sampleCnt, colorType, colorSpace, true)) {
433 return nullptr;
434 }
435
Brian Salomon53706772018-03-19 14:18:08 -0400436 if (!context) {
437 return nullptr;
438 }
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400439 if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), texCopy.config(), colorSpace.get())) {
Brian Salomon53706772018-03-19 14:18:08 -0400440 return nullptr;
441 }
442 sampleCnt = SkTMax(1, sampleCnt);
443
444 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext(
445 texCopy,
446 origin,
447 sampleCnt,
448 std::move(colorSpace),
449 props));
450 if (!rtc) {
451 return nullptr;
452 }
453
454 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), texCopy.width(),
455 texCopy.height(),
456 SkGpuDevice::kUninit_InitContents));
457 if (!device) {
458 return nullptr;
459 }
460 return sk_make_sp<SkSurface_Gpu>(std::move(device));
Greg Danielfaa095e2017-12-19 13:15:02 -0500461}
462
Greg Danielfaa095e2017-12-19 13:15:02 -0500463bool validate_backend_render_target(GrContext* ctx, const GrBackendRenderTarget& rt,
464 GrPixelConfig* config, SkColorType ct, sk_sp<SkColorSpace> cs) {
465 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
466 // create a fake image info here.
467 SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
468
469 if (!SkSurface_Gpu::Valid(info)) {
470 return false;
471 }
472
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400473 if (!ctx->contextPriv().caps()->validateBackendRenderTarget(rt, ct, config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500474 return false;
475 }
476
Brian Salomonbdecacf2018-02-02 20:32:49 -0500477 if (rt.sampleCnt() > 1) {
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400478 if (ctx->contextPriv().caps()->maxRenderTargetSampleCount(*config) <= 1) {
Brian Salomonbdecacf2018-02-02 20:32:49 -0500479 return false;
480 }
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400481 } else if (!ctx->contextPriv().caps()->isConfigRenderable(*config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500482 return false;
483 }
484
485 return true;
486}
487
488sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
489 const GrBackendRenderTarget& rt,
490 GrSurfaceOrigin origin,
491 SkColorType colorType,
492 sk_sp<SkColorSpace> colorSpace,
493 const SkSurfaceProps* props) {
494 if (!context) {
495 return nullptr;
496 }
Brian Salomon49edccd2018-03-23 15:31:32 -0400497
Greg Danielfaa095e2017-12-19 13:15:02 -0500498 GrBackendRenderTarget rtCopy = rt;
499 if (!validate_backend_render_target(context, rtCopy, &rtCopy.fConfig, colorType, colorSpace)) {
500 return nullptr;
501 }
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400502 if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), rtCopy.config(), colorSpace.get())) {
Brian Salomon49edccd2018-03-23 15:31:32 -0400503 return nullptr;
504 }
Greg Danielfaa095e2017-12-19 13:15:02 -0500505
Brian Salomon49edccd2018-03-23 15:31:32 -0400506 if (!context) {
507 return nullptr;
508 }
509
510 sk_sp<GrRenderTargetContext> rtc(
511 context->contextPriv().makeBackendRenderTargetRenderTargetContext(
512 rtCopy, origin, std::move(colorSpace), props));
513 if (!rtc) {
514 return nullptr;
515 }
516
517 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), rtCopy.width(),
518 rtCopy.height(),
519 SkGpuDevice::kUninit_InitContents));
520 if (!device) {
521 return nullptr;
522 }
523
524 return sk_make_sp<SkSurface_Gpu>(std::move(device));
Greg Danielfaa095e2017-12-19 13:15:02 -0500525}
526
reede8f30622016-03-23 18:59:25 -0700527sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
Greg Daniel7ef28f32017-04-20 16:41:55 +0000528 const GrBackendTexture& tex,
529 GrSurfaceOrigin origin,
530 int sampleCnt,
Brian Salomoncb884702018-03-19 14:01:21 -0400531 SkColorType colorType,
Greg Daniel7ef28f32017-04-20 16:41:55 +0000532 sk_sp<SkColorSpace> colorSpace,
533 const SkSurfaceProps* props) {
534 if (!context) {
535 return nullptr;
536 }
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400537 if (!tex.isValid() ||
538 !SkSurface_Gpu::Valid(context->contextPriv().caps(), tex.config(), colorSpace.get())) {
brianosman0e22eb82016-08-30 07:07:59 -0700539 return nullptr;
540 }
Brian Salomonbdecacf2018-02-02 20:32:49 -0500541 sampleCnt = SkTMax(1, sampleCnt);
Brian Salomoncb884702018-03-19 14:01:21 -0400542 GrBackendTexture texCopy = tex;
543 if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
544 sampleCnt, colorType, colorSpace, false)) {
545 return nullptr;
546 }
robertphillips15c42ca2016-08-04 08:45:02 -0700547
Brian Osman11052242016-10-27 14:47:55 -0400548 sk_sp<GrRenderTargetContext> rtc(
549 context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext(
Brian Salomoncb884702018-03-19 14:01:21 -0400550 texCopy,
551 origin,
552 sampleCnt,
553 std::move(colorSpace),
554 props));
Brian Osman11052242016-10-27 14:47:55 -0400555 if (!rtc) {
ericrkf7b8b8a2016-02-24 14:49:51 -0800556 return nullptr;
557 }
robertphillips15c42ca2016-08-04 08:45:02 -0700558
Greg Daniel7ef28f32017-04-20 16:41:55 +0000559 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
robertphillips24e91282016-04-29 06:46:36 -0700560 SkGpuDevice::kUninit_InitContents));
ericrkf7b8b8a2016-02-24 14:49:51 -0800561 if (!device) {
562 return nullptr;
563 }
robertphillips24e91282016-04-29 06:46:36 -0700564 return sk_make_sp<SkSurface_Gpu>(std::move(device));
ericrkf7b8b8a2016-02-24 14:49:51 -0800565}
566
reedf037e0b2014-10-30 11:34:15 -0700567#endif