Chromium Code Reviews| 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 |