blob: 57894c2b9ba97827c8640c2bc52d1849b434ec54 [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:
Mike Klein37854712018-06-26 11:43:06 -0400272 case kRGBA_F32_SkColorType:
brianosman0e22eb82016-08-30 07:07:59 -0700273 case kRGBA_8888_SkColorType:
274 case kBGRA_8888_SkColorType:
Brian Osman2b23c4b2018-06-01 12:25:08 -0400275 return true;
brianosman0e22eb82016-08-30 07:07:59 -0700276 default:
277 return !info.colorSpace();
278 }
279}
280
Robert Phillipsbe77a022018-04-03 17:17:05 -0400281bool SkSurface_Gpu::Valid(const GrCaps* caps, GrPixelConfig config, SkColorSpace* colorSpace) {
brianosman0e22eb82016-08-30 07:07:59 -0700282 switch (config) {
brianosman0e22eb82016-08-30 07:07:59 -0700283 case kSRGBA_8888_GrPixelConfig:
284 case kSBGRA_8888_GrPixelConfig:
Brian Osman2b23c4b2018-06-01 12:25:08 -0400285 return caps->srgbSupport();
286 case kRGBA_half_GrPixelConfig:
Mike Klein37854712018-06-26 11:43:06 -0400287 case kRGBA_float_GrPixelConfig:
brianosman0e22eb82016-08-30 07:07:59 -0700288 case kRGBA_8888_GrPixelConfig:
289 case kBGRA_8888_GrPixelConfig:
Brian Osman2b23c4b2018-06-01 12:25:08 -0400290 return true;
brianosman0e22eb82016-08-30 07:07:59 -0700291 default:
292 return !colorSpace;
293 }
294}
295
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400296sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* context,
297 const SkSurfaceCharacterization& c,
298 SkBudgeted budgeted) {
Robert Phillipsbe77a022018-04-03 17:17:05 -0400299 if (!context || !c.isValid()) {
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400300 return nullptr;
301 }
302
Greg Daniela070ed72018-04-26 16:31:38 -0400303 if (c.usesGLFBO0()) {
304 // If we are making the surface we will never use FBO0.
305 return nullptr;
306 }
307
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400308 if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), c.config(), c.colorSpace())) {
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400309 return nullptr;
310 }
311
Robert Phillipsbe77a022018-04-03 17:17:05 -0400312 // In order to ensure compatibility we have to match the backend format (i.e. the GrPixelConfig
313 // of the characterization)
314 GrSurfaceDesc desc;
315 desc.fFlags = kRenderTarget_GrSurfaceFlag;
316 desc.fWidth = c.width();
317 desc.fHeight = c.height();
318 desc.fConfig = c.config();
319 desc.fSampleCnt = c.stencilCount();
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400320
Robert Phillipsbe77a022018-04-03 17:17:05 -0400321 sk_sp<GrSurfaceContext> sc(
322 context->contextPriv().makeDeferredSurfaceContext(desc, c.origin(),
323 GrMipMapped(c.isMipMapped()),
324 SkBackingFit::kExact, budgeted,
325 c.refColorSpace(),
326 &c.surfaceProps()));
327 if (!sc || !sc->asRenderTargetContext()) {
328 return nullptr;
329 }
330
331 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, sk_ref_sp(sc->asRenderTargetContext()),
332 c.width(), c.height(),
333 SkGpuDevice::kClear_InitContents));
334 if (!device) {
335 return nullptr;
336 }
337
338 sk_sp<SkSurface> s = sk_make_sp<SkSurface_Gpu>(std::move(device));
339#ifdef SK_DEBUG
340 if (s) {
341 SkSurface_Gpu* gpuSurface = static_cast<SkSurface_Gpu*>(s.get());
342 SkASSERT(gpuSurface->isCompatible(c));
343 }
344#endif
345
346 return s;
Robert Phillips6b6fcc72018-03-30 13:57:00 -0400347}
348
349
reede8f30622016-03-23 18:59:25 -0700350sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
351 const SkImageInfo& info, int sampleCount,
Greg Daniele252f082017-10-23 16:05:23 -0400352 GrSurfaceOrigin origin, const SkSurfaceProps* props,
353 bool shouldCreateWithMips) {
Greg Danielf47069c2017-10-24 11:57:01 -0400354 if (!ctx) {
355 return nullptr;
356 }
brianosman0e22eb82016-08-30 07:07:59 -0700357 if (!SkSurface_Gpu::Valid(info)) {
358 return nullptr;
359 }
Brian Salomonbdecacf2018-02-02 20:32:49 -0500360 sampleCount = SkTMax(1, sampleCount);
Greg Daniele252f082017-10-23 16:05:23 -0400361 GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
362
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400363 if (!ctx->contextPriv().caps()->mipMapSupport()) {
Greg Danielf47069c2017-10-24 11:57:01 -0400364 mipMapped = GrMipMapped::kNo;
365 }
366
robertphillips24e91282016-04-29 06:46:36 -0700367 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
Greg Daniele252f082017-10-23 16:05:23 -0400368 ctx, budgeted, info, sampleCount, origin, props, mipMapped,
369 SkGpuDevice::kClear_InitContents));
bsalomonafe30052015-01-16 07:32:33 -0800370 if (!device) {
halcanary96fcdcc2015-08-27 07:41:13 -0700371 return nullptr;
reed@google.com5d4ba882012-07-31 15:45:27 +0000372 }
robertphillips24e91282016-04-29 06:46:36 -0700373 return sk_make_sp<SkSurface_Gpu>(std::move(device));
reed@google.com5d4ba882012-07-31 15:45:27 +0000374}
reedf037e0b2014-10-30 11:34:15 -0700375
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500376sk_sp<SkSurface> SkSurface_Gpu::MakeWrappedRenderTarget(GrContext* context,
377 sk_sp<GrRenderTargetContext> rtc) {
378 if (!context) {
379 return nullptr;
380 }
381
Brian Salomonf7778972018-03-08 10:13:17 -0500382 int w = rtc->width();
383 int h = rtc->height();
384 sk_sp<SkGpuDevice> device(
385 SkGpuDevice::Make(context, std::move(rtc), w, h, SkGpuDevice::kUninit_InitContents));
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500386 if (!device) {
387 return nullptr;
388 }
389
390 return sk_make_sp<SkSurface_Gpu>(std::move(device));
391}
392
Greg Danielfaa095e2017-12-19 13:15:02 -0500393bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
394 int sampleCnt, SkColorType ct, sk_sp<SkColorSpace> cs,
395 bool texturable) {
Greg Daniel66aebf32018-04-09 09:15:56 -0400396 if (!tex.isValid()) {
397 return false;
398 }
Greg Danielfaa095e2017-12-19 13:15:02 -0500399 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
400 // create a fake image info here.
401 SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
402
403 if (!SkSurface_Gpu::Valid(info)) {
404 return false;
405 }
406
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400407 if (!ctx->contextPriv().caps()->validateBackendTexture(tex, ct, config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500408 return false;
409 }
410
Brian Salomonbdecacf2018-02-02 20:32:49 -0500411 // We don't require that the client gave us an exact valid sample cnt. However, it must be
412 // less than the max supported sample count and 1 if MSAA is unsupported for the color type.
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400413 if (!ctx->contextPriv().caps()->getRenderTargetSampleCount(sampleCnt, *config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500414 return false;
415 }
416
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400417 if (texturable && !ctx->contextPriv().caps()->isConfigTexturable(*config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500418 return false;
419 }
420 return true;
421}
422
423sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
424 GrSurfaceOrigin origin, int sampleCnt,
425 SkColorType colorType,
426 sk_sp<SkColorSpace> colorSpace,
427 const SkSurfaceProps* props) {
428 if (!context) {
429 return nullptr;
430 }
Brian Salomonbdecacf2018-02-02 20:32:49 -0500431 sampleCnt = SkTMax(1, sampleCnt);
Greg Danielfaa095e2017-12-19 13:15:02 -0500432 GrBackendTexture texCopy = tex;
433 if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
434 sampleCnt, colorType, colorSpace, true)) {
435 return nullptr;
436 }
437
Brian Salomon53706772018-03-19 14:18:08 -0400438 if (!context) {
439 return nullptr;
440 }
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400441 if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), texCopy.config(), colorSpace.get())) {
Brian Salomon53706772018-03-19 14:18:08 -0400442 return nullptr;
443 }
444 sampleCnt = SkTMax(1, sampleCnt);
445
446 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext(
447 texCopy,
448 origin,
449 sampleCnt,
450 std::move(colorSpace),
451 props));
452 if (!rtc) {
453 return nullptr;
454 }
455
456 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), texCopy.width(),
457 texCopy.height(),
458 SkGpuDevice::kUninit_InitContents));
459 if (!device) {
460 return nullptr;
461 }
462 return sk_make_sp<SkSurface_Gpu>(std::move(device));
Greg Danielfaa095e2017-12-19 13:15:02 -0500463}
464
Greg Danielfaa095e2017-12-19 13:15:02 -0500465bool validate_backend_render_target(GrContext* ctx, const GrBackendRenderTarget& rt,
466 GrPixelConfig* config, SkColorType ct, sk_sp<SkColorSpace> cs) {
467 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
468 // create a fake image info here.
469 SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
470
471 if (!SkSurface_Gpu::Valid(info)) {
472 return false;
473 }
474
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400475 if (!ctx->contextPriv().caps()->validateBackendRenderTarget(rt, ct, config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500476 return false;
477 }
478
Brian Salomonbdecacf2018-02-02 20:32:49 -0500479 if (rt.sampleCnt() > 1) {
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400480 if (ctx->contextPriv().caps()->maxRenderTargetSampleCount(*config) <= 1) {
Brian Salomonbdecacf2018-02-02 20:32:49 -0500481 return false;
482 }
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400483 } else if (!ctx->contextPriv().caps()->isConfigRenderable(*config)) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500484 return false;
485 }
486
487 return true;
488}
489
490sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
491 const GrBackendRenderTarget& rt,
492 GrSurfaceOrigin origin,
493 SkColorType colorType,
494 sk_sp<SkColorSpace> colorSpace,
495 const SkSurfaceProps* props) {
496 if (!context) {
497 return nullptr;
498 }
Brian Salomon49edccd2018-03-23 15:31:32 -0400499
Greg Danielfaa095e2017-12-19 13:15:02 -0500500 GrBackendRenderTarget rtCopy = rt;
501 if (!validate_backend_render_target(context, rtCopy, &rtCopy.fConfig, colorType, colorSpace)) {
502 return nullptr;
503 }
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400504 if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), rtCopy.config(), colorSpace.get())) {
Brian Salomon49edccd2018-03-23 15:31:32 -0400505 return nullptr;
506 }
Greg Danielfaa095e2017-12-19 13:15:02 -0500507
Brian Salomon49edccd2018-03-23 15:31:32 -0400508 if (!context) {
509 return nullptr;
510 }
511
512 sk_sp<GrRenderTargetContext> rtc(
513 context->contextPriv().makeBackendRenderTargetRenderTargetContext(
514 rtCopy, origin, std::move(colorSpace), props));
515 if (!rtc) {
516 return nullptr;
517 }
518
519 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), rtCopy.width(),
520 rtCopy.height(),
521 SkGpuDevice::kUninit_InitContents));
522 if (!device) {
523 return nullptr;
524 }
525
526 return sk_make_sp<SkSurface_Gpu>(std::move(device));
Greg Danielfaa095e2017-12-19 13:15:02 -0500527}
528
reede8f30622016-03-23 18:59:25 -0700529sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
Greg Daniel7ef28f32017-04-20 16:41:55 +0000530 const GrBackendTexture& tex,
531 GrSurfaceOrigin origin,
532 int sampleCnt,
Brian Salomoncb884702018-03-19 14:01:21 -0400533 SkColorType colorType,
Greg Daniel7ef28f32017-04-20 16:41:55 +0000534 sk_sp<SkColorSpace> colorSpace,
535 const SkSurfaceProps* props) {
536 if (!context) {
537 return nullptr;
538 }
Justin Novosad21a99d42018-07-17 16:53:43 -0400539
Brian Salomonbdecacf2018-02-02 20:32:49 -0500540 sampleCnt = SkTMax(1, sampleCnt);
Brian Salomoncb884702018-03-19 14:01:21 -0400541 GrBackendTexture texCopy = tex;
542 if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
543 sampleCnt, colorType, colorSpace, false)) {
544 return nullptr;
545 }
robertphillips15c42ca2016-08-04 08:45:02 -0700546
Justin Novosad21a99d42018-07-17 16:53:43 -0400547 if (!SkSurface_Gpu::Valid(context->contextPriv().caps(), texCopy.config(), colorSpace.get())) {
548 return nullptr;
549 }
550
Brian Osman11052242016-10-27 14:47:55 -0400551 sk_sp<GrRenderTargetContext> rtc(
552 context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext(
Brian Salomoncb884702018-03-19 14:01:21 -0400553 texCopy,
554 origin,
555 sampleCnt,
556 std::move(colorSpace),
557 props));
Brian Osman11052242016-10-27 14:47:55 -0400558 if (!rtc) {
ericrkf7b8b8a2016-02-24 14:49:51 -0800559 return nullptr;
560 }
robertphillips15c42ca2016-08-04 08:45:02 -0700561
Greg Daniel7ef28f32017-04-20 16:41:55 +0000562 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
robertphillips24e91282016-04-29 06:46:36 -0700563 SkGpuDevice::kUninit_InitContents));
ericrkf7b8b8a2016-02-24 14:49:51 -0800564 if (!device) {
565 return nullptr;
566 }
robertphillips24e91282016-04-29 06:46:36 -0700567 return sk_make_sp<SkSurface_Gpu>(std::move(device));
ericrkf7b8b8a2016-02-24 14:49:51 -0800568}
569
reedf037e0b2014-10-30 11:34:15 -0700570#endif