/* * 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 { public: struct CopyParams { GrSamplerState::Filter 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 std::unique_ptr 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 refTextureProxyForParams(const GrSamplerState&, SkScalar scaleAdjust[2]); sk_sp 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 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 GrColorTypeIsAlphaOnly(fColorSpaceInfo.colorType()); } bool domainNeedsDecal() const { return fDomainNeedsDecal; } // If the "texture" samples multiple images that have different resolutions (e.g. YUV420) virtual bool hasMixedResolutions() const { return false; } protected: 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) { SkASSERT(!copyKey->isValid()); if (origKey.isValid()) { static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3); builder[0] = static_cast(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 { kNoDomain_DomainMode, kDomain_DomainMode, kTightCopy_DomainMode }; // This can draw to accomplish the copy, thus the recording context is needed static sk_sp CopyOnGpu(GrRecordingContext*, sk_sp inputProxy, GrColorType, const CopyParams& copyParams, bool dstWillRequireMipMaps); static DomainMode DetermineDomainMode(const SkRect& constraintRect, FilterConstraint filterConstraint, bool coordsLimitedToConstraintRect, GrTextureProxy*, const GrSamplerState::Filter* filterModeOrNullForBicubic, SkRect* domainRect); std::unique_ptr createFragmentProcessorForDomainAndFilter( sk_sp proxy, const SkMatrix& textureMatrix, DomainMode, const SkRect& domain, const GrSamplerState::Filter* filterOrNullForBicubic); GrRecordingContext* context() const { return fContext; } private: virtual sk_sp 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; }; #endif