GrTextureProducer cleanup, phase two: Producer, Adjuster, Maker
Previously: GrTextureProducer, GrTextureAdjuster, and GrTextureMaker were all in GrTextureParamsAdjuster.h. Now they're each in their own header. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=5202 Change-Id: I17fa9057b11511aa4d3e15569ea1c378cfec4c80 Reviewed-on: https://skia-review.googlesource.com/5202 Reviewed-by: Robert Phillips <robertphillips@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
e9f78b41c6
commit
e8e54580c3
@ -200,10 +200,14 @@ skia_gpu_sources = [
|
||||
"$_src/gpu/GrSurfaceProxy.cpp",
|
||||
"$_src/gpu/GrSwizzle.h",
|
||||
"$_src/gpu/GrTexture.cpp",
|
||||
"$_src/gpu/GrTextureAdjuster.cpp",
|
||||
"$_src/gpu/GrTextureAdjuster.h",
|
||||
"$_src/gpu/GrTextureContext.cpp",
|
||||
"$_src/gpu/GrTextureParamsAdjuster.h",
|
||||
"$_src/gpu/GrTextureParamsAdjuster.cpp",
|
||||
"$_src/gpu/GrTextureMaker.cpp",
|
||||
"$_src/gpu/GrTextureMaker.h",
|
||||
"$_src/gpu/GrTexturePriv.h",
|
||||
"$_src/gpu/GrTextureProducer.cpp",
|
||||
"$_src/gpu/GrTextureProducer.h",
|
||||
"$_src/gpu/GrTextureProvider.cpp",
|
||||
"$_src/gpu/GrTextureProxy.cpp",
|
||||
"$_src/gpu/GrTextureRenderTargetProxy.cpp",
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef GrBitmapTextureMaker_DEFINED
|
||||
#define GrBitmapTextureMaker_DEFINED
|
||||
|
||||
#include "GrTextureParamsAdjuster.h"
|
||||
#include "GrTextureMaker.h"
|
||||
|
||||
/** This class manages the conversion of SW-backed bitmaps to GrTextures. If the input bitmap is
|
||||
non-volatile the texture is cached using a key created from the pixels' image id and the
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "GrProgramDesc.h"
|
||||
#include "GrSwizzle.h"
|
||||
#include "GrAllocator.h"
|
||||
#include "GrTextureParamsAdjuster.h"
|
||||
#include "GrTextureProducer.h"
|
||||
#include "GrTypes.h"
|
||||
#include "GrXferProcessor.h"
|
||||
#include "SkPath.h"
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef GrImageTextureMaker_DEFINED
|
||||
#define GrImageTextureMaker_DEFINED
|
||||
|
||||
#include "GrTextureParamsAdjuster.h"
|
||||
#include "GrTextureMaker.h"
|
||||
#include "SkImage.h"
|
||||
|
||||
class SkImageCacherator;
|
||||
|
167
src/gpu/GrTextureAdjuster.cpp
Normal file
167
src/gpu/GrTextureAdjuster.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrTextureAdjuster.h"
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrGpuResourcePriv.h"
|
||||
#include "GrTexture.h"
|
||||
#include "SkGrPriv.h"
|
||||
|
||||
GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, SkAlphaType alphaType,
|
||||
const SkIRect& contentArea, uint32_t uniqueID,
|
||||
SkColorSpace* cs)
|
||||
: INHERITED(contentArea.width(), contentArea.height(),
|
||||
GrPixelConfigIsAlphaOnly(original->config()))
|
||||
, fOriginal(original)
|
||||
, fAlphaType(alphaType)
|
||||
, fColorSpace(cs)
|
||||
, fUniqueID(uniqueID) {
|
||||
SkASSERT(SkIRect::MakeWH(original->width(), original->height()).contains(contentArea));
|
||||
if (contentArea.fLeft > 0 || contentArea.fTop > 0 ||
|
||||
contentArea.fRight < original->width() || contentArea.fBottom < original->height()) {
|
||||
fContentArea.set(contentArea);
|
||||
}
|
||||
}
|
||||
|
||||
void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode) {
|
||||
// Color mode is irrelevant in this case - we already have a texture so we're just sub-setting
|
||||
GrUniqueKey baseKey;
|
||||
GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height()));
|
||||
MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
|
||||
}
|
||||
|
||||
void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) {
|
||||
// We don't currently have a mechanism for notifications on Images!
|
||||
}
|
||||
|
||||
GrTexture* GrTextureAdjuster::refCopy(const CopyParams& copyParams) {
|
||||
GrTexture* texture = this->originalTexture();
|
||||
GrContext* context = texture->getContext();
|
||||
const SkIRect* contentArea = this->contentAreaOrNull();
|
||||
GrUniqueKey key;
|
||||
this->makeCopyKey(copyParams, &key, SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware);
|
||||
if (key.isValid()) {
|
||||
GrTexture* cachedCopy = context->textureProvider()->findAndRefTextureByUniqueKey(key);
|
||||
if (cachedCopy) {
|
||||
return cachedCopy;
|
||||
}
|
||||
}
|
||||
GrTexture* copy = CopyOnGpu(texture, contentArea, copyParams);
|
||||
if (copy) {
|
||||
if (key.isValid()) {
|
||||
copy->resourcePriv().setUniqueKey(key);
|
||||
this->didCacheCopy(key);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
SkIPoint* outOffset) {
|
||||
GrTexture* texture = this->originalTexture();
|
||||
GrContext* context = texture->getContext();
|
||||
CopyParams copyParams;
|
||||
const SkIRect* contentArea = this->contentAreaOrNull();
|
||||
|
||||
if (!context) {
|
||||
// The texture was abandoned.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (contentArea && GrSamplerParams::kMipMap_FilterMode == params.filterMode()) {
|
||||
// If we generate a MIP chain for texture it will read pixel values from outside the content
|
||||
// area.
|
||||
copyParams.fWidth = contentArea->width();
|
||||
copyParams.fHeight = contentArea->height();
|
||||
copyParams.fFilter = GrSamplerParams::kBilerp_FilterMode;
|
||||
} else if (!context->getGpu()->makeCopyForTextureParams(texture, params, ©Params)) {
|
||||
if (outOffset) {
|
||||
if (contentArea) {
|
||||
outOffset->set(contentArea->fLeft, contentArea->fRight);
|
||||
} else {
|
||||
outOffset->set(0, 0);
|
||||
}
|
||||
}
|
||||
return SkRef(texture);
|
||||
}
|
||||
|
||||
GrTexture* copy = this->refCopy(copyParams);
|
||||
if (copy && outOffset) {
|
||||
outOffset->set(0, 0);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
sk_sp<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
|
||||
const SkMatrix& origTextureMatrix,
|
||||
const SkRect& origConstraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
|
||||
SkMatrix textureMatrix = origTextureMatrix;
|
||||
const SkIRect* contentArea = this->contentAreaOrNull();
|
||||
// Convert the constraintRect to be relative to the texture rather than the content area so
|
||||
// that both rects are in the same coordinate system.
|
||||
SkTCopyOnFirstWrite<SkRect> constraintRect(origConstraintRect);
|
||||
if (contentArea) {
|
||||
SkScalar l = SkIntToScalar(contentArea->fLeft);
|
||||
SkScalar t = SkIntToScalar(contentArea->fTop);
|
||||
constraintRect.writable()->offset(l, t);
|
||||
textureMatrix.postTranslate(l, t);
|
||||
}
|
||||
|
||||
SkRect domain;
|
||||
GrSamplerParams params;
|
||||
if (filterOrNullForBicubic) {
|
||||
params.setFilterMode(*filterOrNullForBicubic);
|
||||
}
|
||||
sk_sp<GrTexture> texture(this->refTextureSafeForParams(params, colorMode, nullptr));
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
// If we made a copy then we only copied the contentArea, in which case the new texture is all
|
||||
// content.
|
||||
if (texture.get() != this->originalTexture()) {
|
||||
contentArea = nullptr;
|
||||
}
|
||||
|
||||
DomainMode domainMode =
|
||||
DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
|
||||
texture->width(), texture->height(),
|
||||
contentArea, filterOrNullForBicubic,
|
||||
&domain);
|
||||
if (kTightCopy_DomainMode == domainMode) {
|
||||
// TODO: Copy the texture and adjust the texture matrix (both parts need to consider
|
||||
// non-int constraint rect)
|
||||
// For now: treat as bilerp and ignore what goes on above level 0.
|
||||
|
||||
// We only expect MIP maps to require a tight copy.
|
||||
SkASSERT(filterOrNullForBicubic &&
|
||||
GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic);
|
||||
static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode;
|
||||
domainMode =
|
||||
DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
|
||||
texture->width(), texture->height(),
|
||||
contentArea, &kBilerp, &domain);
|
||||
SkASSERT(kTightCopy_DomainMode != domainMode);
|
||||
}
|
||||
SkASSERT(kNoDomain_DomainMode == domainMode ||
|
||||
(domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
|
||||
textureMatrix.postIDiv(texture->width(), texture->height());
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace,
|
||||
dstColorSpace);
|
||||
return CreateFragmentProcessorForDomainAndFilter(texture.get(), std::move(colorSpaceXform),
|
||||
textureMatrix, domainMode, domain,
|
||||
filterOrNullForBicubic);
|
||||
}
|
66
src/gpu/GrTextureAdjuster.h
Normal file
66
src/gpu/GrTextureAdjuster.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrTextureAdjuster_DEFINED
|
||||
#define GrTextureAdjuster_DEFINED
|
||||
|
||||
#include "GrTextureProducer.h"
|
||||
#include "SkTLazy.h"
|
||||
|
||||
/**
|
||||
* Base class for sources that start out as textures. Optionally allows for a content area subrect.
|
||||
* The intent is not to use content area for subrect rendering. Rather, the pixels outside the
|
||||
* content area have undefined values and shouldn't be read *regardless* of filtering mode or
|
||||
* the SkCanvas::SrcRectConstraint used for subrect draws.
|
||||
*/
|
||||
class GrTextureAdjuster : public GrTextureProducer {
|
||||
public:
|
||||
/** Makes the subset of the texture safe to use with the given texture parameters.
|
||||
outOffset will be the top-left corner of the subset if a copy is not made. Otherwise,
|
||||
the copy will be tight to the contents and outOffset will be (0, 0). If the copy's size
|
||||
does not match subset's dimensions then the contents are scaled to fit the copy.*/
|
||||
GrTexture* refTextureSafeForParams(const GrSamplerParams&, SkDestinationSurfaceColorMode,
|
||||
SkIPoint* outOffset);
|
||||
|
||||
sk_sp<GrFragmentProcessor> createFragmentProcessor(
|
||||
const SkMatrix& textureMatrix,
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode) override;
|
||||
|
||||
// We do not ref the texture nor the colorspace, so the caller must keep them in scope while
|
||||
// this Adjuster is alive.
|
||||
GrTextureAdjuster(GrTexture*, SkAlphaType, const SkIRect& area, uint32_t uniqueID,
|
||||
SkColorSpace*);
|
||||
|
||||
protected:
|
||||
SkAlphaType alphaType() const override { return fAlphaType; }
|
||||
void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) override;
|
||||
void didCacheCopy(const GrUniqueKey& copyKey) override;
|
||||
|
||||
GrTexture* originalTexture() const { return fOriginal; }
|
||||
|
||||
/** Returns the content area or null for the whole original texture */
|
||||
const SkIRect* contentAreaOrNull() { return fContentArea.getMaybeNull(); }
|
||||
|
||||
private:
|
||||
SkTLazy<SkIRect> fContentArea;
|
||||
GrTexture* fOriginal;
|
||||
SkAlphaType fAlphaType;
|
||||
SkColorSpace* fColorSpace;
|
||||
uint32_t fUniqueID;
|
||||
|
||||
GrTexture* refCopy(const CopyParams ©Params);
|
||||
|
||||
typedef GrTextureProducer INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
107
src/gpu/GrTextureMaker.cpp
Normal file
107
src/gpu/GrTextureMaker.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrTextureMaker.h"
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "GrGpu.h"
|
||||
|
||||
GrTexture* GrTextureMaker::refTextureForParams(const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace) {
|
||||
CopyParams copyParams;
|
||||
bool willBeMipped = params.filterMode() == GrSamplerParams::kMipMap_FilterMode;
|
||||
|
||||
if (!fContext->caps()->mipMapSupport()) {
|
||||
willBeMipped = false;
|
||||
}
|
||||
|
||||
if (texColorSpace) {
|
||||
*texColorSpace = this->getColorSpace(colorMode);
|
||||
}
|
||||
|
||||
if (!fContext->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
|
||||
©Params)) {
|
||||
return this->refOriginalTexture(willBeMipped, colorMode);
|
||||
}
|
||||
GrUniqueKey copyKey;
|
||||
this->makeCopyKey(copyParams, ©Key, colorMode);
|
||||
if (copyKey.isValid()) {
|
||||
GrTexture* result = fContext->textureProvider()->findAndRefTextureByUniqueKey(copyKey);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
GrTexture* result = this->generateTextureForParams(copyParams, willBeMipped, colorMode);
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (copyKey.isValid()) {
|
||||
fContext->textureProvider()->assignUniqueKeyToTexture(copyKey, result);
|
||||
this->didCacheCopy(copyKey);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
sk_sp<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
|
||||
const SkMatrix& textureMatrix,
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
|
||||
const GrSamplerParams::FilterMode* fmForDetermineDomain = filterOrNullForBicubic;
|
||||
if (filterOrNullForBicubic && GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic &&
|
||||
kYes_FilterConstraint == filterConstraint) {
|
||||
// TODo: Here we should force a copy restricted to the constraintRect since MIP maps will
|
||||
// read outside the constraint rect. However, as in the adjuster case, we aren't currently
|
||||
// doing that.
|
||||
// We instead we compute the domain as though were bilerping which is only correct if we
|
||||
// only sample level 0.
|
||||
static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode;
|
||||
fmForDetermineDomain = &kBilerp;
|
||||
}
|
||||
|
||||
GrSamplerParams params;
|
||||
if (filterOrNullForBicubic) {
|
||||
params.reset(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
|
||||
} else {
|
||||
// Bicubic doesn't use filtering for it's texture accesses.
|
||||
params.reset(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
|
||||
}
|
||||
sk_sp<SkColorSpace> texColorSpace;
|
||||
sk_sp<GrTexture> texture(this->refTextureForParams(params, colorMode, &texColorSpace));
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
SkRect domain;
|
||||
DomainMode domainMode =
|
||||
DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
|
||||
texture->width(), texture->height(), nullptr, fmForDetermineDomain,
|
||||
&domain);
|
||||
SkASSERT(kTightCopy_DomainMode != domainMode);
|
||||
SkMatrix normalizedTextureMatrix = textureMatrix;
|
||||
normalizedTextureMatrix.postIDiv(texture->width(), texture->height());
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
|
||||
dstColorSpace);
|
||||
return CreateFragmentProcessorForDomainAndFilter(texture.get(), std::move(colorSpaceXform),
|
||||
normalizedTextureMatrix, domainMode, domain,
|
||||
filterOrNullForBicubic);
|
||||
}
|
||||
|
||||
GrTexture* GrTextureMaker::generateTextureForParams(const CopyParams& copyParams, bool willBeMipped,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
sk_sp<GrTexture> original(this->refOriginalTexture(willBeMipped, colorMode));
|
||||
if (!original) {
|
||||
return nullptr;
|
||||
}
|
||||
return CopyOnGpu(original.get(), nullptr, copyParams);
|
||||
}
|
74
src/gpu/GrTextureMaker.h
Normal file
74
src/gpu/GrTextureMaker.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrTextureMaker_DEFINED
|
||||
#define GrTextureMaker_DEFINED
|
||||
|
||||
#include "GrTextureProducer.h"
|
||||
|
||||
/**
|
||||
* Base class for sources that start out as something other than a texture (encoded image,
|
||||
* picture, ...).
|
||||
*/
|
||||
class GrTextureMaker : public GrTextureProducer {
|
||||
public:
|
||||
/**
|
||||
* Returns a texture that is safe for use with the params. If the size of the returned texture
|
||||
* does not match width()/height() then the contents of the original must be scaled to fit
|
||||
* the texture. Places the color space of the texture in (*texColorSpace).
|
||||
*/
|
||||
GrTexture* refTextureForParams(const GrSamplerParams&, SkDestinationSurfaceColorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace);
|
||||
|
||||
sk_sp<GrFragmentProcessor> createFragmentProcessor(
|
||||
const SkMatrix& textureMatrix,
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode) override;
|
||||
|
||||
protected:
|
||||
GrTextureMaker(GrContext* context, int width, int height, bool isAlphaOnly)
|
||||
: INHERITED(width, height, isAlphaOnly)
|
||||
, fContext(context) {}
|
||||
|
||||
/**
|
||||
* Return the maker's "original" texture. It is the responsibility of the maker to handle any
|
||||
* caching of the original if desired.
|
||||
*/
|
||||
virtual GrTexture* refOriginalTexture(bool willBeMipped, SkDestinationSurfaceColorMode) = 0;
|
||||
|
||||
/**
|
||||
* Returns the color space of the maker's "original" texture, assuming it was retrieved with
|
||||
* the same destination color mode.
|
||||
*/
|
||||
virtual sk_sp<SkColorSpace> getColorSpace(SkDestinationSurfaceColorMode) = 0;
|
||||
|
||||
/**
|
||||
* Return a new (uncached) texture that is the stretch of the maker's original.
|
||||
*
|
||||
* The base-class handles general logic for this, and only needs access to the following
|
||||
* method:
|
||||
* - refOriginalTexture()
|
||||
*
|
||||
* Subclass may override this if they can handle creating the texture more directly than
|
||||
* by copying.
|
||||
*/
|
||||
virtual GrTexture* generateTextureForParams(const CopyParams&, bool willBeMipped,
|
||||
SkDestinationSurfaceColorMode);
|
||||
|
||||
GrContext* context() const { return fContext; }
|
||||
|
||||
private:
|
||||
GrContext* fContext;
|
||||
|
||||
typedef GrTextureProducer INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,524 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrTextureParamsAdjuster.h"
|
||||
|
||||
#include "GrCaps.h"
|
||||
#include "GrColorSpaceXform.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrRenderTargetContext.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrGpuResourcePriv.h"
|
||||
#include "GrResourceKey.h"
|
||||
#include "GrTexture.h"
|
||||
#include "GrSamplerParams.h"
|
||||
#include "GrTextureProvider.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkGr.h"
|
||||
#include "SkGrPriv.h"
|
||||
#include "effects/GrBicubicEffect.h"
|
||||
#include "effects/GrSimpleTextureEffect.h"
|
||||
#include "effects/GrTextureDomain.h"
|
||||
|
||||
typedef GrTextureProducer::CopyParams CopyParams;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset,
|
||||
const CopyParams& copyParams) {
|
||||
SkASSERT(!subset || !subset->isEmpty());
|
||||
GrContext* context = inputTexture->getContext();
|
||||
SkASSERT(context);
|
||||
|
||||
GrPixelConfig config = GrMakePixelConfigUncompressed(inputTexture->config());
|
||||
|
||||
sk_sp<GrRenderTargetContext> copyRTC = context->makeRenderTargetContextWithFallback(
|
||||
SkBackingFit::kExact, copyParams.fWidth, copyParams.fHeight, config, nullptr);
|
||||
if (!copyRTC) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrPaint paint;
|
||||
paint.setGammaCorrect(true);
|
||||
|
||||
SkScalar sx SK_INIT_TO_AVOID_WARNING;
|
||||
SkScalar sy SK_INIT_TO_AVOID_WARNING;
|
||||
if (subset) {
|
||||
sx = 1.f / inputTexture->width();
|
||||
sy = 1.f / inputTexture->height();
|
||||
}
|
||||
|
||||
if (copyParams.fFilter != GrSamplerParams::kNone_FilterMode && subset &&
|
||||
(subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) {
|
||||
SkRect domain;
|
||||
domain.fLeft = (subset->fLeft + 0.5f) * sx;
|
||||
domain.fTop = (subset->fTop + 0.5f)* sy;
|
||||
domain.fRight = (subset->fRight - 0.5f) * sx;
|
||||
domain.fBottom = (subset->fBottom - 0.5f) * sy;
|
||||
// This would cause us to read values from outside the subset. Surely, the caller knows
|
||||
// better!
|
||||
SkASSERT(copyParams.fFilter != GrSamplerParams::kMipMap_FilterMode);
|
||||
paint.addColorFragmentProcessor(
|
||||
GrTextureDomainEffect::Make(inputTexture, nullptr, SkMatrix::I(), domain,
|
||||
GrTextureDomain::kClamp_Mode,
|
||||
copyParams.fFilter));
|
||||
} else {
|
||||
GrSamplerParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
|
||||
paint.addColorTextureProcessor(inputTexture, nullptr, SkMatrix::I(), params);
|
||||
}
|
||||
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
||||
|
||||
SkRect localRect;
|
||||
if (subset) {
|
||||
localRect = SkRect::Make(*subset);
|
||||
localRect.fLeft *= sx;
|
||||
localRect.fTop *= sy;
|
||||
localRect.fRight *= sx;
|
||||
localRect.fBottom *= sy;
|
||||
} else {
|
||||
localRect = SkRect::MakeWH(1.f, 1.f);
|
||||
}
|
||||
|
||||
SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
|
||||
copyRTC->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect);
|
||||
return copyRTC->asTexture().release();
|
||||
}
|
||||
|
||||
GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, SkAlphaType alphaType,
|
||||
const SkIRect& contentArea, uint32_t uniqueID,
|
||||
SkColorSpace* cs)
|
||||
: INHERITED(contentArea.width(), contentArea.height(),
|
||||
GrPixelConfigIsAlphaOnly(original->config()))
|
||||
, fOriginal(original)
|
||||
, fAlphaType(alphaType)
|
||||
, fColorSpace(cs)
|
||||
, fUniqueID(uniqueID)
|
||||
{
|
||||
SkASSERT(SkIRect::MakeWH(original->width(), original->height()).contains(contentArea));
|
||||
if (contentArea.fLeft > 0 || contentArea.fTop > 0 ||
|
||||
contentArea.fRight < original->width() || contentArea.fBottom < original->height()) {
|
||||
fContentArea.set(contentArea);
|
||||
}
|
||||
}
|
||||
|
||||
void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode) {
|
||||
// Color mode is irrelevant in this case - we already have a texture so we're just sub-setting
|
||||
GrUniqueKey baseKey;
|
||||
GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height()));
|
||||
MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
|
||||
}
|
||||
|
||||
void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) {
|
||||
// We don't currently have a mechanism for notifications on Images!
|
||||
}
|
||||
|
||||
GrTexture* GrTextureAdjuster::refCopy(const CopyParams& copyParams) {
|
||||
GrTexture* texture = this->originalTexture();
|
||||
GrContext* context = texture->getContext();
|
||||
const SkIRect* contentArea = this->contentAreaOrNull();
|
||||
GrUniqueKey key;
|
||||
this->makeCopyKey(copyParams, &key, SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware);
|
||||
if (key.isValid()) {
|
||||
GrTexture* cachedCopy = context->textureProvider()->findAndRefTextureByUniqueKey(key);
|
||||
if (cachedCopy) {
|
||||
return cachedCopy;
|
||||
}
|
||||
}
|
||||
GrTexture* copy = copy_on_gpu(texture, contentArea, copyParams);
|
||||
if (copy) {
|
||||
if (key.isValid()) {
|
||||
copy->resourcePriv().setUniqueKey(key);
|
||||
this->didCacheCopy(key);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
SkIPoint* outOffset) {
|
||||
GrTexture* texture = this->originalTexture();
|
||||
GrContext* context = texture->getContext();
|
||||
CopyParams copyParams;
|
||||
const SkIRect* contentArea = this->contentAreaOrNull();
|
||||
|
||||
if (!context) {
|
||||
// The texture was abandoned.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (contentArea && GrSamplerParams::kMipMap_FilterMode == params.filterMode()) {
|
||||
// If we generate a MIP chain for texture it will read pixel values from outside the content
|
||||
// area.
|
||||
copyParams.fWidth = contentArea->width();
|
||||
copyParams.fHeight = contentArea->height();
|
||||
copyParams.fFilter = GrSamplerParams::kBilerp_FilterMode;
|
||||
} else if (!context->getGpu()->makeCopyForTextureParams(texture, params, ©Params)) {
|
||||
if (outOffset) {
|
||||
if (contentArea) {
|
||||
outOffset->set(contentArea->fLeft, contentArea->fRight);
|
||||
} else {
|
||||
outOffset->set(0, 0);
|
||||
}
|
||||
}
|
||||
return SkRef(texture);
|
||||
}
|
||||
|
||||
GrTexture* copy = this->refCopy(copyParams);
|
||||
if (copy && outOffset) {
|
||||
outOffset->set(0, 0);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
enum DomainMode {
|
||||
kNoDomain_DomainMode,
|
||||
kDomain_DomainMode,
|
||||
kTightCopy_DomainMode
|
||||
};
|
||||
|
||||
/** Determines whether a texture domain is necessary and if so what domain to use. There are two
|
||||
* rectangles to consider:
|
||||
* - The first is the content area specified by the texture adjuster. We can *never* allow
|
||||
* filtering to cause bleed of pixels outside this rectangle.
|
||||
* - The second rectangle is the constraint rectangle, which is known to be contained by the
|
||||
* content area. The filterConstraint specifies whether we are allowed to bleed across this
|
||||
* rect.
|
||||
*
|
||||
* We want to avoid using a domain if possible. We consider the above rectangles, the filter type,
|
||||
* and whether the coords generated by the draw would all fall within the constraint rect. If the
|
||||
* latter is true we only need to consider whether the filter would extend beyond the rects.
|
||||
*/
|
||||
static DomainMode determine_domain_mode(
|
||||
const SkRect& constraintRect,
|
||||
GrTextureAdjuster::FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
int texW, int texH,
|
||||
const SkIRect* textureContentArea,
|
||||
const GrSamplerParams::FilterMode* filterModeOrNullForBicubic,
|
||||
SkRect* domainRect) {
|
||||
|
||||
SkASSERT(SkRect::MakeIWH(texW, texH).contains(constraintRect));
|
||||
// We only expect a content area rect if there is some non-content area.
|
||||
SkASSERT(!textureContentArea ||
|
||||
(!textureContentArea->contains(SkIRect::MakeWH(texW, texH)) &&
|
||||
SkRect::Make(*textureContentArea).contains(constraintRect)));
|
||||
|
||||
SkRect textureBounds = SkRect::MakeIWH(texW, texH);
|
||||
// If the src rectangle contains the whole texture then no need for a domain.
|
||||
if (constraintRect.contains(textureBounds)) {
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
|
||||
bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
|
||||
|
||||
// If we can filter outside the constraint rect, and there is no non-content area of the
|
||||
// texture, and we aren't going to generate sample coords outside the constraint rect then we
|
||||
// don't need a domain.
|
||||
if (!restrictFilterToRect && !textureContentArea && coordsLimitedToConstraintRect) {
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
|
||||
// Get the domain inset based on sampling mode (or bail if mipped)
|
||||
SkScalar filterHalfWidth = 0.f;
|
||||
if (filterModeOrNullForBicubic) {
|
||||
switch (*filterModeOrNullForBicubic) {
|
||||
case GrSamplerParams::kNone_FilterMode:
|
||||
if (coordsLimitedToConstraintRect) {
|
||||
return kNoDomain_DomainMode;
|
||||
} else {
|
||||
filterHalfWidth = 0.f;
|
||||
}
|
||||
break;
|
||||
case GrSamplerParams::kBilerp_FilterMode:
|
||||
filterHalfWidth = .5f;
|
||||
break;
|
||||
case GrSamplerParams::kMipMap_FilterMode:
|
||||
if (restrictFilterToRect || textureContentArea) {
|
||||
// No domain can save us here.
|
||||
return kTightCopy_DomainMode;
|
||||
}
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
} else {
|
||||
// bicubic does nearest filtering internally.
|
||||
filterHalfWidth = 1.5f;
|
||||
}
|
||||
|
||||
// Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center
|
||||
// of the edge texel. Pinning to the texel center has no impact on nearest mode and MIP-maps
|
||||
|
||||
static const SkScalar kDomainInset = 0.5f;
|
||||
// Figure out the limits of pixels we're allowed to sample from.
|
||||
// Unless we know the amount of outset and the texture matrix we have to conservatively enforce
|
||||
// the domain.
|
||||
if (restrictFilterToRect) {
|
||||
domainRect->fLeft = constraintRect.fLeft + kDomainInset;
|
||||
domainRect->fTop = constraintRect.fTop + kDomainInset;
|
||||
domainRect->fRight = constraintRect.fRight - kDomainInset;
|
||||
domainRect->fBottom = constraintRect.fBottom - kDomainInset;
|
||||
} else if (textureContentArea) {
|
||||
// If we got here then: there is a textureContentArea, the coords are limited to the
|
||||
// constraint rect, and we're allowed to filter across the constraint rect boundary. So
|
||||
// we check whether the filter would reach across the edge of the content area.
|
||||
// We will only set the sides that are required.
|
||||
|
||||
domainRect->setLargest();
|
||||
if (coordsLimitedToConstraintRect) {
|
||||
// We may be able to use the fact that the texture coords are limited to the constraint
|
||||
// rect in order to avoid having to add a domain.
|
||||
bool needContentAreaConstraint = false;
|
||||
if (textureContentArea->fLeft > 0 &&
|
||||
textureContentArea->fLeft + filterHalfWidth > constraintRect.fLeft) {
|
||||
domainRect->fLeft = textureContentArea->fLeft + kDomainInset;
|
||||
needContentAreaConstraint = true;
|
||||
}
|
||||
if (textureContentArea->fTop > 0 &&
|
||||
textureContentArea->fTop + filterHalfWidth > constraintRect.fTop) {
|
||||
domainRect->fTop = textureContentArea->fTop + kDomainInset;
|
||||
needContentAreaConstraint = true;
|
||||
}
|
||||
if (textureContentArea->fRight < texW &&
|
||||
textureContentArea->fRight - filterHalfWidth < constraintRect.fRight) {
|
||||
domainRect->fRight = textureContentArea->fRight - kDomainInset;
|
||||
needContentAreaConstraint = true;
|
||||
}
|
||||
if (textureContentArea->fBottom < texH &&
|
||||
textureContentArea->fBottom - filterHalfWidth < constraintRect.fBottom) {
|
||||
domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
|
||||
needContentAreaConstraint = true;
|
||||
}
|
||||
if (!needContentAreaConstraint) {
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
} else {
|
||||
// Our sample coords for the texture are allowed to be outside the constraintRect so we
|
||||
// don't consider it when computing the domain.
|
||||
if (textureContentArea->fLeft != 0) {
|
||||
domainRect->fLeft = textureContentArea->fLeft + kDomainInset;
|
||||
}
|
||||
if (textureContentArea->fTop != 0) {
|
||||
domainRect->fTop = textureContentArea->fTop + kDomainInset;
|
||||
}
|
||||
if (textureContentArea->fRight != texW) {
|
||||
domainRect->fRight = textureContentArea->fRight - kDomainInset;
|
||||
}
|
||||
if (textureContentArea->fBottom != texH) {
|
||||
domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
|
||||
if (domainRect->fLeft > domainRect->fRight) {
|
||||
domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight);
|
||||
}
|
||||
if (domainRect->fTop > domainRect->fBottom) {
|
||||
domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom);
|
||||
}
|
||||
domainRect->fLeft /= texW;
|
||||
domainRect->fTop /= texH;
|
||||
domainRect->fRight /= texW;
|
||||
domainRect->fBottom /= texH;
|
||||
return kDomain_DomainMode;
|
||||
}
|
||||
|
||||
static sk_sp<GrFragmentProcessor> create_fp_for_domain_and_filter(
|
||||
GrTexture* texture,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& textureMatrix,
|
||||
DomainMode domainMode,
|
||||
const SkRect& domain,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic) {
|
||||
SkASSERT(kTightCopy_DomainMode != domainMode);
|
||||
if (filterOrNullForBicubic) {
|
||||
if (kDomain_DomainMode == domainMode) {
|
||||
return GrTextureDomainEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
|
||||
domain, GrTextureDomain::kClamp_Mode,
|
||||
*filterOrNullForBicubic);
|
||||
} else {
|
||||
GrSamplerParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
|
||||
return GrSimpleTextureEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
|
||||
params);
|
||||
}
|
||||
} else {
|
||||
if (kDomain_DomainMode == domainMode) {
|
||||
return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
|
||||
domain);
|
||||
} else {
|
||||
static const SkShader::TileMode kClampClamp[] =
|
||||
{ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode };
|
||||
return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
|
||||
kClampClamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sk_sp<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
|
||||
const SkMatrix& origTextureMatrix,
|
||||
const SkRect& origConstraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
|
||||
SkMatrix textureMatrix = origTextureMatrix;
|
||||
const SkIRect* contentArea = this->contentAreaOrNull();
|
||||
// Convert the constraintRect to be relative to the texture rather than the content area so
|
||||
// that both rects are in the same coordinate system.
|
||||
SkTCopyOnFirstWrite<SkRect> constraintRect(origConstraintRect);
|
||||
if (contentArea) {
|
||||
SkScalar l = SkIntToScalar(contentArea->fLeft);
|
||||
SkScalar t = SkIntToScalar(contentArea->fTop);
|
||||
constraintRect.writable()->offset(l, t);
|
||||
textureMatrix.postTranslate(l, t);
|
||||
}
|
||||
|
||||
SkRect domain;
|
||||
GrSamplerParams params;
|
||||
if (filterOrNullForBicubic) {
|
||||
params.setFilterMode(*filterOrNullForBicubic);
|
||||
}
|
||||
sk_sp<GrTexture> texture(this->refTextureSafeForParams(params, colorMode, nullptr));
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
// If we made a copy then we only copied the contentArea, in which case the new texture is all
|
||||
// content.
|
||||
if (texture.get() != this->originalTexture()) {
|
||||
contentArea = nullptr;
|
||||
}
|
||||
|
||||
DomainMode domainMode =
|
||||
determine_domain_mode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
|
||||
texture->width(), texture->height(),
|
||||
contentArea, filterOrNullForBicubic,
|
||||
&domain);
|
||||
if (kTightCopy_DomainMode == domainMode) {
|
||||
// TODO: Copy the texture and adjust the texture matrix (both parts need to consider
|
||||
// non-int constraint rect)
|
||||
// For now: treat as bilerp and ignore what goes on above level 0.
|
||||
|
||||
// We only expect MIP maps to require a tight copy.
|
||||
SkASSERT(filterOrNullForBicubic &&
|
||||
GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic);
|
||||
static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode;
|
||||
domainMode =
|
||||
determine_domain_mode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
|
||||
texture->width(), texture->height(),
|
||||
contentArea, &kBilerp, &domain);
|
||||
SkASSERT(kTightCopy_DomainMode != domainMode);
|
||||
}
|
||||
SkASSERT(kNoDomain_DomainMode == domainMode ||
|
||||
(domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
|
||||
textureMatrix.postIDiv(texture->width(), texture->height());
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace,
|
||||
dstColorSpace);
|
||||
return create_fp_for_domain_and_filter(texture.get(), std::move(colorSpaceXform), textureMatrix,
|
||||
domainMode, domain, filterOrNullForBicubic);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrTexture* GrTextureMaker::refTextureForParams(const GrSamplerParams& params,
|
||||
SkDestinationSurfaceColorMode colorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace) {
|
||||
CopyParams copyParams;
|
||||
bool willBeMipped = params.filterMode() == GrSamplerParams::kMipMap_FilterMode;
|
||||
|
||||
if (!fContext->caps()->mipMapSupport()) {
|
||||
willBeMipped = false;
|
||||
}
|
||||
|
||||
if (texColorSpace) {
|
||||
*texColorSpace = this->getColorSpace(colorMode);
|
||||
}
|
||||
|
||||
if (!fContext->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
|
||||
©Params)) {
|
||||
return this->refOriginalTexture(willBeMipped, colorMode);
|
||||
}
|
||||
GrUniqueKey copyKey;
|
||||
this->makeCopyKey(copyParams, ©Key, colorMode);
|
||||
if (copyKey.isValid()) {
|
||||
GrTexture* result = fContext->textureProvider()->findAndRefTextureByUniqueKey(copyKey);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
GrTexture* result = this->generateTextureForParams(copyParams, willBeMipped, colorMode);
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (copyKey.isValid()) {
|
||||
fContext->textureProvider()->assignUniqueKeyToTexture(copyKey, result);
|
||||
this->didCacheCopy(copyKey);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
sk_sp<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
|
||||
const SkMatrix& textureMatrix,
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
|
||||
const GrSamplerParams::FilterMode* fmForDetermineDomain = filterOrNullForBicubic;
|
||||
if (filterOrNullForBicubic && GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic &&
|
||||
kYes_FilterConstraint == filterConstraint) {
|
||||
// TODo: Here we should force a copy restricted to the constraintRect since MIP maps will
|
||||
// read outside the constraint rect. However, as in the adjuster case, we aren't currently
|
||||
// doing that.
|
||||
// We instead we compute the domain as though were bilerping which is only correct if we
|
||||
// only sample level 0.
|
||||
static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode;
|
||||
fmForDetermineDomain = &kBilerp;
|
||||
}
|
||||
|
||||
GrSamplerParams params;
|
||||
if (filterOrNullForBicubic) {
|
||||
params.reset(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
|
||||
} else {
|
||||
// Bicubic doesn't use filtering for it's texture accesses.
|
||||
params.reset(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
|
||||
}
|
||||
sk_sp<SkColorSpace> texColorSpace;
|
||||
sk_sp<GrTexture> texture(this->refTextureForParams(params, colorMode, &texColorSpace));
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
SkRect domain;
|
||||
DomainMode domainMode =
|
||||
determine_domain_mode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
|
||||
texture->width(), texture->height(), nullptr, fmForDetermineDomain,
|
||||
&domain);
|
||||
SkASSERT(kTightCopy_DomainMode != domainMode);
|
||||
SkMatrix normalizedTextureMatrix = textureMatrix;
|
||||
normalizedTextureMatrix.postIDiv(texture->width(), texture->height());
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
|
||||
dstColorSpace);
|
||||
return create_fp_for_domain_and_filter(texture.get(), std::move(colorSpaceXform),
|
||||
normalizedTextureMatrix, domainMode, domain,
|
||||
filterOrNullForBicubic);
|
||||
}
|
||||
|
||||
GrTexture* GrTextureMaker::generateTextureForParams(const CopyParams& copyParams, bool willBeMipped,
|
||||
SkDestinationSurfaceColorMode colorMode) {
|
||||
sk_sp<GrTexture> original(this->refOriginalTexture(willBeMipped, colorMode));
|
||||
if (!original) {
|
||||
return nullptr;
|
||||
}
|
||||
return copy_on_gpu(original.get(), nullptr, copyParams);
|
||||
}
|
@ -1,236 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrTextureMaker_DEFINED
|
||||
#define GrTextureMaker_DEFINED
|
||||
|
||||
#include "GrSamplerParams.h"
|
||||
#include "GrResourceKey.h"
|
||||
#include "GrTexture.h"
|
||||
#include "SkTLazy.h"
|
||||
|
||||
class GrContext;
|
||||
class GrSamplerParams;
|
||||
class GrUniqueKey;
|
||||
class SkBitmap;
|
||||
|
||||
/**
|
||||
* Different GPUs and API extensions have different requirements with respect to what texture
|
||||
* sampling parameters may be used with textures of various types. This class facilitates making
|
||||
* texture compatible with a given GrSamplerParams. There are two immediate subclasses defined
|
||||
* below. One is a base class for sources that are inherently texture-backed (e.g. a texture-backed
|
||||
* SkImage). It supports subsetting the original texture. The other is for use cases where the
|
||||
* source can generate a texture that represents some content (e.g. cpu pixels, SkPicture, ...).
|
||||
*/
|
||||
class GrTextureProducer : public SkNoncopyable {
|
||||
public:
|
||||
struct CopyParams {
|
||||
GrSamplerParams::FilterMode fFilter;
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
};
|
||||
|
||||
enum FilterConstraint {
|
||||
kYes_FilterConstraint,
|
||||
kNo_FilterConstraint,
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper for creating a fragment processor to sample the texture with a given filtering mode.
|
||||
* It attempts to avoid making texture copies or using domains whenever possible.
|
||||
*
|
||||
* @param textureMatrix Matrix used to access the texture. It is applied to
|
||||
* the local coords. The post-transformed coords should
|
||||
* be in texel units (rather than normalized) with
|
||||
* respect to this Producer's bounds (width()/height()).
|
||||
* @param constraintRect A rect that represents the area of the texture to be
|
||||
* sampled. It must be contained in the Producer's bounds
|
||||
* as defined by width()/height().
|
||||
* @param filterConstriant Indicates whether filtering is limited to
|
||||
* constraintRect.
|
||||
* @param coordsLimitedToConstraintRect Is it known that textureMatrix*localCoords is bound
|
||||
* by the portion of the texture indicated by
|
||||
* constraintRect (without consideration of filter
|
||||
* width, just the raw coords).
|
||||
* @param filterOrNullForBicubic If non-null indicates the filter mode. If null means
|
||||
* use bicubic filtering.
|
||||
**/
|
||||
virtual sk_sp<GrFragmentProcessor> createFragmentProcessor(
|
||||
const SkMatrix& textureMatrix,
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode) = 0;
|
||||
|
||||
virtual ~GrTextureProducer() {}
|
||||
|
||||
int width() const { return fWidth; }
|
||||
int height() const { return fHeight; }
|
||||
bool isAlphaOnly() const { return fIsAlphaOnly; }
|
||||
virtual SkAlphaType alphaType() const = 0;
|
||||
|
||||
protected:
|
||||
GrTextureProducer(int width, int height, bool isAlphaOnly)
|
||||
: fWidth(width)
|
||||
, fHeight(height)
|
||||
, fIsAlphaOnly(isAlphaOnly) {}
|
||||
|
||||
/** Helper for creating a key for a copy from an original key. */
|
||||
static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey,
|
||||
const CopyParams& copyParams,
|
||||
GrUniqueKey* copyKey) {
|
||||
SkASSERT(!copyKey->isValid());
|
||||
if (origKey.isValid()) {
|
||||
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
||||
GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
|
||||
builder[0] = copyParams.fFilter;
|
||||
builder[1] = copyParams.fWidth;
|
||||
builder[2] = copyParams.fHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we need to make a copy in order to be compatible with GrTextureParams producer is asked to
|
||||
* return a key that identifies its original content + the CopyParms parameter. If the producer
|
||||
* does not want to cache the stretched version (e.g. the producer is volatile), this should
|
||||
* simply return without initializing the copyKey. If the texture generated by this producer
|
||||
* depends on colorMode, then that information should also be incorporated in the key.
|
||||
*/
|
||||
virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) = 0;
|
||||
|
||||
/**
|
||||
* If a stretched version of the texture is generated, it may be cached (assuming that
|
||||
* makeCopyKey() returns true). In that case, the maker is notified in case it
|
||||
* wants to note that for when the maker is destroyed.
|
||||
*/
|
||||
virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0;
|
||||
|
||||
private:
|
||||
const int fWidth;
|
||||
const int fHeight;
|
||||
const bool fIsAlphaOnly;
|
||||
|
||||
typedef SkNoncopyable INHERITED;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for sources that start out as textures. Optionally allows for a content area subrect.
|
||||
* The intent is not to use content area for subrect rendering. Rather, the pixels outside the
|
||||
* content area have undefined values and shouldn't be read *regardless* of filtering mode or
|
||||
* the SkCanvas::SrcRectConstraint used for subrect draws.
|
||||
*/
|
||||
class GrTextureAdjuster : public GrTextureProducer {
|
||||
public:
|
||||
/** Makes the subset of the texture safe to use with the given texture parameters.
|
||||
outOffset will be the top-left corner of the subset if a copy is not made. Otherwise,
|
||||
the copy will be tight to the contents and outOffset will be (0, 0). If the copy's size
|
||||
does not match subset's dimensions then the contents are scaled to fit the copy.*/
|
||||
GrTexture* refTextureSafeForParams(const GrSamplerParams&, SkDestinationSurfaceColorMode,
|
||||
SkIPoint* outOffset);
|
||||
|
||||
sk_sp<GrFragmentProcessor> createFragmentProcessor(
|
||||
const SkMatrix& textureMatrix,
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode) override;
|
||||
|
||||
// We do not ref the texture nor the colorspace, so the caller must keep them in scope while
|
||||
// this Adjuster is alive.
|
||||
GrTextureAdjuster(GrTexture*, SkAlphaType, const SkIRect& area, uint32_t uniqueID,
|
||||
SkColorSpace*);
|
||||
|
||||
protected:
|
||||
SkAlphaType alphaType() const override { return fAlphaType; }
|
||||
void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) override;
|
||||
void didCacheCopy(const GrUniqueKey& copyKey) override;
|
||||
|
||||
GrTexture* originalTexture() const { return fOriginal; }
|
||||
|
||||
/** Returns the content area or null for the whole original texture */
|
||||
const SkIRect* contentAreaOrNull() { return fContentArea.getMaybeNull(); }
|
||||
|
||||
private:
|
||||
SkTLazy<SkIRect> fContentArea;
|
||||
GrTexture* fOriginal;
|
||||
SkAlphaType fAlphaType;
|
||||
SkColorSpace* fColorSpace;
|
||||
uint32_t fUniqueID;
|
||||
|
||||
GrTexture* refCopy(const CopyParams ©Params);
|
||||
|
||||
typedef GrTextureProducer INHERITED;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for sources that start out as something other than a texture (encoded image,
|
||||
* picture, ...).
|
||||
*/
|
||||
class GrTextureMaker : public GrTextureProducer {
|
||||
public:
|
||||
/**
|
||||
* Returns a texture that is safe for use with the params. If the size of the returned texture
|
||||
* does not match width()/height() then the contents of the original must be scaled to fit
|
||||
* the texture. Places the color space of the texture in (*texColorSpace).
|
||||
*/
|
||||
GrTexture* refTextureForParams(const GrSamplerParams&, SkDestinationSurfaceColorMode,
|
||||
sk_sp<SkColorSpace>* texColorSpace);
|
||||
|
||||
sk_sp<GrFragmentProcessor> createFragmentProcessor(
|
||||
const SkMatrix& textureMatrix,
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode) override;
|
||||
|
||||
protected:
|
||||
GrTextureMaker(GrContext* context, int width, int height, bool isAlphaOnly)
|
||||
: INHERITED(width, height, isAlphaOnly)
|
||||
, fContext(context) {}
|
||||
|
||||
/**
|
||||
* Return the maker's "original" texture. It is the responsibility of the maker to handle any
|
||||
* caching of the original if desired.
|
||||
*/
|
||||
virtual GrTexture* refOriginalTexture(bool willBeMipped, SkDestinationSurfaceColorMode) = 0;
|
||||
|
||||
/**
|
||||
* Returns the color space of the maker's "original" texture, assuming it was retrieved with
|
||||
* the same destination color mode.
|
||||
*/
|
||||
virtual sk_sp<SkColorSpace> getColorSpace(SkDestinationSurfaceColorMode) = 0;
|
||||
|
||||
/**
|
||||
* Return a new (uncached) texture that is the stretch of the maker's original.
|
||||
*
|
||||
* The base-class handles general logic for this, and only needs access to the following
|
||||
* method:
|
||||
* - refOriginalTexture()
|
||||
*
|
||||
* Subclass may override this if they can handle creating the texture more directly than
|
||||
* by copying.
|
||||
*/
|
||||
virtual GrTexture* generateTextureForParams(const CopyParams&, bool willBeMipped,
|
||||
SkDestinationSurfaceColorMode);
|
||||
|
||||
GrContext* context() const { return fContext; }
|
||||
|
||||
private:
|
||||
GrContext* fContext;
|
||||
|
||||
typedef GrTextureProducer INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
252
src/gpu/GrTextureProducer.cpp
Normal file
252
src/gpu/GrTextureProducer.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrTextureProducer.h"
|
||||
|
||||
#include "GrRenderTargetContext.h"
|
||||
#include "GrTexture.h"
|
||||
#include "effects/GrBicubicEffect.h"
|
||||
#include "effects/GrSimpleTextureEffect.h"
|
||||
#include "effects/GrTextureDomain.h"
|
||||
|
||||
GrTexture* GrTextureProducer::CopyOnGpu(GrTexture* inputTexture, const SkIRect* subset,
|
||||
const CopyParams& copyParams) {
|
||||
SkASSERT(!subset || !subset->isEmpty());
|
||||
GrContext* context = inputTexture->getContext();
|
||||
SkASSERT(context);
|
||||
|
||||
GrPixelConfig config = GrMakePixelConfigUncompressed(inputTexture->config());
|
||||
|
||||
sk_sp<GrRenderTargetContext> copyRTC = context->makeRenderTargetContextWithFallback(
|
||||
SkBackingFit::kExact, copyParams.fWidth, copyParams.fHeight, config, nullptr);
|
||||
if (!copyRTC) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrPaint paint;
|
||||
paint.setGammaCorrect(true);
|
||||
|
||||
SkScalar sx SK_INIT_TO_AVOID_WARNING;
|
||||
SkScalar sy SK_INIT_TO_AVOID_WARNING;
|
||||
if (subset) {
|
||||
sx = 1.f / inputTexture->width();
|
||||
sy = 1.f / inputTexture->height();
|
||||
}
|
||||
|
||||
if (copyParams.fFilter != GrSamplerParams::kNone_FilterMode && subset &&
|
||||
(subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) {
|
||||
SkRect domain;
|
||||
domain.fLeft = (subset->fLeft + 0.5f) * sx;
|
||||
domain.fTop = (subset->fTop + 0.5f)* sy;
|
||||
domain.fRight = (subset->fRight - 0.5f) * sx;
|
||||
domain.fBottom = (subset->fBottom - 0.5f) * sy;
|
||||
// This would cause us to read values from outside the subset. Surely, the caller knows
|
||||
// better!
|
||||
SkASSERT(copyParams.fFilter != GrSamplerParams::kMipMap_FilterMode);
|
||||
paint.addColorFragmentProcessor(
|
||||
GrTextureDomainEffect::Make(inputTexture, nullptr, SkMatrix::I(), domain,
|
||||
GrTextureDomain::kClamp_Mode,
|
||||
copyParams.fFilter));
|
||||
} else {
|
||||
GrSamplerParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
|
||||
paint.addColorTextureProcessor(inputTexture, nullptr, SkMatrix::I(), params);
|
||||
}
|
||||
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
||||
|
||||
SkRect localRect;
|
||||
if (subset) {
|
||||
localRect = SkRect::Make(*subset);
|
||||
localRect.fLeft *= sx;
|
||||
localRect.fTop *= sy;
|
||||
localRect.fRight *= sx;
|
||||
localRect.fBottom *= sy;
|
||||
} else {
|
||||
localRect = SkRect::MakeWH(1.f, 1.f);
|
||||
}
|
||||
|
||||
SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
|
||||
copyRTC->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect);
|
||||
return copyRTC->asTexture().release();
|
||||
}
|
||||
|
||||
/** Determines whether a texture domain is necessary and if so what domain to use. There are two
|
||||
* rectangles to consider:
|
||||
* - The first is the content area specified by the texture adjuster. We can *never* allow
|
||||
* filtering to cause bleed of pixels outside this rectangle.
|
||||
* - The second rectangle is the constraint rectangle, which is known to be contained by the
|
||||
* content area. The filterConstraint specifies whether we are allowed to bleed across this
|
||||
* rect.
|
||||
*
|
||||
* We want to avoid using a domain if possible. We consider the above rectangles, the filter type,
|
||||
* and whether the coords generated by the draw would all fall within the constraint rect. If the
|
||||
* latter is true we only need to consider whether the filter would extend beyond the rects.
|
||||
*/
|
||||
GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode(
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
int texW, int texH,
|
||||
const SkIRect* textureContentArea,
|
||||
const GrSamplerParams::FilterMode* filterModeOrNullForBicubic,
|
||||
SkRect* domainRect) {
|
||||
|
||||
SkASSERT(SkRect::MakeIWH(texW, texH).contains(constraintRect));
|
||||
// We only expect a content area rect if there is some non-content area.
|
||||
SkASSERT(!textureContentArea ||
|
||||
(!textureContentArea->contains(SkIRect::MakeWH(texW, texH)) &&
|
||||
SkRect::Make(*textureContentArea).contains(constraintRect)));
|
||||
|
||||
SkRect textureBounds = SkRect::MakeIWH(texW, texH);
|
||||
// If the src rectangle contains the whole texture then no need for a domain.
|
||||
if (constraintRect.contains(textureBounds)) {
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
|
||||
bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
|
||||
|
||||
// If we can filter outside the constraint rect, and there is no non-content area of the
|
||||
// texture, and we aren't going to generate sample coords outside the constraint rect then we
|
||||
// don't need a domain.
|
||||
if (!restrictFilterToRect && !textureContentArea && coordsLimitedToConstraintRect) {
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
|
||||
// Get the domain inset based on sampling mode (or bail if mipped)
|
||||
SkScalar filterHalfWidth = 0.f;
|
||||
if (filterModeOrNullForBicubic) {
|
||||
switch (*filterModeOrNullForBicubic) {
|
||||
case GrSamplerParams::kNone_FilterMode:
|
||||
if (coordsLimitedToConstraintRect) {
|
||||
return kNoDomain_DomainMode;
|
||||
} else {
|
||||
filterHalfWidth = 0.f;
|
||||
}
|
||||
break;
|
||||
case GrSamplerParams::kBilerp_FilterMode:
|
||||
filterHalfWidth = .5f;
|
||||
break;
|
||||
case GrSamplerParams::kMipMap_FilterMode:
|
||||
if (restrictFilterToRect || textureContentArea) {
|
||||
// No domain can save us here.
|
||||
return kTightCopy_DomainMode;
|
||||
}
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
} else {
|
||||
// bicubic does nearest filtering internally.
|
||||
filterHalfWidth = 1.5f;
|
||||
}
|
||||
|
||||
// Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center
|
||||
// of the edge texel. Pinning to the texel center has no impact on nearest mode and MIP-maps
|
||||
|
||||
static const SkScalar kDomainInset = 0.5f;
|
||||
// Figure out the limits of pixels we're allowed to sample from.
|
||||
// Unless we know the amount of outset and the texture matrix we have to conservatively enforce
|
||||
// the domain.
|
||||
if (restrictFilterToRect) {
|
||||
domainRect->fLeft = constraintRect.fLeft + kDomainInset;
|
||||
domainRect->fTop = constraintRect.fTop + kDomainInset;
|
||||
domainRect->fRight = constraintRect.fRight - kDomainInset;
|
||||
domainRect->fBottom = constraintRect.fBottom - kDomainInset;
|
||||
} else if (textureContentArea) {
|
||||
// If we got here then: there is a textureContentArea, the coords are limited to the
|
||||
// constraint rect, and we're allowed to filter across the constraint rect boundary. So
|
||||
// we check whether the filter would reach across the edge of the content area.
|
||||
// We will only set the sides that are required.
|
||||
|
||||
domainRect->setLargest();
|
||||
if (coordsLimitedToConstraintRect) {
|
||||
// We may be able to use the fact that the texture coords are limited to the constraint
|
||||
// rect in order to avoid having to add a domain.
|
||||
bool needContentAreaConstraint = false;
|
||||
if (textureContentArea->fLeft > 0 &&
|
||||
textureContentArea->fLeft + filterHalfWidth > constraintRect.fLeft) {
|
||||
domainRect->fLeft = textureContentArea->fLeft + kDomainInset;
|
||||
needContentAreaConstraint = true;
|
||||
}
|
||||
if (textureContentArea->fTop > 0 &&
|
||||
textureContentArea->fTop + filterHalfWidth > constraintRect.fTop) {
|
||||
domainRect->fTop = textureContentArea->fTop + kDomainInset;
|
||||
needContentAreaConstraint = true;
|
||||
}
|
||||
if (textureContentArea->fRight < texW &&
|
||||
textureContentArea->fRight - filterHalfWidth < constraintRect.fRight) {
|
||||
domainRect->fRight = textureContentArea->fRight - kDomainInset;
|
||||
needContentAreaConstraint = true;
|
||||
}
|
||||
if (textureContentArea->fBottom < texH &&
|
||||
textureContentArea->fBottom - filterHalfWidth < constraintRect.fBottom) {
|
||||
domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
|
||||
needContentAreaConstraint = true;
|
||||
}
|
||||
if (!needContentAreaConstraint) {
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
} else {
|
||||
// Our sample coords for the texture are allowed to be outside the constraintRect so we
|
||||
// don't consider it when computing the domain.
|
||||
if (textureContentArea->fLeft != 0) {
|
||||
domainRect->fLeft = textureContentArea->fLeft + kDomainInset;
|
||||
}
|
||||
if (textureContentArea->fTop != 0) {
|
||||
domainRect->fTop = textureContentArea->fTop + kDomainInset;
|
||||
}
|
||||
if (textureContentArea->fRight != texW) {
|
||||
domainRect->fRight = textureContentArea->fRight - kDomainInset;
|
||||
}
|
||||
if (textureContentArea->fBottom != texH) {
|
||||
domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
|
||||
if (domainRect->fLeft > domainRect->fRight) {
|
||||
domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight);
|
||||
}
|
||||
if (domainRect->fTop > domainRect->fBottom) {
|
||||
domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom);
|
||||
}
|
||||
domainRect->fLeft /= texW;
|
||||
domainRect->fTop /= texH;
|
||||
domainRect->fRight /= texW;
|
||||
domainRect->fBottom /= texH;
|
||||
return kDomain_DomainMode;
|
||||
}
|
||||
|
||||
sk_sp<GrFragmentProcessor> GrTextureProducer::CreateFragmentProcessorForDomainAndFilter(
|
||||
GrTexture* texture,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& textureMatrix,
|
||||
DomainMode domainMode,
|
||||
const SkRect& domain,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic) {
|
||||
SkASSERT(kTightCopy_DomainMode != domainMode);
|
||||
if (filterOrNullForBicubic) {
|
||||
if (kDomain_DomainMode == domainMode) {
|
||||
return GrTextureDomainEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
|
||||
domain, GrTextureDomain::kClamp_Mode,
|
||||
*filterOrNullForBicubic);
|
||||
} else {
|
||||
GrSamplerParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
|
||||
return GrSimpleTextureEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
|
||||
params);
|
||||
}
|
||||
} else {
|
||||
if (kDomain_DomainMode == domainMode) {
|
||||
return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
|
||||
domain);
|
||||
} else {
|
||||
static const SkShader::TileMode kClampClamp[] =
|
||||
{ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode };
|
||||
return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
|
||||
kClampClamp);
|
||||
}
|
||||
}
|
||||
}
|
146
src/gpu/GrTextureProducer.h
Normal file
146
src/gpu/GrTextureProducer.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrTextureProducer_DEFINED
|
||||
#define GrTextureProducer_DEFINED
|
||||
|
||||
#include "GrSamplerParams.h"
|
||||
#include "GrResourceKey.h"
|
||||
|
||||
class GrColorSpaceXform;
|
||||
class GrTexture;
|
||||
|
||||
/**
|
||||
* Different GPUs and API extensions have different requirements with respect to what texture
|
||||
* sampling parameters may be used with textures of various types. This class facilitates making
|
||||
* texture compatible with a given GrSamplerParams. There are two immediate subclasses defined
|
||||
* below. One is a base class for sources that are inherently texture-backed (e.g. a texture-backed
|
||||
* SkImage). It supports subsetting the original texture. The other is for use cases where the
|
||||
* source can generate a texture that represents some content (e.g. cpu pixels, SkPicture, ...).
|
||||
*/
|
||||
class GrTextureProducer : public SkNoncopyable {
|
||||
public:
|
||||
struct CopyParams {
|
||||
GrSamplerParams::FilterMode fFilter;
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
};
|
||||
|
||||
enum FilterConstraint {
|
||||
kYes_FilterConstraint,
|
||||
kNo_FilterConstraint,
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper for creating a fragment processor to sample the texture with a given filtering mode.
|
||||
* It attempts to avoid making texture copies or using domains whenever possible.
|
||||
*
|
||||
* @param textureMatrix Matrix used to access the texture. It is applied to
|
||||
* the local coords. The post-transformed coords should
|
||||
* be in texel units (rather than normalized) with
|
||||
* respect to this Producer's bounds (width()/height()).
|
||||
* @param constraintRect A rect that represents the area of the texture to be
|
||||
* sampled. It must be contained in the Producer's
|
||||
* bounds as defined by width()/height().
|
||||
* @param filterConstriant Indicates whether filtering is limited to
|
||||
* constraintRect.
|
||||
* @param coordsLimitedToConstraintRect Is it known that textureMatrix*localCoords is bound
|
||||
* by the portion of the texture indicated by
|
||||
* constraintRect (without consideration of filter
|
||||
* width, just the raw coords).
|
||||
* @param filterOrNullForBicubic If non-null indicates the filter mode. If null means
|
||||
* use bicubic filtering.
|
||||
**/
|
||||
virtual sk_sp<GrFragmentProcessor> createFragmentProcessor(
|
||||
const SkMatrix& textureMatrix,
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkDestinationSurfaceColorMode) = 0;
|
||||
|
||||
virtual ~GrTextureProducer() {}
|
||||
|
||||
int width() const { return fWidth; }
|
||||
int height() const { return fHeight; }
|
||||
bool isAlphaOnly() const { return fIsAlphaOnly; }
|
||||
virtual SkAlphaType alphaType() const = 0;
|
||||
|
||||
protected:
|
||||
GrTextureProducer(int width, int height, bool isAlphaOnly)
|
||||
: fWidth(width)
|
||||
, fHeight(height)
|
||||
, fIsAlphaOnly(isAlphaOnly) {}
|
||||
|
||||
/** Helper for creating a key for a copy from an original key. */
|
||||
static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey,
|
||||
const CopyParams& copyParams,
|
||||
GrUniqueKey* copyKey) {
|
||||
SkASSERT(!copyKey->isValid());
|
||||
if (origKey.isValid()) {
|
||||
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
||||
GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
|
||||
builder[0] = copyParams.fFilter;
|
||||
builder[1] = copyParams.fWidth;
|
||||
builder[2] = copyParams.fHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we need to make a copy in order to be compatible with GrTextureParams producer is asked to
|
||||
* return a key that identifies its original content + the CopyParms parameter. If the producer
|
||||
* does not want to cache the stretched version (e.g. the producer is volatile), this should
|
||||
* simply return without initializing the copyKey. If the texture generated by this producer
|
||||
* depends on colorMode, then that information should also be incorporated in the key.
|
||||
*/
|
||||
virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey,
|
||||
SkDestinationSurfaceColorMode colorMode) = 0;
|
||||
|
||||
/**
|
||||
* If a stretched version of the texture is generated, it may be cached (assuming that
|
||||
* makeCopyKey() returns true). In that case, the maker is notified in case it
|
||||
* wants to note that for when the maker is destroyed.
|
||||
*/
|
||||
virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0;
|
||||
|
||||
|
||||
enum DomainMode {
|
||||
kNoDomain_DomainMode,
|
||||
kDomain_DomainMode,
|
||||
kTightCopy_DomainMode
|
||||
};
|
||||
|
||||
static GrTexture* CopyOnGpu(GrTexture* inputTexture, const SkIRect* subset,
|
||||
const CopyParams& copyParams);
|
||||
|
||||
static DomainMode DetermineDomainMode(
|
||||
const SkRect& constraintRect,
|
||||
FilterConstraint filterConstraint,
|
||||
bool coordsLimitedToConstraintRect,
|
||||
int texW, int texH,
|
||||
const SkIRect* textureContentArea,
|
||||
const GrSamplerParams::FilterMode* filterModeOrNullForBicubic,
|
||||
SkRect* domainRect);
|
||||
|
||||
static sk_sp<GrFragmentProcessor> CreateFragmentProcessorForDomainAndFilter(
|
||||
GrTexture* texture,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& textureMatrix,
|
||||
DomainMode domainMode,
|
||||
const SkRect& domain,
|
||||
const GrSamplerParams::FilterMode* filterOrNullForBicubic);
|
||||
|
||||
private:
|
||||
const int fWidth;
|
||||
const int fHeight;
|
||||
const bool fIsAlphaOnly;
|
||||
|
||||
typedef SkNoncopyable INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -14,6 +14,7 @@
|
||||
#include "../private/GrSingleOwner.h"
|
||||
#include "SkMathPriv.h"
|
||||
#include "SkTArray.h"
|
||||
#include "SkTLazy.h"
|
||||
|
||||
#define ASSERT_SINGLE_OWNER \
|
||||
SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "GrImageTextureMaker.h"
|
||||
#include "GrRenderTargetContextPriv.h"
|
||||
#include "GrStyle.h"
|
||||
#include "GrTextureAdjuster.h"
|
||||
#include "GrTracing.h"
|
||||
|
||||
#include "SkCanvasPriv.h"
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "GrCaps.h"
|
||||
#include "GrRenderTargetContext.h"
|
||||
#include "GrStyle.h"
|
||||
#include "GrTextureParamsAdjuster.h"
|
||||
#include "GrTextureAdjuster.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkGrPriv.h"
|
||||
#include "SkMaskFilter.h"
|
||||
@ -168,7 +168,7 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer,
|
||||
&doBicubic);
|
||||
const GrSamplerParams::FilterMode* filterMode = doBicubic ? nullptr : &fm;
|
||||
|
||||
GrTextureAdjuster::FilterConstraint constraintMode;
|
||||
GrTextureProducer::FilterConstraint constraintMode;
|
||||
if (SkCanvas::kFast_SrcRectConstraint == constraint) {
|
||||
constraintMode = GrTextureAdjuster::kNo_FilterConstraint;
|
||||
} else {
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "GrContext.h"
|
||||
#include "GrGpuResourcePriv.h"
|
||||
#include "GrRenderTargetContext.h"
|
||||
#include "GrTextureParamsAdjuster.h"
|
||||
#include "GrTexturePriv.h"
|
||||
#include "GrTypes.h"
|
||||
#include "GrXferProcessor.h"
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "GrContext.h"
|
||||
#include "GrImageTextureMaker.h"
|
||||
#include "GrRenderTargetContext.h"
|
||||
#include "GrTextureAdjuster.h"
|
||||
#include "GrTexturePriv.h"
|
||||
#include "effects/GrYUVEffect.h"
|
||||
#include "SkCanvas.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrContext.h"
|
||||
#include "GrTextureParamsAdjuster.h"
|
||||
#include "GrTextureAdjuster.h"
|
||||
#include "SkGr.h"
|
||||
#include "SkGrPriv.h"
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user