1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef GrTextureProducer_DEFINED
9 #define GrTextureProducer_DEFINED
10 
11 #include "GrResourceKey.h"
12 #include "GrSamplerState.h"
13 #include "SkImageInfo.h"
14 #include "SkNoncopyable.h"
15 
16 class GrFragmentProcessor;
17 class GrRecordingContext;
18 class GrTexture;
19 class GrTextureProxy;
20 class SkColorSpace;
21 class SkMatrix;
22 struct SkRect;
23 
24 /**
25  * Different GPUs and API extensions have different requirements with respect to what texture
26  * sampling parameters may be used with textures of various types. This class facilitates making
27  * texture compatible with a given GrSamplerState. There are two immediate subclasses defined
28  * below. One is a base class for sources that are inherently texture-backed (e.g. a texture-backed
29  * SkImage). It supports subsetting the original texture. The other is for use cases where the
30  * source can generate a texture that represents some content (e.g. cpu pixels, SkPicture, ...).
31  */
32 class GrTextureProducer : public SkNoncopyable {
33 public:
34     struct CopyParams {
35         GrSamplerState::Filter fFilter;
36         int fWidth;
37         int fHeight;
38     };
39 
40     enum FilterConstraint {
41         kYes_FilterConstraint,
42         kNo_FilterConstraint,
43     };
44 
45     /**
46      * Helper for creating a fragment processor to sample the texture with a given filtering mode.
47      * It attempts to avoid making texture copies or using domains whenever possible.
48      *
49      * @param textureMatrix                    Matrix used to access the texture. It is applied to
50      *                                         the local coords. The post-transformed coords should
51      *                                         be in texel units (rather than normalized) with
52      *                                         respect to this Producer's bounds (width()/height()).
53      * @param constraintRect                   A rect that represents the area of the texture to be
54      *                                         sampled. It must be contained in the Producer's
55      *                                         bounds as defined by width()/height().
56      * @param filterConstriant                 Indicates whether filtering is limited to
57      *                                         constraintRect.
58      * @param coordsLimitedToConstraintRect    Is it known that textureMatrix*localCoords is bound
59      *                                         by the portion of the texture indicated by
60      *                                         constraintRect (without consideration of filter
61      *                                         width, just the raw coords).
62      * @param filterOrNullForBicubic           If non-null indicates the filter mode. If null means
63      *                                         use bicubic filtering.
64      **/
65     virtual std::unique_ptr<GrFragmentProcessor> createFragmentProcessor(
66             const SkMatrix& textureMatrix,
67             const SkRect& constraintRect,
68             FilterConstraint filterConstraint,
69             bool coordsLimitedToConstraintRect,
70             const GrSamplerState::Filter* filterOrNullForBicubic) = 0;
71 
72     /**
73      *  Returns a texture that is safe for use with the params.
74      *
75      * If the size of the returned texture does not match width()/height() then the contents of the
76      * original may have been scaled to fit the texture or the original may have been copied into
77      * a subrect of the copy. 'scaleAdjust' must be  applied to the normalized texture coordinates
78      * in order to correct for the latter case.
79      *
80      * If the GrSamplerState is known to clamp and use kNearest or kBilerp filter mode then the
81      * proxy will always be unscaled and nullptr can be passed for scaleAdjust. There is a weird
82      * contract that if scaleAdjust is not null it must be initialized to {1, 1} before calling
83      * this method. (TODO: Fix this and make this function always initialize scaleAdjust).
84      */
85     sk_sp<GrTextureProxy> refTextureProxyForParams(const GrSamplerState&,
86                                                    SkScalar scaleAdjust[2]);
87 
88     sk_sp<GrTextureProxy> refTextureProxyForParams(
89             const GrSamplerState::Filter* filterOrNullForBicubic, SkScalar scaleAdjust[2]);
90 
91     /**
92      * Returns a texture. If willNeedMips is true then the returned texture is guaranteed to have
93      * allocated mip map levels. This can be a performance win if future draws with the texture
94      * require mip maps.
95      */
96     // TODO: Once we remove support for npot textures, we should add a flag for must support repeat
97     // wrap mode. To support that flag now would require us to support scaleAdjust array like in
98     // refTextureProxyForParams, however the current public API that uses this call does not expose
99     // that array.
100     sk_sp<GrTextureProxy> refTextureProxy(GrMipMapped willNeedMips);
101 
~GrTextureProducer()102     virtual ~GrTextureProducer() {}
103 
width()104     int width() const { return fWidth; }
height()105     int height() const { return fHeight; }
isAlphaOnly()106     bool isAlphaOnly() const { return fIsAlphaOnly; }
domainNeedsDecal()107     bool domainNeedsDecal() const { return fDomainNeedsDecal; }
108     virtual SkAlphaType alphaType() const = 0;
109     virtual SkColorSpace* colorSpace() const = 0;
110 
111 protected:
112     friend class GrTextureProducer_TestAccess;
113 
GrTextureProducer(GrRecordingContext * context,int width,int height,bool isAlphaOnly,bool domainNeedsDecal)114     GrTextureProducer(GrRecordingContext* context, int width, int height, bool isAlphaOnly,
115                       bool domainNeedsDecal)
116         : fContext(context)
117         , fWidth(width)
118         , fHeight(height)
119         , fIsAlphaOnly(isAlphaOnly)
120         , fDomainNeedsDecal(domainNeedsDecal) {}
121 
122     /** Helper for creating a key for a copy from an original key. */
MakeCopyKeyFromOrigKey(const GrUniqueKey & origKey,const CopyParams & copyParams,GrUniqueKey * copyKey)123     static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey,
124                                        const CopyParams& copyParams,
125                                        GrUniqueKey* copyKey) {
126         SkASSERT(!copyKey->isValid());
127         if (origKey.isValid()) {
128             static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
129             GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
130             builder[0] = static_cast<uint32_t>(copyParams.fFilter);
131             builder[1] = copyParams.fWidth;
132             builder[2] = copyParams.fHeight;
133         }
134     }
135 
136     /**
137     *  If we need to make a copy in order to be compatible with GrTextureParams producer is asked to
138     *  return a key that identifies its original content + the CopyParms parameter. If the producer
139     *  does not want to cache the stretched version (e.g. the producer is volatile), this should
140     *  simply return without initializing the copyKey. If the texture generated by this producer
141     *  depends on the destination color space, then that information should also be incorporated
142     *  in the key.
143     */
144     virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey) = 0;
145 
146     /**
147     *  If a stretched version of the texture is generated, it may be cached (assuming that
148     *  makeCopyKey() returns true). In that case, the maker is notified in case it
149     *  wants to note that for when the maker is destroyed.
150     */
151     virtual void didCacheCopy(const GrUniqueKey& copyKey, uint32_t contextUniqueID) = 0;
152 
153     enum DomainMode {
154         kNoDomain_DomainMode,
155         kDomain_DomainMode,
156         kTightCopy_DomainMode
157     };
158 
159     // This can draw to accomplish the copy, thus the recording context is needed
160     static sk_sp<GrTextureProxy> CopyOnGpu(GrRecordingContext*, sk_sp<GrTextureProxy> inputProxy,
161                                            const CopyParams& copyParams,
162                                            bool dstWillRequireMipMaps);
163 
164     static DomainMode DetermineDomainMode(const SkRect& constraintRect,
165                                           FilterConstraint filterConstraint,
166                                           bool coordsLimitedToConstraintRect,
167                                           GrTextureProxy*,
168                                           const GrSamplerState::Filter* filterModeOrNullForBicubic,
169                                           SkRect* domainRect);
170 
171     std::unique_ptr<GrFragmentProcessor> createFragmentProcessorForDomainAndFilter(
172             sk_sp<GrTextureProxy> proxy,
173             const SkMatrix& textureMatrix,
174             DomainMode,
175             const SkRect& domain,
176             const GrSamplerState::Filter* filterOrNullForBicubic);
177 
context()178     GrRecordingContext* context() const { return fContext; }
179 
180 private:
181     virtual sk_sp<GrTextureProxy> onRefTextureProxyForParams(const GrSamplerState&,
182                                                              bool willBeMipped,
183                                                              SkScalar scaleAdjust[2]) = 0;
184 
185     GrRecordingContext* fContext;
186     const int           fWidth;
187     const int           fHeight;
188     const bool          fIsAlphaOnly;
189     // If true, any domain effect uses kDecal instead of kClamp, and sampler filter uses
190     // kClampToBorder instead of kClamp.
191     const bool  fDomainNeedsDecal;
192 
193     typedef SkNoncopyable INHERITED;
194 };
195 
196 #endif
197