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 , fConfig(fTarget->config())
26 , fWidth(fTarget->width())
27 , fHeight(fTarget->height())
28 , fOrigin(fTarget->origin())
29 , fFit(fit)
30 , fBudgeted(fTarget->resourcePriv().isBudgeted())
31 , fFlags(0)
32 , fUniqueID(fTarget->uniqueID()) // Note: converting from unique resource ID to a proxy ID!
33 , fNeedsClear(false)
34 , fGpuMemorySize(kInvalidGpuMemorySize)
35 , fLastOpList(nullptr) {}
36
~GrSurfaceProxy()37 GrSurfaceProxy::~GrSurfaceProxy() {
38 // For this to be deleted the opList that held a ref on it (if there was one) must have been
39 // deleted. Which would have cleared out this back pointer.
40 SkASSERT(!fLastOpList);
41 }
42
createSurfaceImpl(GrResourceProvider * resourceProvider,int sampleCnt,GrSurfaceFlags flags,bool isMipMapped,SkDestinationSurfaceColorMode mipColorMode) const43 sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(
44 GrResourceProvider* resourceProvider, int sampleCnt,
45 GrSurfaceFlags flags, bool isMipMapped,
46 SkDestinationSurfaceColorMode mipColorMode) const {
47 GrSurfaceDesc desc;
48 desc.fConfig = fConfig;
49 desc.fWidth = fWidth;
50 desc.fHeight = fHeight;
51 desc.fOrigin = fOrigin;
52 desc.fSampleCnt = sampleCnt;
53 desc.fIsMipMapped = isMipMapped;
54 desc.fFlags = flags;
55 if (fNeedsClear) {
56 desc.fFlags |= kPerformInitialClear_GrSurfaceFlag;
57 }
58
59 sk_sp<GrSurface> surface;
60 if (SkBackingFit::kApprox == fFit) {
61 surface.reset(resourceProvider->createApproxTexture(desc, fFlags).release());
62 } else {
63 surface.reset(resourceProvider->createTexture(desc, fBudgeted, fFlags).release());
64 }
65 if (surface) {
66 surface->asTexture()->texturePriv().setMipColorMode(mipColorMode);
67 }
68
69 return surface;
70 }
71
assign(sk_sp<GrSurface> surface)72 void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) {
73 SkASSERT(!fTarget && surface);
74 fTarget = surface.release();
75 this->INHERITED::transferRefs();
76
77 #ifdef SK_DEBUG
78 if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
79 SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
80 }
81 #endif
82 }
83
instantiateImpl(GrResourceProvider * resourceProvider,int sampleCnt,GrSurfaceFlags flags,bool isMipMapped,SkDestinationSurfaceColorMode mipColorMode)84 bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
85 GrSurfaceFlags flags, bool isMipMapped,
86 SkDestinationSurfaceColorMode mipColorMode) {
87 if (fTarget) {
88 return true;
89 }
90
91 sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, sampleCnt, flags,
92 isMipMapped, mipColorMode);
93 if (!surface) {
94 return false;
95 }
96
97 this->assign(std::move(surface));
98 return true;
99 }
100
setLastOpList(GrOpList * opList)101 void GrSurfaceProxy::setLastOpList(GrOpList* opList) {
102 #ifdef SK_DEBUG
103 if (fLastOpList) {
104 SkASSERT(fLastOpList->isClosed());
105 }
106 #endif
107
108 // Un-reffed
109 fLastOpList = opList;
110 }
111
getLastRenderTargetOpList()112 GrRenderTargetOpList* GrSurfaceProxy::getLastRenderTargetOpList() {
113 return fLastOpList ? fLastOpList->asRenderTargetOpList() : nullptr;
114 }
115
getLastTextureOpList()116 GrTextureOpList* GrSurfaceProxy::getLastTextureOpList() {
117 return fLastOpList ? fLastOpList->asTextureOpList() : nullptr;
118 }
119
MakeWrapped(sk_sp<GrSurface> surf)120 sk_sp<GrSurfaceProxy> GrSurfaceProxy::MakeWrapped(sk_sp<GrSurface> surf) {
121 if (!surf) {
122 return nullptr;
123 }
124
125 if (surf->asTexture()) {
126 if (surf->asRenderTarget()) {
127 return sk_sp<GrSurfaceProxy>(new GrTextureRenderTargetProxy(std::move(surf)));
128 } else {
129 return sk_sp<GrSurfaceProxy>(new GrTextureProxy(std::move(surf)));
130 }
131 } else {
132 SkASSERT(surf->asRenderTarget());
133
134 // Not texturable
135 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(surf)));
136 }
137 }
138
MakeWrapped(sk_sp<GrTexture> tex)139 sk_sp<GrTextureProxy> GrSurfaceProxy::MakeWrapped(sk_sp<GrTexture> tex) {
140 if (!tex) {
141 return nullptr;
142 }
143
144 if (tex->asRenderTarget()) {
145 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex)));
146 } else {
147 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex)));
148 }
149 }
150
MakeDeferred(GrResourceProvider * resourceProvider,const GrSurfaceDesc & desc,SkBackingFit fit,SkBudgeted budgeted,uint32_t flags)151 sk_sp<GrTextureProxy> GrSurfaceProxy::MakeDeferred(GrResourceProvider* resourceProvider,
152 const GrSurfaceDesc& desc,
153 SkBackingFit fit,
154 SkBudgeted budgeted,
155 uint32_t flags) {
156 SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags);
157
158 const GrCaps* caps = resourceProvider->caps();
159
160 // TODO: move this logic into GrResourceProvider!
161 // TODO: share this testing code with check_texture_creation_params
162 if (!caps->isConfigTexturable(desc.fConfig)) {
163 return nullptr;
164 }
165
166 bool willBeRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
167 if (willBeRT && !caps->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
168 return nullptr;
169 }
170
171 // We currently do not support multisampled textures
172 if (!willBeRT && desc.fSampleCnt > 0) {
173 return nullptr;
174 }
175
176 int maxSize;
177 if (willBeRT) {
178 maxSize = caps->maxRenderTargetSize();
179 } else {
180 maxSize = caps->maxTextureSize();
181 }
182
183 if (desc.fWidth > maxSize || desc.fHeight > maxSize || desc.fWidth <= 0 || desc.fHeight <= 0) {
184 return nullptr;
185 }
186
187 GrSurfaceDesc copyDesc = desc;
188 copyDesc.fSampleCnt = caps->getSampleCount(desc.fSampleCnt, desc.fConfig);
189
190 if (willBeRT) {
191 // We know anything we instantiate later from this deferred path will be
192 // both texturable and renderable
193 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*caps, copyDesc, fit,
194 budgeted, flags));
195 }
196
197 return sk_sp<GrTextureProxy>(new GrTextureProxy(copyDesc, fit, budgeted, nullptr, 0, flags));
198 }
199
MakeDeferred(GrResourceProvider * resourceProvider,const GrSurfaceDesc & desc,SkBudgeted budgeted,const void * srcData,size_t rowBytes)200 sk_sp<GrTextureProxy> GrSurfaceProxy::MakeDeferred(GrResourceProvider* resourceProvider,
201 const GrSurfaceDesc& desc,
202 SkBudgeted budgeted,
203 const void* srcData,
204 size_t rowBytes) {
205 if (srcData) {
206 GrMipLevel mipLevel = { srcData, rowBytes };
207
208 return resourceProvider->createTextureProxy(desc, budgeted, mipLevel);
209 }
210
211 return GrSurfaceProxy::MakeDeferred(resourceProvider, desc, SkBackingFit::kExact, budgeted);
212 }
213
MakeDeferredMipMap(GrResourceProvider * resourceProvider,const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel texels[],int mipLevelCount,SkDestinationSurfaceColorMode mipColorMode)214 sk_sp<GrTextureProxy> GrSurfaceProxy::MakeDeferredMipMap(
215 GrResourceProvider* resourceProvider,
216 const GrSurfaceDesc& desc,
217 SkBudgeted budgeted,
218 const GrMipLevel texels[],
219 int mipLevelCount,
220 SkDestinationSurfaceColorMode mipColorMode) {
221 if (!mipLevelCount) {
222 if (texels) {
223 return nullptr;
224 }
225 return GrSurfaceProxy::MakeDeferred(resourceProvider, desc, budgeted, nullptr, 0);
226 } else if (1 == mipLevelCount) {
227 if (!texels) {
228 return nullptr;
229 }
230 return resourceProvider->createTextureProxy(desc, budgeted, texels[0]);
231 }
232
233 for (int i = 0; i < mipLevelCount; ++i) {
234 if (!texels[i].fPixels) {
235 return nullptr;
236 }
237 }
238
239 sk_sp<GrTexture> tex(resourceProvider->createTexture(desc, budgeted,
240 texels, mipLevelCount, mipColorMode));
241 if (!tex) {
242 return nullptr;
243 }
244
245 return GrSurfaceProxy::MakeWrapped(std::move(tex));
246 }
247
MakeWrappedBackend(GrContext * context,GrBackendTexture & backendTex,GrSurfaceOrigin origin)248 sk_sp<GrTextureProxy> GrSurfaceProxy::MakeWrappedBackend(GrContext* context,
249 GrBackendTexture& backendTex,
250 GrSurfaceOrigin origin) {
251 sk_sp<GrTexture> tex(context->resourceProvider()->wrapBackendTexture(
252 backendTex, origin, kNone_GrBackendTextureFlag, 0));
253 return GrSurfaceProxy::MakeWrapped(std::move(tex));
254 }
255
256 #ifdef SK_DEBUG
validate(GrContext * context) const257 void GrSurfaceProxy::validate(GrContext* context) const {
258 if (fTarget) {
259 SkASSERT(fTarget->getContext() == context);
260 }
261
262 INHERITED::validate();
263 }
264 #endif
265
Copy(GrContext * context,GrSurfaceProxy * src,SkIRect srcRect,SkBudgeted budgeted)266 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context,
267 GrSurfaceProxy* src,
268 SkIRect srcRect,
269 SkBudgeted budgeted) {
270 if (!srcRect.intersect(SkIRect::MakeWH(src->width(), src->height()))) {
271 return nullptr;
272 }
273
274 GrSurfaceDesc dstDesc;
275 dstDesc.fConfig = src->config();
276 dstDesc.fWidth = srcRect.width();
277 dstDesc.fHeight = srcRect.height();
278 dstDesc.fOrigin = src->origin();
279
280 sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext(
281 dstDesc,
282 SkBackingFit::kExact,
283 budgeted));
284 if (!dstContext) {
285 return nullptr;
286 }
287
288 if (!dstContext->copy(src, srcRect, SkIPoint::Make(0, 0))) {
289 return nullptr;
290 }
291
292 return dstContext->asTextureProxyRef();
293 }
294
Copy(GrContext * context,GrSurfaceProxy * src,SkBudgeted budgeted)295 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context, GrSurfaceProxy* src,
296 SkBudgeted budgeted) {
297 return Copy(context, src, SkIRect::MakeWH(src->width(), src->height()), budgeted);
298 }
299
TestCopy(GrContext * context,const GrSurfaceDesc & dstDesc,GrSurfaceProxy * srcProxy)300 sk_sp<GrSurfaceContext> GrSurfaceProxy::TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc,
301 GrSurfaceProxy* srcProxy) {
302
303 sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext(
304 dstDesc,
305 SkBackingFit::kExact,
306 SkBudgeted::kYes));
307 if (!dstContext) {
308 return nullptr;
309 }
310
311 if (!dstContext->copy(srcProxy)) {
312 return nullptr;
313 }
314
315 return dstContext;
316 }
317
exactify()318 void GrSurfaceProxyPriv::exactify() {
319 if (this->isExact()) {
320 return;
321 }
322
323 SkASSERT(SkBackingFit::kApprox == fProxy->fFit);
324
325 if (fProxy->fTarget) {
326 // The kApprox but already instantiated case. Setting the proxy's width & height to
327 // the instantiated width & height could have side-effects going forward, since we're
328 // obliterating the area of interest information. This call (exactify) only used
329 // when converting an SkSpecialImage to an SkImage so the proxy shouldn't be
330 // used for additional draws.
331 fProxy->fWidth = fProxy->fTarget->width();
332 fProxy->fHeight = fProxy->fTarget->height();
333 return;
334 }
335
336 // The kApprox uninstantiated case. Making this proxy be exact should be okay.
337 // It could mess things up if prior decisions were based on the approximate size.
338 fProxy->fFit = SkBackingFit::kExact;
339 // If fGpuMemorySize is used when caching specialImages for the image filter DAG. If it has
340 // already been computed we want to leave it alone so that amount will be removed when
341 // the special image goes away. If it hasn't been computed yet it might as well compute the
342 // exact amount.
343 }
344
345