1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "GrSurfaceProxy.h"
9 #include "GrSurfaceProxyPriv.h"
10
11 #include "GrCaps.h"
12 #include "GrContext.h"
13 #include "GrContextPriv.h"
14 #include "GrGpuResourcePriv.h"
15 #include "GrOpList.h"
16 #include "GrProxyProvider.h"
17 #include "GrSurfaceContext.h"
18 #include "GrTexturePriv.h"
19 #include "GrTextureRenderTargetProxy.h"
20
21 #include "SkMathPriv.h"
22 #include "SkMipMap.h"
23
24 #ifdef SK_DEBUG
is_valid_fully_lazy(const GrSurfaceDesc & desc,SkBackingFit fit)25 static bool is_valid_fully_lazy(const GrSurfaceDesc& desc, SkBackingFit fit) {
26 return desc.fWidth <= 0 &&
27 desc.fHeight <= 0 &&
28 desc.fConfig != kUnknown_GrPixelConfig &&
29 desc.fSampleCnt == 1 &&
30 SkBackingFit::kApprox == fit;
31 }
32
is_valid_partially_lazy(const GrSurfaceDesc & desc)33 static bool is_valid_partially_lazy(const GrSurfaceDesc& desc) {
34 return ((desc.fWidth > 0 && desc.fHeight > 0) ||
35 (desc.fWidth <= 0 && desc.fHeight <= 0)) &&
36 desc.fConfig != kUnknown_GrPixelConfig;
37 }
38
is_valid_non_lazy(const GrSurfaceDesc & desc)39 static bool is_valid_non_lazy(const GrSurfaceDesc& desc) {
40 return desc.fWidth > 0 &&
41 desc.fHeight > 0 &&
42 desc.fConfig != kUnknown_GrPixelConfig;
43 }
44 #endif
45
46 // Lazy-callback version
GrSurfaceProxy(LazyInstantiateCallback && callback,const GrSurfaceDesc & desc,SkBackingFit fit,SkBudgeted budgeted,uint32_t flags)47 GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback, const GrSurfaceDesc& desc,
48 SkBackingFit fit, SkBudgeted budgeted, uint32_t flags)
49 : fConfig(desc.fConfig)
50 , fWidth(desc.fWidth)
51 , fHeight(desc.fHeight)
52 , fOrigin(desc.fOrigin)
53 , fFit(fit)
54 , fBudgeted(budgeted)
55 , fFlags(flags)
56 , fLazyInstantiateCallback(std::move(callback))
57 , fNeedsClear(SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag))
58 , fGpuMemorySize(kInvalidGpuMemorySize)
59 , fLastOpList(nullptr) {
60 // NOTE: the default fUniqueID ctor pulls a value from the same pool as the GrGpuResources.
61 if (fLazyInstantiateCallback) {
62 SkASSERT(is_valid_fully_lazy(desc, fit) || is_valid_partially_lazy(desc));
63 } else {
64 SkASSERT(is_valid_non_lazy(desc));
65 }
66
67 }
68
69 // Wrapped version
GrSurfaceProxy(sk_sp<GrSurface> surface,GrSurfaceOrigin origin,SkBackingFit fit)70 GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface, GrSurfaceOrigin origin, SkBackingFit fit)
71 : INHERITED(std::move(surface))
72 , fConfig(fTarget->config())
73 , fWidth(fTarget->width())
74 , fHeight(fTarget->height())
75 , fOrigin(origin)
76 , fFit(fit)
77 , fBudgeted(fTarget->resourcePriv().isBudgeted())
78 , fFlags(0)
79 , fUniqueID(fTarget->uniqueID()) // Note: converting from unique resource ID to a proxy ID!
80 , fNeedsClear(false)
81 , fGpuMemorySize(kInvalidGpuMemorySize)
82 , fLastOpList(nullptr) {
83 }
84
~GrSurfaceProxy()85 GrSurfaceProxy::~GrSurfaceProxy() {
86 if (fLazyInstantiateCallback) {
87 // We call the callback with a null GrResourceProvider to signal that the lambda should
88 // clean itself up if it is holding onto any captured objects.
89 this->fLazyInstantiateCallback(nullptr, nullptr);
90 }
91 // For this to be deleted the opList that held a ref on it (if there was one) must have been
92 // deleted. Which would have cleared out this back pointer.
93 SkASSERT(!fLastOpList);
94 }
95
AttachStencilIfNeeded(GrResourceProvider * resourceProvider,GrSurface * surface,bool needsStencil)96 bool GrSurfaceProxyPriv::AttachStencilIfNeeded(GrResourceProvider* resourceProvider,
97 GrSurface* surface, bool needsStencil) {
98 if (needsStencil) {
99 GrRenderTarget* rt = surface->asRenderTarget();
100 if (!rt) {
101 SkASSERT(0);
102 return false;
103 }
104
105 if (!resourceProvider->attachStencilAttachment(rt)) {
106 return false;
107 }
108 }
109
110 return true;
111 }
112
createSurfaceImpl(GrResourceProvider * resourceProvider,int sampleCnt,bool needsStencil,GrSurfaceFlags flags,GrMipMapped mipMapped,SkDestinationSurfaceColorMode mipColorMode) const113 sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(
114 GrResourceProvider* resourceProvider,
115 int sampleCnt, bool needsStencil,
116 GrSurfaceFlags flags, GrMipMapped mipMapped,
117 SkDestinationSurfaceColorMode mipColorMode) const {
118 SkASSERT(GrSurfaceProxy::LazyState::kNot == this->lazyInstantiationState());
119 SkASSERT(GrMipMapped::kNo == mipMapped);
120 GrSurfaceDesc desc;
121 desc.fFlags = flags;
122 if (fNeedsClear) {
123 desc.fFlags |= kPerformInitialClear_GrSurfaceFlag;
124 }
125 desc.fOrigin = fOrigin;
126 desc.fWidth = fWidth;
127 desc.fHeight = fHeight;
128 desc.fConfig = fConfig;
129 desc.fSampleCnt = sampleCnt;
130
131 sk_sp<GrSurface> surface;
132 if (SkBackingFit::kApprox == fFit) {
133 surface.reset(resourceProvider->createApproxTexture(desc, fFlags).release());
134 } else {
135 surface.reset(resourceProvider->createTexture(desc, fBudgeted, fFlags).release());
136 }
137 if (!surface) {
138 return nullptr;
139 }
140
141 surface->asTexture()->texturePriv().setMipColorMode(mipColorMode);
142
143 if (!GrSurfaceProxyPriv::AttachStencilIfNeeded(resourceProvider, surface.get(), needsStencil)) {
144 return nullptr;
145 }
146
147 return surface;
148 }
149
assign(sk_sp<GrSurface> surface)150 void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) {
151 SkASSERT(!fTarget && surface);
152 fTarget = surface.release();
153 this->INHERITED::transferRefs();
154
155 #ifdef SK_DEBUG
156 if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
157 SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
158 }
159 #endif
160 }
161
instantiateImpl(GrResourceProvider * resourceProvider,int sampleCnt,bool needsStencil,GrSurfaceFlags flags,GrMipMapped mipMapped,SkDestinationSurfaceColorMode mipColorMode,const GrUniqueKey * uniqueKey)162 bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
163 bool needsStencil, GrSurfaceFlags flags, GrMipMapped mipMapped,
164 SkDestinationSurfaceColorMode mipColorMode,
165 const GrUniqueKey* uniqueKey) {
166 SkASSERT(LazyState::kNot == this->lazyInstantiationState());
167 if (fTarget) {
168 if (uniqueKey) {
169 SkASSERT(fTarget->getUniqueKey() == *uniqueKey);
170 }
171 return GrSurfaceProxyPriv::AttachStencilIfNeeded(resourceProvider, fTarget, needsStencil);
172 }
173
174 sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, sampleCnt, needsStencil,
175 flags, mipMapped, mipColorMode);
176 if (!surface) {
177 return false;
178 }
179
180 // If there was an invalidation message pending for this key, we might have just processed it,
181 // causing the key (stored on this proxy) to become invalid.
182 if (uniqueKey && uniqueKey->isValid()) {
183 resourceProvider->assignUniqueKeyToResource(*uniqueKey, surface.get());
184 }
185
186 this->assign(std::move(surface));
187 return true;
188 }
189
computeScratchKey(GrScratchKey * key) const190 void GrSurfaceProxy::computeScratchKey(GrScratchKey* key) const {
191 SkASSERT(LazyState::kFully != this->lazyInstantiationState());
192 const GrRenderTargetProxy* rtp = this->asRenderTargetProxy();
193 int sampleCount = 1;
194 if (rtp) {
195 sampleCount = rtp->numStencilSamples();
196 }
197
198 const GrTextureProxy* tp = this->asTextureProxy();
199 GrMipMapped mipMapped = GrMipMapped::kNo;
200 if (tp) {
201 mipMapped = tp->mipMapped();
202 }
203
204 int width = this->worstCaseWidth();
205 int height = this->worstCaseHeight();
206
207 GrTexturePriv::ComputeScratchKey(this->config(), width, height, SkToBool(rtp), sampleCount,
208 mipMapped, key);
209 }
210
setLastOpList(GrOpList * opList)211 void GrSurfaceProxy::setLastOpList(GrOpList* opList) {
212 #ifdef SK_DEBUG
213 if (fLastOpList) {
214 SkASSERT(fLastOpList->isClosed());
215 }
216 #endif
217
218 // Un-reffed
219 fLastOpList = opList;
220 }
221
getLastRenderTargetOpList()222 GrRenderTargetOpList* GrSurfaceProxy::getLastRenderTargetOpList() {
223 return fLastOpList ? fLastOpList->asRenderTargetOpList() : nullptr;
224 }
225
getLastTextureOpList()226 GrTextureOpList* GrSurfaceProxy::getLastTextureOpList() {
227 return fLastOpList ? fLastOpList->asTextureOpList() : nullptr;
228 }
229
worstCaseWidth() const230 int GrSurfaceProxy::worstCaseWidth() const {
231 SkASSERT(LazyState::kFully != this->lazyInstantiationState());
232 if (fTarget) {
233 return fTarget->width();
234 }
235
236 if (SkBackingFit::kExact == fFit) {
237 return fWidth;
238 }
239 return SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(fWidth));
240 }
241
worstCaseHeight() const242 int GrSurfaceProxy::worstCaseHeight() const {
243 SkASSERT(LazyState::kFully != this->lazyInstantiationState());
244 if (fTarget) {
245 return fTarget->height();
246 }
247
248 if (SkBackingFit::kExact == fFit) {
249 return fHeight;
250 }
251 return SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(fHeight));
252 }
253
254 #ifdef SK_DEBUG
validate(GrContext * context) const255 void GrSurfaceProxy::validate(GrContext* context) const {
256 if (fTarget) {
257 SkASSERT(fTarget->getContext() == context);
258 }
259
260 INHERITED::validate();
261 }
262 #endif
263
Copy(GrContext * context,GrSurfaceProxy * src,GrMipMapped mipMapped,SkIRect srcRect,SkBudgeted budgeted)264 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context,
265 GrSurfaceProxy* src,
266 GrMipMapped mipMapped,
267 SkIRect srcRect,
268 SkBudgeted budgeted) {
269 SkASSERT(LazyState::kFully != src->lazyInstantiationState());
270 if (!srcRect.intersect(SkIRect::MakeWH(src->width(), src->height()))) {
271 return nullptr;
272 }
273
274 GrSurfaceDesc dstDesc;
275 dstDesc.fOrigin = src->origin();
276 dstDesc.fWidth = srcRect.width();
277 dstDesc.fHeight = srcRect.height();
278 dstDesc.fConfig = src->config();
279
280 sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext(
281 dstDesc,
282 mipMapped,
283 SkBackingFit::kExact,
284 budgeted));
285 if (!dstContext) {
286 return nullptr;
287 }
288
289 if (!dstContext->copy(src, srcRect, SkIPoint::Make(0, 0))) {
290 return nullptr;
291 }
292
293 return dstContext->asTextureProxyRef();
294 }
295
Copy(GrContext * context,GrSurfaceProxy * src,GrMipMapped mipMapped,SkBudgeted budgeted)296 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context, GrSurfaceProxy* src,
297 GrMipMapped mipMapped, SkBudgeted budgeted) {
298 SkASSERT(LazyState::kFully != src->lazyInstantiationState());
299 return Copy(context, src, mipMapped, SkIRect::MakeWH(src->width(), src->height()), budgeted);
300 }
301
TestCopy(GrContext * context,const GrSurfaceDesc & dstDesc,GrSurfaceProxy * srcProxy)302 sk_sp<GrSurfaceContext> GrSurfaceProxy::TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc,
303 GrSurfaceProxy* srcProxy) {
304 SkASSERT(LazyState::kFully != srcProxy->lazyInstantiationState());
305 sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext(
306 dstDesc,
307 GrMipMapped::kNo,
308 SkBackingFit::kExact,
309 SkBudgeted::kYes));
310 if (!dstContext) {
311 return nullptr;
312 }
313
314 if (!dstContext->copy(srcProxy)) {
315 return nullptr;
316 }
317
318 return dstContext;
319 }
320
exactify()321 void GrSurfaceProxyPriv::exactify() {
322 SkASSERT(GrSurfaceProxy::LazyState::kFully != fProxy->lazyInstantiationState());
323 if (this->isExact()) {
324 return;
325 }
326
327 SkASSERT(SkBackingFit::kApprox == fProxy->fFit);
328
329 if (fProxy->fTarget) {
330 // The kApprox but already instantiated case. Setting the proxy's width & height to
331 // the instantiated width & height could have side-effects going forward, since we're
332 // obliterating the area of interest information. This call (exactify) only used
333 // when converting an SkSpecialImage to an SkImage so the proxy shouldn't be
334 // used for additional draws.
335 fProxy->fWidth = fProxy->fTarget->width();
336 fProxy->fHeight = fProxy->fTarget->height();
337 return;
338 }
339
340 // The kApprox uninstantiated case. Making this proxy be exact should be okay.
341 // It could mess things up if prior decisions were based on the approximate size.
342 fProxy->fFit = SkBackingFit::kExact;
343 // If fGpuMemorySize is used when caching specialImages for the image filter DAG. If it has
344 // already been computed we want to leave it alone so that amount will be removed when
345 // the special image goes away. If it hasn't been computed yet it might as well compute the
346 // exact amount.
347 }
348
doLazyInstantiation(GrResourceProvider * resourceProvider)349 bool GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvider) {
350 SkASSERT(GrSurfaceProxy::LazyState::kNot != fProxy->lazyInstantiationState());
351
352 GrSurfaceOrigin* outOrigin;
353 if (GrSurfaceProxy::LazyState::kPartially == fProxy->lazyInstantiationState()) {
354 // In the partially instantiated case, we set the origin on the SurfaceProxy at creation
355 // time (via a GrSurfaceDesc). In the lambda, the creation of the texture never needs to
356 // know the origin, and it also can't change or have any effect on it. Thus we just pass in
357 // nullptr in this case since it should never be set.
358 outOrigin = nullptr;
359 } else {
360 outOrigin = &fProxy->fOrigin;
361 }
362
363 sk_sp<GrTexture> texture = fProxy->fLazyInstantiateCallback(resourceProvider, outOrigin);
364
365 if (!texture) {
366 fProxy->fWidth = 0;
367 fProxy->fHeight = 0;
368 fProxy->fOrigin = kTopLeft_GrSurfaceOrigin;
369 return false;
370 }
371
372 fProxy->fWidth = texture->width();
373 fProxy->fHeight = texture->height();
374
375 SkASSERT(texture->config() == fProxy->fConfig);
376 SkDEBUGCODE(fProxy->validateLazyTexture(texture.get());)
377 this->assign(std::move(texture));
378 return true;
379 }
380
381