• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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