• Home
  • History
  • Annotate
  • 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 "GrResourceProvider.h"
17 #include "GrSurfaceContext.h"
18 #include "GrTexturePriv.h"
19 #include "GrTextureRenderTargetProxy.h"
20 
21 #include "SkMathPriv.h"
22 
GrSurfaceProxy(sk_sp<GrSurface> surface,SkBackingFit fit)23 GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface, SkBackingFit fit)
24     : INHERITED(std::move(surface))
25     , fDesc(fTarget->desc())
26     , fFit(fit)
27     , fBudgeted(fTarget->resourcePriv().isBudgeted())
28     , fFlags(0)
29     , fUniqueID(fTarget->uniqueID()) // Note: converting from unique resource ID to a proxy ID!
30     , fGpuMemorySize(kInvalidGpuMemorySize)
31     , fLastOpList(nullptr) {
32 }
33 
~GrSurfaceProxy()34 GrSurfaceProxy::~GrSurfaceProxy() {
35     if (fLastOpList) {
36         fLastOpList->clearTarget();
37     }
38     SkSafeUnref(fLastOpList);
39 }
40 
instantiate(GrResourceProvider * resourceProvider)41 GrSurface* GrSurfaceProxy::instantiate(GrResourceProvider* resourceProvider) {
42     if (fTarget) {
43         return fTarget;
44     }
45 
46     if (SkBackingFit::kApprox == fFit) {
47         fTarget = resourceProvider->createApproxTexture(fDesc, fFlags);
48     } else {
49         fTarget = resourceProvider->createTexture(fDesc, fBudgeted, fFlags);
50     }
51     if (!fTarget) {
52         return nullptr;
53     }
54 
55     fTarget->asTexture()->texturePriv().setMipColorMode(fMipColorMode);
56     this->INHERITED::transferRefs();
57 
58 #ifdef SK_DEBUG
59     if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
60         SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
61     }
62 #endif
63 
64     return fTarget;
65 }
66 
worstCaseWidth(const GrCaps & caps) const67 int GrSurfaceProxy::worstCaseWidth(const GrCaps& caps) const {
68     if (fTarget) {
69         return fTarget->width();
70     }
71 
72     if (SkBackingFit::kExact == fFit) {
73         return fDesc.fWidth;
74     }
75 
76     if (caps.reuseScratchTextures() || fDesc.fFlags & kRenderTarget_GrSurfaceFlag) {
77         return SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(fDesc.fWidth));
78     }
79 
80     return fDesc.fWidth;
81 }
82 
worstCaseHeight(const GrCaps & caps) const83 int GrSurfaceProxy::worstCaseHeight(const GrCaps& caps) const {
84     if (fTarget) {
85         return fTarget->height();
86     }
87 
88     if (SkBackingFit::kExact == fFit) {
89         return fDesc.fHeight;
90     }
91 
92     if (caps.reuseScratchTextures() || fDesc.fFlags & kRenderTarget_GrSurfaceFlag) {
93         return SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(fDesc.fHeight));
94     }
95 
96     return fDesc.fHeight;
97 }
98 
setLastOpList(GrOpList * opList)99 void GrSurfaceProxy::setLastOpList(GrOpList* opList) {
100     if (fLastOpList) {
101         // The non-MDB world never closes so we can't check this condition
102 #ifdef ENABLE_MDB
103         SkASSERT(fLastOpList->isClosed());
104 #endif
105         fLastOpList->clearTarget();
106     }
107 
108     SkRefCnt_SafeAssign(fLastOpList, opList);
109 }
110 
getLastRenderTargetOpList()111 GrRenderTargetOpList* GrSurfaceProxy::getLastRenderTargetOpList() {
112     return fLastOpList ? fLastOpList->asRenderTargetOpList() : nullptr;
113 }
114 
getLastTextureOpList()115 GrTextureOpList* GrSurfaceProxy::getLastTextureOpList() {
116     return fLastOpList ? fLastOpList->asTextureOpList() : nullptr;
117 }
118 
MakeWrapped(sk_sp<GrSurface> surf)119 sk_sp<GrSurfaceProxy> GrSurfaceProxy::MakeWrapped(sk_sp<GrSurface> surf) {
120     if (!surf) {
121         return nullptr;
122     }
123 
124     if (surf->asTexture()) {
125         if (surf->asRenderTarget()) {
126             return sk_sp<GrSurfaceProxy>(new GrTextureRenderTargetProxy(std::move(surf)));
127         } else {
128             return sk_sp<GrSurfaceProxy>(new GrTextureProxy(std::move(surf)));
129         }
130     } else {
131         SkASSERT(surf->asRenderTarget());
132 
133         // Not texturable
134         return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(surf)));
135     }
136 }
137 
MakeWrapped(sk_sp<GrTexture> tex)138 sk_sp<GrTextureProxy> GrSurfaceProxy::MakeWrapped(sk_sp<GrTexture> tex) {
139     if (!tex) {
140         return nullptr;
141     }
142 
143     if (tex->asRenderTarget()) {
144         return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex)));
145     } else {
146         return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex)));
147     }
148 }
149 
150 #include "GrResourceProvider.h"
151 
MakeDeferred(GrResourceProvider * resourceProvider,const GrSurfaceDesc & desc,SkBackingFit fit,SkBudgeted budgeted,uint32_t flags)152 sk_sp<GrTextureProxy> GrSurfaceProxy::MakeDeferred(GrResourceProvider* resourceProvider,
153                                                    const GrSurfaceDesc& desc,
154                                                    SkBackingFit fit,
155                                                    SkBudgeted budgeted,
156                                                    uint32_t flags) {
157     SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags);
158 
159     const GrCaps* caps = resourceProvider->caps();
160 
161     // TODO: move this logic into GrResourceProvider!
162     // TODO: share this testing code with check_texture_creation_params
163     if (GrPixelConfigIsCompressed(desc.fConfig)) {
164         if (SkBackingFit::kApprox == fit || kBottomLeft_GrSurfaceOrigin == desc.fOrigin) {
165             // We don't allow scratch compressed textures and, apparently can't Y-flip compressed
166             // textures
167             return nullptr;
168         }
169 
170         if (!caps->npotTextureTileSupport() && (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) {
171             return nullptr;
172         }
173     }
174 
175     if (!caps->isConfigTexturable(desc.fConfig)) {
176         return nullptr;
177     }
178 
179     bool willBeRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
180     if (willBeRT && !caps->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
181         return nullptr;
182     }
183 
184     // We currently do not support multisampled textures
185     if (!willBeRT && desc.fSampleCnt > 0) {
186         return nullptr;
187     }
188 
189     int maxSize;
190     if (willBeRT) {
191         maxSize = caps->maxRenderTargetSize();
192     } else {
193         maxSize = caps->maxTextureSize();
194     }
195 
196     if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
197         return nullptr;
198     }
199 
200     GrSurfaceDesc copyDesc = desc;
201     copyDesc.fSampleCnt = SkTMin(desc.fSampleCnt, caps->maxSampleCount());
202 
203     if (willBeRT) {
204         // We know anything we instantiate later from this deferred path will be
205         // both texturable and renderable
206         return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*caps, copyDesc, fit,
207                                                                     budgeted, flags));
208     }
209 
210     return sk_sp<GrTextureProxy>(new GrTextureProxy(copyDesc, fit, budgeted, nullptr, 0, flags));
211 }
212 
MakeDeferred(GrResourceProvider * resourceProvider,const GrSurfaceDesc & desc,SkBudgeted budgeted,const void * srcData,size_t rowBytes)213 sk_sp<GrTextureProxy> GrSurfaceProxy::MakeDeferred(GrResourceProvider* resourceProvider,
214                                                    const GrSurfaceDesc& desc,
215                                                    SkBudgeted budgeted,
216                                                    const void* srcData,
217                                                    size_t rowBytes) {
218     if (srcData) {
219         // If we have srcData, for now, we create a wrapped GrTextureProxy
220         sk_sp<GrTexture> tex(resourceProvider->createTexture(desc, budgeted, srcData, rowBytes));
221         return GrSurfaceProxy::MakeWrapped(std::move(tex));
222     }
223 
224     return GrSurfaceProxy::MakeDeferred(resourceProvider, desc, SkBackingFit::kExact, budgeted);
225 }
226 
MakeWrappedBackend(GrContext * context,GrBackendTextureDesc & desc)227 sk_sp<GrSurfaceProxy> GrSurfaceProxy::MakeWrappedBackend(GrContext* context,
228                                                          GrBackendTextureDesc& desc) {
229     sk_sp<GrTexture> tex(context->resourceProvider()->wrapBackendTexture(desc));
230     return GrSurfaceProxy::MakeWrapped(std::move(tex));
231 }
232 
233 #ifdef SK_DEBUG
validate(GrContext * context) const234 void GrSurfaceProxy::validate(GrContext* context) const {
235     if (fTarget) {
236         SkASSERT(fTarget->getContext() == context);
237     }
238 
239     INHERITED::validate();
240 }
241 #endif
242 
Copy(GrContext * context,GrSurfaceProxy * src,SkIRect srcRect,SkBudgeted budgeted)243 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context,
244                                            GrSurfaceProxy* src,
245                                            SkIRect srcRect,
246                                            SkBudgeted budgeted) {
247     if (!srcRect.intersect(SkIRect::MakeWH(src->width(), src->height()))) {
248         return nullptr;
249     }
250 
251     GrSurfaceDesc dstDesc = src->desc();
252     dstDesc.fWidth = srcRect.width();
253     dstDesc.fHeight = srcRect.height();
254 
255     sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext(
256                                                                             dstDesc,
257                                                                             SkBackingFit::kExact,
258                                                                             budgeted));
259     if (!dstContext) {
260         return nullptr;
261     }
262 
263     if (!dstContext->copy(src, srcRect, SkIPoint::Make(0, 0))) {
264         return nullptr;
265     }
266 
267     return dstContext->asTextureProxyRef();
268 }
269 
Copy(GrContext * context,GrSurfaceProxy * src,SkBudgeted budgeted)270 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context, GrSurfaceProxy* src,
271                                            SkBudgeted budgeted) {
272     return Copy(context, src, SkIRect::MakeWH(src->width(), src->height()), budgeted);
273 }
274 
TestCopy(GrContext * context,const GrSurfaceDesc & dstDesc,GrSurfaceProxy * srcProxy)275 sk_sp<GrSurfaceContext> GrSurfaceProxy::TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc,
276                                                  GrSurfaceProxy* srcProxy) {
277 
278     sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext(
279                                                                             dstDesc,
280                                                                             SkBackingFit::kExact,
281                                                                             SkBudgeted::kYes));
282     if (!dstContext) {
283         return nullptr;
284     }
285 
286     if (!dstContext->copy(srcProxy)) {
287         return nullptr;
288     }
289 
290     return dstContext;
291 }
292 
exactify()293 void GrSurfaceProxyPriv::exactify() {
294     if (this->isExact()) {
295         return;
296     }
297 
298     SkASSERT(SkBackingFit::kApprox == fProxy->fFit);
299 
300     if (fProxy->fTarget) {
301         // The kApprox but already instantiated case. Setting the proxy's width & height to
302         // the instantiated width & height could have side-effects going forward, since we're
303         // obliterating the area of interest information. This call (exactify) only used
304         // when converting an SkSpecialImage to an SkImage so the proxy shouldn't be
305         // used for additional draws.
306         fProxy->fDesc.fWidth = fProxy->fTarget->width();
307         fProxy->fDesc.fHeight = fProxy->fTarget->height();
308         return;
309     }
310 
311     // The kApprox uninstantiated case. Making this proxy be exact should be okay.
312     // It could mess things up if prior decisions were based on the approximate size.
313     fProxy->fFit = SkBackingFit::kExact;
314     // If fGpuMemorySize is used when caching specialImages for the image filter DAG. If it has
315     // already been computed we want to leave it alone so that amount will be removed when
316     // the special image goes away. If it hasn't been computed yet it might as well compute the
317     // exact amount.
318 }
319 
320