OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrTextureParamsAdjuster.h" | 8 #include "GrTextureParamsAdjuster.h" |
9 | 9 |
10 #include "GrCaps.h" | 10 #include "GrCaps.h" |
11 #include "GrContext.h" | 11 #include "GrContext.h" |
12 #include "GrDrawContext.h" | 12 #include "GrDrawContext.h" |
13 #include "GrGpu.h" | 13 #include "GrGpu.h" |
14 #include "GrGpuResourcePriv.h" | 14 #include "GrGpuResourcePriv.h" |
15 #include "GrResourceKey.h" | 15 #include "GrResourceKey.h" |
16 #include "GrTexture.h" | 16 #include "GrTexture.h" |
17 #include "GrTextureParams.h" | 17 #include "GrTextureParams.h" |
18 #include "GrTextureProvider.h" | 18 #include "GrTextureProvider.h" |
19 #include "SkCanvas.h" | 19 #include "SkCanvas.h" |
20 #include "SkGr.h" | 20 #include "SkGr.h" |
21 #include "SkGrPriv.h" | 21 #include "SkGrPriv.h" |
22 #include "effects/GrBicubicEffect.h" | |
22 #include "effects/GrTextureDomain.h" | 23 #include "effects/GrTextureDomain.h" |
23 | 24 |
24 typedef GrTextureProducer::CopyParams CopyParams; | 25 typedef GrTextureProducer::CopyParams CopyParams; |
25 | 26 |
26 ////////////////////////////////////////////////////////////////////////////// | 27 ////////////////////////////////////////////////////////////////////////////// |
27 | 28 |
28 static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset, | 29 static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset, |
29 const CopyParams& copyParams) { | 30 const CopyParams& copyParams) { |
30 SkASSERT(!subset || !subset->isEmpty()); | 31 SkASSERT(!subset || !subset->isEmpty()); |
31 GrContext* context = inputTexture->getContext(); | 32 GrContext* context = inputTexture->getContext(); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
124 contentArea.fRight < original->width() || contentArea.fBottom < original ->height()) { | 125 contentArea.fRight < original->width() || contentArea.fBottom < original ->height()) { |
125 fContentArea.set(contentArea); | 126 fContentArea.set(contentArea); |
126 } | 127 } |
127 } | 128 } |
128 | 129 |
129 GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& par ams, | 130 GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& par ams, |
130 SkIPoint* outOffset) { | 131 SkIPoint* outOffset) { |
131 GrTexture* texture = this->originalTexture(); | 132 GrTexture* texture = this->originalTexture(); |
132 GrContext* context = texture->getContext(); | 133 GrContext* context = texture->getContext(); |
133 CopyParams copyParams; | 134 CopyParams copyParams; |
134 const SkIRect* contentArea = this->contentArea(); | 135 const SkIRect* contentArea = this->contentAreaOrNull(); |
135 | 136 |
136 if (contentArea && GrTextureParams::kMipMap_FilterMode == params.filterMode( )) { | 137 if (contentArea && GrTextureParams::kMipMap_FilterMode == params.filterMode( )) { |
137 // If we generate a MIP chain for texture it will read pixel values from outside the content | 138 // If we generate a MIP chain for texture it will read pixel values from outside the content |
138 // area. | 139 // area. |
139 copyParams.fWidth = contentArea->width(); | 140 copyParams.fWidth = contentArea->width(); |
140 copyParams.fHeight = contentArea->height(); | 141 copyParams.fHeight = contentArea->height(); |
141 copyParams.fFilter = GrTextureParams::kBilerp_FilterMode; | 142 copyParams.fFilter = GrTextureParams::kBilerp_FilterMode; |
142 } else if (!context->getGpu()->makeCopyForTextureParams(texture->width(), te xture->height(), | 143 } else if (!context->getGpu()->makeCopyForTextureParams(texture->width(), te xture->height(), |
143 params, ©Params) ) { | 144 params, ©Params) ) { |
144 if (outOffset) { | 145 if (outOffset) { |
(...skipping 19 matching lines...) Expand all Loading... | |
164 result->resourcePriv().setUniqueKey(key); | 165 result->resourcePriv().setUniqueKey(key); |
165 this->didCacheCopy(key); | 166 this->didCacheCopy(key); |
166 } | 167 } |
167 if (outOffset) { | 168 if (outOffset) { |
168 outOffset->set(0, 0); | 169 outOffset->set(0, 0); |
169 } | 170 } |
170 } | 171 } |
171 return result; | 172 return result; |
172 } | 173 } |
173 | 174 |
175 enum DomainMode { | |
176 kNoDomain_DomainMode, | |
177 kDomain_DomainMode, | |
178 kTightCopy_DomainMode | |
179 }; | |
180 | |
181 /** Determines whether a texture domain is necessary and if so what domain to us e. There are two | |
182 * rectangles to consider: | |
183 * - The first is the content area specified by the texture adjuster. We can *n ever* allow | |
184 * filtering to cause bleed of pixels outside this rectangle. | |
185 * - The second rectangle is the constraint rectangle, which is known to be con tained by the | |
186 * content area. The filterConstraint specifies whether we are allowed to ble ed across this | |
187 * rect. | |
188 * | |
189 * We want to avoid using a domain if possible. We consider the above rectangle s, the filter type, | |
190 * and whether the coords generated by the draw would all fall within the const raint rect. If the | |
191 * latter is true we only need to consider whether the filter would extend beyo nd the rects. | |
192 */ | |
193 static DomainMode determine_domain_mode( | |
194 const SkRect& constraintRect, | |
195 GrTextureAdjuster::FilterConstraint filterCo nstraint, | |
robertphillips
2015/11/06 20:54:51
...LimitedTo... (i.e., add "To") ?
Contraint -> Co
bsalomon
2015/11/09 19:35:22
Done.
| |
196 bool coordsLimitedContraintRect, | |
197 int texW, int texH, | |
198 const SkIRect* textureContentArea, | |
199 const GrTextureParams::FilterMode* filterMod eOrNullForBicubic, | |
200 SkRect* domainRect) { | |
201 | |
202 SkASSERT(SkRect::MakeIWH(texW, texH).contains(constraintRect)); | |
203 // We only expect a content area rect if there is some non-content area. | |
204 SkASSERT(!textureContentArea || | |
205 (!textureContentArea->contains(SkIRect::MakeWH(texW, texH)) && | |
206 SkRect::Make(*textureContentArea).contains(constraintRect))); | |
207 | |
208 SkRect textureBounds = SkRect::MakeIWH(texW, texH); | |
209 // If the src rectangle contains the whole texture then no need for a domain . | |
210 if (constraintRect.contains(textureBounds)) { | |
211 return kNoDomain_DomainMode; | |
212 } | |
213 | |
214 bool restrictFilterToRect = (filterConstraint == GrTextureAdjuster::kYes_Fil terConstraint); | |
215 | |
216 // If we can filter outside the constraint rect, and there is no non-content area of the | |
217 // texture, and we aren't going to generate sample coords outside the constr aint rect then we | |
218 // don't need a domain. | |
219 if (!restrictFilterToRect && !textureContentArea && coordsLimitedContraintRe ct) { | |
220 return kNoDomain_DomainMode; | |
221 } | |
222 | |
223 // Get the domain inset based on sampling mode (or bail if mipped) | |
224 SkScalar filterHalfWidth; | |
225 if (filterModeOrNullForBicubic) { | |
226 switch (*filterModeOrNullForBicubic) { | |
227 case GrTextureParams::kNone_FilterMode: | |
228 if (coordsLimitedContraintRect) { | |
229 return kNoDomain_DomainMode; | |
230 } else { | |
231 filterHalfWidth = 0.f; | |
232 } | |
233 break; | |
234 case GrTextureParams::kBilerp_FilterMode: | |
robertphillips
2015/11/06 20:54:51
Wouldn't this be 0.5f for half filter width ? Isn'
bsalomon
2015/11/09 19:35:22
It's supposed to really be half-width, fixed the v
| |
235 filterHalfWidth = 1.f; | |
236 break; | |
237 case GrTextureParams::kMipMap_FilterMode: | |
238 // No domain can save use here. | |
239 return kTightCopy_DomainMode; | |
240 } | |
241 } else { | |
242 // bicubic does nearest filtering internally. | |
243 filterHalfWidth = 2.f; | |
244 } | |
245 | |
246 // Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center | |
247 // of the edge texel. Pinning to the texel center has no impact on nearest m ode and MIP-maps | |
248 | |
249 static const SkScalar kDomainInset = 0.5f; | |
250 // Figure out the limits of pixels we're allowed to sample from. | |
251 // Unless we know the amount of outset and the texture matrix we have to con servatively enforce | |
252 // the domain. | |
253 if (restrictFilterToRect) { | |
254 domainRect->fLeft = constraintRect.fLeft + kDomainInset; | |
255 domainRect->fTop = constraintRect.fTop + kDomainInset; | |
256 domainRect->fRight = constraintRect.fRight - kDomainInset; | |
257 domainRect->fBottom = constraintRect.fBottom - kDomainInset; | |
258 } else if (textureContentArea) { | |
259 // If we got here then: there is a textureContentArea, the coords are li mited to the | |
260 // constraint rect, and we're allowed to filter across the constraint re ct boundary. So | |
261 // we check whether the filter would reach across the edge of the conten t area. | |
262 bool needContentAreaConstraint = false; | |
263 // We will only set the sides that are required. | |
264 domainRect->setLargest(); | |
265 if (textureContentArea->fLeft > 0 && | |
266 textureContentArea->fLeft + filterHalfWidth > constraintRect.fLeft) { | |
267 domainRect->fLeft = textureContentArea->fLeft + kDomainInset; | |
268 needContentAreaConstraint = true; | |
269 } | |
270 if (textureContentArea->fTop > 0 && | |
271 textureContentArea->fTop + filterHalfWidth > constraintRect.fTop) { | |
272 domainRect->fTop = textureContentArea->fTop + kDomainInset; | |
273 needContentAreaConstraint = true; | |
274 } | |
robertphillips
2015/11/06 20:54:51
texW-1 ?
bsalomon
2015/11/09 19:35:22
no, if fRight is equal to texW we don't need a dom
| |
275 if (textureContentArea->fRight < texW && | |
276 textureContentArea->fRight - filterHalfWidth < constraintRect.fRight ) { | |
277 domainRect->fRight = textureContentArea->fRight - kDomainInset; | |
278 needContentAreaConstraint = true; | |
279 } | |
robertphillips
2015/11/06 20:54:51
texH ?
texH-1 ?
bsalomon
2015/11/09 19:35:22
texH
| |
280 if (textureContentArea->fBottom < texW && | |
281 textureContentArea->fBottom - filterHalfWidth < constraintRect.fBott om) { | |
282 domainRect->fBottom = textureContentArea->fBottom - kDomainInset; | |
283 needContentAreaConstraint = true; | |
284 } | |
285 if (!needContentAreaConstraint) { | |
286 return kNoDomain_DomainMode; | |
287 } | |
288 } else { | |
289 return kNoDomain_DomainMode; | |
290 } | |
291 | |
292 if (domainRect->fLeft > domainRect->fRight) { | |
293 domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight); | |
294 } | |
295 if (domainRect->fTop > domainRect->fBottom) { | |
296 domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, d omainRect->fBottom); | |
297 } | |
298 domainRect->fLeft /= texW; | |
299 domainRect->fTop /= texH; | |
300 domainRect->fRight /= texW; | |
301 domainRect->fBottom /= texH; | |
302 return kDomain_DomainMode; | |
303 } | |
304 | |
305 const GrFragmentProcessor* GrTextureAdjuster::createFragmentProcessor( | |
306 const SkMatrix& textureMatrix, | |
307 const SkRect& constraintRect, | |
308 FilterConstraint filterConstraint, | |
309 bool coordsLimitedToConstraintRect, | |
310 const GrTextureParams::FilterMode* filte rOrNullForBicubic) { | |
311 | |
312 const SkIRect* contentArea = this->contentAreaOrNull(); | |
313 | |
314 SkRect domain; | |
315 GrTexture* texture = this->originalTexture(); | |
316 DomainMode domainMode = | |
317 determine_domain_mode(constraintRect, filterConstraint, coordsLimitedToC onstraintRect, | |
318 texture->width(), texture->height(), | |
319 contentArea, filterOrNullForBicubic, | |
320 &domain); | |
321 if (kTightCopy_DomainMode == domainMode) { | |
322 // TODO: Copy the texture and adjust the texture matrix (both parts need to consider | |
323 // non-int constraint rect) | |
324 // For now: treat as bilerp and ignore what goes on above level 0. | |
325 SkASSERT(filterOrNullForBicubic && | |
326 GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic) ; | |
327 static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBil erp_FilterMode; | |
328 domainMode = | |
329 determine_domain_mode(constraintRect, filterConstraint, coordsLimite dToConstraintRect, | |
330 texture->width(), texture->height(), | |
331 contentArea, &kBilerp, &domain); | |
332 SkASSERT(kTightCopy_DomainMode != domainMode); | |
333 filterOrNullForBicubic = &kBilerp; | |
334 } | |
335 SkASSERT(kNoDomain_DomainMode == domainMode || | |
336 (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom)); | |
337 if (filterOrNullForBicubic) { | |
338 if (kDomain_DomainMode == domainMode) { | |
robertphillips
2015/11/06 20:54:51
// All mipmapped textures should be tight (and not
bsalomon
2015/11/09 19:35:22
Done.
| |
339 SkASSERT(*filterOrNullForBicubic != GrTextureParams::kMipMap_FilterM ode); | |
340 return GrTextureDomainEffect::Create(texture, textureMatrix, domain, | |
341 GrTextureDomain::kClamp_Mode, | |
342 *filterOrNullForBicubic); | |
343 } else { | |
344 GrTextureParams params(SkShader::kClamp_TileMode, *filterOrNullForBi cubic); | |
345 return GrSimpleTextureEffect::Create(texture, textureMatrix, params) ; | |
346 } | |
347 } else { | |
348 if (kDomain_DomainMode == domainMode) { | |
349 return GrBicubicEffect::Create(texture, textureMatrix, domain); | |
350 } else { | |
351 static const SkShader::TileMode kClampClamp[] = | |
352 { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode }; | |
353 return GrBicubicEffect::Create(texture, textureMatrix, kClampClamp); | |
354 } | |
355 } | |
356 } | |
357 | |
174 ////////////////////////////////////////////////////////////////////////////// | 358 ////////////////////////////////////////////////////////////////////////////// |
175 | 359 |
176 GrTexture* GrTextureMaker::refTextureForParams(GrContext* ctx, const GrTexturePa rams& params) { | 360 GrTexture* GrTextureMaker::refTextureForParams(GrContext* ctx, const GrTexturePa rams& params) { |
177 CopyParams copyParams; | 361 CopyParams copyParams; |
178 if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params, | 362 if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params, |
179 ©Params)) { | 363 ©Params)) { |
180 return this->refOriginalTexture(ctx); | 364 return this->refOriginalTexture(ctx); |
181 } | 365 } |
182 GrUniqueKey copyKey; | 366 GrUniqueKey copyKey; |
183 this->makeCopyKey(copyParams, ©Key); | 367 this->makeCopyKey(copyParams, ©Key); |
(...skipping 16 matching lines...) Expand all Loading... | |
200 return result; | 384 return result; |
201 } | 385 } |
202 | 386 |
203 GrTexture* GrTextureMaker::generateTextureForParams(GrContext* ctx, const CopyPa rams& copyParams) { | 387 GrTexture* GrTextureMaker::generateTextureForParams(GrContext* ctx, const CopyPa rams& copyParams) { |
204 SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx)); | 388 SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx)); |
205 if (!original) { | 389 if (!original) { |
206 return nullptr; | 390 return nullptr; |
207 } | 391 } |
208 return copy_on_gpu(original, nullptr, copyParams); | 392 return copy_on_gpu(original, nullptr, copyParams); |
209 } | 393 } |
OLD | NEW |