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, |
| 196 bool coordsLimitedToConstraintRect, |
| 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 && coordsLimitedToConstrain
tRect) { |
| 220 return kNoDomain_DomainMode; |
| 221 } |
| 222 |
| 223 // Get the domain inset based on sampling mode (or bail if mipped) |
| 224 SkScalar filterHalfWidth = 0.f; |
| 225 if (filterModeOrNullForBicubic) { |
| 226 switch (*filterModeOrNullForBicubic) { |
| 227 case GrTextureParams::kNone_FilterMode: |
| 228 if (coordsLimitedToConstraintRect) { |
| 229 return kNoDomain_DomainMode; |
| 230 } else { |
| 231 filterHalfWidth = 0.f; |
| 232 } |
| 233 break; |
| 234 case GrTextureParams::kBilerp_FilterMode: |
| 235 filterHalfWidth = .5f; |
| 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 = 1.5f; |
| 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 // We will only set the sides that are required. |
| 263 |
| 264 domainRect->setLargest(); |
| 265 if (coordsLimitedToConstraintRect) { |
| 266 // We may be able to use the fact that the texture coords are limite
d to the constraint |
| 267 // rect in order to avoid having to add a domain. |
| 268 bool needContentAreaConstraint = false; |
| 269 if (textureContentArea->fLeft > 0 && |
| 270 textureContentArea->fLeft + filterHalfWidth > constraintRect.fLe
ft) { |
| 271 domainRect->fLeft = textureContentArea->fLeft + kDomainInset; |
| 272 needContentAreaConstraint = true; |
| 273 } |
| 274 if (textureContentArea->fTop > 0 && |
| 275 textureContentArea->fTop + filterHalfWidth > constraintRect.fTop
) { |
| 276 domainRect->fTop = textureContentArea->fTop + kDomainInset; |
| 277 needContentAreaConstraint = true; |
| 278 } |
| 279 if (textureContentArea->fRight < texW && |
| 280 textureContentArea->fRight - filterHalfWidth < constraintRect.fR
ight) { |
| 281 domainRect->fRight = textureContentArea->fRight - kDomainInset; |
| 282 needContentAreaConstraint = true; |
| 283 } |
| 284 if (textureContentArea->fBottom < texH && |
| 285 textureContentArea->fBottom - filterHalfWidth < constraintRect.f
Bottom) { |
| 286 domainRect->fBottom = textureContentArea->fBottom - kDomainInset
; |
| 287 needContentAreaConstraint = true; |
| 288 } |
| 289 if (!needContentAreaConstraint) { |
| 290 return kNoDomain_DomainMode; |
| 291 } |
| 292 } else { |
| 293 // Our sample coords for the texture are allowed to be outside the c
onstraintRect so we |
| 294 // don't consider it when computing the domain. |
| 295 if (textureContentArea->fLeft != 0) { |
| 296 domainRect->fLeft = textureContentArea->fLeft + kDomainInset; |
| 297 } |
| 298 if (textureContentArea->fTop != 0) { |
| 299 domainRect->fTop = textureContentArea->fTop + kDomainInset; |
| 300 } |
| 301 if (textureContentArea->fRight != texW) { |
| 302 domainRect->fRight = textureContentArea->fRight - kDomainInset; |
| 303 } |
| 304 if (textureContentArea->fBottom != texH) { |
| 305 domainRect->fBottom = textureContentArea->fBottom - kDomainInset
; |
| 306 } |
| 307 } |
| 308 } else { |
| 309 return kNoDomain_DomainMode; |
| 310 } |
| 311 |
| 312 if (domainRect->fLeft > domainRect->fRight) { |
| 313 domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft,
domainRect->fRight); |
| 314 } |
| 315 if (domainRect->fTop > domainRect->fBottom) { |
| 316 domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, d
omainRect->fBottom); |
| 317 } |
| 318 domainRect->fLeft /= texW; |
| 319 domainRect->fTop /= texH; |
| 320 domainRect->fRight /= texW; |
| 321 domainRect->fBottom /= texH; |
| 322 return kDomain_DomainMode; |
| 323 } |
| 324 |
| 325 const GrFragmentProcessor* GrTextureAdjuster::createFragmentProcessor( |
| 326 const SkMatrix& textureMatrix, |
| 327 const SkRect& constraintRect, |
| 328 FilterConstraint filterConstraint, |
| 329 bool coordsLimitedToConstraintRect, |
| 330 const GrTextureParams::FilterMode* filte
rOrNullForBicubic) { |
| 331 |
| 332 const SkIRect* contentArea = this->contentAreaOrNull(); |
| 333 |
| 334 SkRect domain; |
| 335 GrTexture* texture = this->originalTexture(); |
| 336 DomainMode domainMode = |
| 337 determine_domain_mode(constraintRect, filterConstraint, coordsLimitedToC
onstraintRect, |
| 338 texture->width(), texture->height(), |
| 339 contentArea, filterOrNullForBicubic, |
| 340 &domain); |
| 341 if (kTightCopy_DomainMode == domainMode) { |
| 342 // TODO: Copy the texture and adjust the texture matrix (both parts need
to consider |
| 343 // non-int constraint rect) |
| 344 // For now: treat as bilerp and ignore what goes on above level 0. |
| 345 |
| 346 // We only expect MIP maps to require a tight copy. |
| 347 SkASSERT(filterOrNullForBicubic && |
| 348 GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic)
; |
| 349 static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBil
erp_FilterMode; |
| 350 domainMode = |
| 351 determine_domain_mode(constraintRect, filterConstraint, coordsLimite
dToConstraintRect, |
| 352 texture->width(), texture->height(), |
| 353 contentArea, &kBilerp, &domain); |
| 354 SkASSERT(kTightCopy_DomainMode != domainMode); |
| 355 filterOrNullForBicubic = &kBilerp; |
| 356 } |
| 357 SkASSERT(kNoDomain_DomainMode == domainMode || |
| 358 (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom)); |
| 359 if (filterOrNullForBicubic) { |
| 360 if (kDomain_DomainMode == domainMode) { |
| 361 SkASSERT(*filterOrNullForBicubic != GrTextureParams::kMipMap_FilterM
ode); |
| 362 return GrTextureDomainEffect::Create(texture, textureMatrix, domain, |
| 363 GrTextureDomain::kClamp_Mode, |
| 364 *filterOrNullForBicubic); |
| 365 } else { |
| 366 GrTextureParams params(SkShader::kClamp_TileMode, *filterOrNullForBi
cubic); |
| 367 return GrSimpleTextureEffect::Create(texture, textureMatrix, params)
; |
| 368 } |
| 369 } else { |
| 370 if (kDomain_DomainMode == domainMode) { |
| 371 return GrBicubicEffect::Create(texture, textureMatrix, domain); |
| 372 } else { |
| 373 static const SkShader::TileMode kClampClamp[] = |
| 374 { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode }; |
| 375 return GrBicubicEffect::Create(texture, textureMatrix, kClampClamp); |
| 376 } |
| 377 } |
| 378 } |
| 379 |
174 ////////////////////////////////////////////////////////////////////////////// | 380 ////////////////////////////////////////////////////////////////////////////// |
175 | 381 |
176 GrTexture* GrTextureMaker::refTextureForParams(GrContext* ctx, const GrTexturePa
rams& params) { | 382 GrTexture* GrTextureMaker::refTextureForParams(GrContext* ctx, const GrTexturePa
rams& params) { |
177 CopyParams copyParams; | 383 CopyParams copyParams; |
178 if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(),
params, | 384 if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(),
params, |
179 ©Params)) { | 385 ©Params)) { |
180 return this->refOriginalTexture(ctx); | 386 return this->refOriginalTexture(ctx); |
181 } | 387 } |
182 GrUniqueKey copyKey; | 388 GrUniqueKey copyKey; |
183 this->makeCopyKey(copyParams, ©Key); | 389 this->makeCopyKey(copyParams, ©Key); |
(...skipping 16 matching lines...) Expand all Loading... |
200 return result; | 406 return result; |
201 } | 407 } |
202 | 408 |
203 GrTexture* GrTextureMaker::generateTextureForParams(GrContext* ctx, const CopyPa
rams& copyParams) { | 409 GrTexture* GrTextureMaker::generateTextureForParams(GrContext* ctx, const CopyPa
rams& copyParams) { |
204 SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx)); | 410 SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx)); |
205 if (!original) { | 411 if (!original) { |
206 return nullptr; | 412 return nullptr; |
207 } | 413 } |
208 return copy_on_gpu(original, nullptr, copyParams); | 414 return copy_on_gpu(original, nullptr, copyParams); |
209 } | 415 } |
OLD | NEW |