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