blob: d73ed2543c493a0dd8590be0a09530cc6140a186 [file] [log] [blame]
* 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 "include/core/SkImageInfo.h"
#include "include/gpu/GrSamplerState.h"
#include "include/private/GrResourceKey.h"
#include "include/private/SkNoncopyable.h"
#include "src/gpu/GrColorSpaceInfo.h"
class GrFragmentProcessor;
class GrRecordingContext;
class GrTexture;
class GrTextureProxy;
class SkColorSpace;
class SkMatrix;
struct SkRect;
* 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 GrSamplerState. 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 {
struct CopyParams {
GrSamplerState::Filter fFilter;
int fWidth;
int fHeight;
enum 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 std::unique_ptr<GrFragmentProcessor> createFragmentProcessor(
const SkMatrix& textureMatrix,
const SkRect& constraintRect,
FilterConstraint filterConstraint,
bool coordsLimitedToConstraintRect,
const GrSamplerState::Filter* filterOrNullForBicubic) = 0;
* 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 may have been scaled to fit the texture or the original may have been copied into
* a subrect of the copy. 'scaleAdjust' must be applied to the normalized texture coordinates
* in order to correct for the latter case.
* If the GrSamplerState is known to clamp and use kNearest or kBilerp filter mode then the
* proxy will always be unscaled and nullptr can be passed for scaleAdjust. There is a weird
* contract that if scaleAdjust is not null it must be initialized to {1, 1} before calling
* this method. (TODO: Fix this and make this function always initialize scaleAdjust).
sk_sp<GrTextureProxy> refTextureProxyForParams(const GrSamplerState&,
SkScalar scaleAdjust[2]);
sk_sp<GrTextureProxy> refTextureProxyForParams(
const GrSamplerState::Filter* filterOrNullForBicubic, SkScalar scaleAdjust[2]);
* Returns a texture. If willNeedMips is true then the returned texture is guaranteed to have
* allocated mip map levels. This can be a performance win if future draws with the texture
* require mip maps.
// TODO: Once we remove support for npot textures, we should add a flag for must support repeat
// wrap mode. To support that flag now would require us to support scaleAdjust array like in
// refTextureProxyForParams, however the current public API that uses this call does not expose
// that array.
sk_sp<GrTextureProxy> refTextureProxy(GrMipMapped willNeedMips);
virtual ~GrTextureProducer() {}
int width() const { return fWidth; }
int height() const { return fHeight; }
GrColorType colorType() const { return fColorSpaceInfo.colorType(); }
SkAlphaType alphaType() const { return fColorSpaceInfo.alphaType(); }
SkColorSpace* colorSpace() const { return fColorSpaceInfo.colorSpace(); }
bool isAlphaOnly() const { return GrPixelConfigIsAlphaOnly(fColorSpaceInfo.config()); }
bool domainNeedsDecal() const { return fDomainNeedsDecal; }
// If the "texture" samples multiple images that have different resolutions (e.g. YUV420)
virtual bool hasMixedResolutions() const { return false; }
friend class GrTextureProducer_TestAccess;
GrTextureProducer(GrRecordingContext* context, int width, int height,
const GrColorSpaceInfo& csInfo, bool domainNeedsDecal)
: fContext(context)
, fWidth(width)
, fHeight(height)
, fColorSpaceInfo(csInfo)
, fDomainNeedsDecal(domainNeedsDecal) {}
/** Helper for creating a key for a copy from an original key. */
static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey,
const CopyParams& copyParams,
GrUniqueKey* copyKey) {
if (origKey.isValid()) {
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
builder[0] = static_cast<uint32_t>(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 the destination color space, then that information should also be incorporated
* in the key.
virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey) = 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, uint32_t contextUniqueID) = 0;
enum DomainMode {
// This can draw to accomplish the copy, thus the recording context is needed
static sk_sp<GrTextureProxy> CopyOnGpu(GrRecordingContext*,
sk_sp<GrTextureProxy> inputProxy,
const CopyParams& copyParams,
bool dstWillRequireMipMaps);
static DomainMode DetermineDomainMode(const SkRect& constraintRect,
FilterConstraint filterConstraint,
bool coordsLimitedToConstraintRect,
const GrSamplerState::Filter* filterModeOrNullForBicubic,
SkRect* domainRect);
std::unique_ptr<GrFragmentProcessor> createFragmentProcessorForDomainAndFilter(
sk_sp<GrTextureProxy> proxy,
const SkMatrix& textureMatrix,
const SkRect& domain,
const GrSamplerState::Filter* filterOrNullForBicubic);
GrRecordingContext* context() const { return fContext; }
virtual sk_sp<GrTextureProxy> onRefTextureProxyForParams(const GrSamplerState&,
bool willBeMipped,
SkScalar scaleAdjust[2]) = 0;
GrRecordingContext* fContext;
const int fWidth;
const int fHeight;
const GrColorSpaceInfo fColorSpaceInfo;
// If true, any domain effect uses kDecal instead of kClamp, and sampler filter uses
// kClampToBorder instead of kClamp.
const bool fDomainNeedsDecal;
typedef SkNoncopyable INHERITED;