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 #include "GrTextureMaker.h"
9 
10 #include "GrColorSpaceXform.h"
11 #include "GrContext.h"
12 #include "GrContextPriv.h"
13 #include "GrGpu.h"
14 #include "GrProxyProvider.h"
15 
16 sk_sp<GrTextureProxy> GrTextureMaker::onRefTextureProxyForParams(const GrSamplerState& params,
17                                                                  bool willBeMipped,
18                                                                  SkScalar scaleAdjust[2]) {
19     if (this->width() > fContext->contextPriv().caps()->maxTextureSize() ||
20         this->height() > fContext->contextPriv().caps()->maxTextureSize()) {
21         return nullptr;
22     }
23 
24     CopyParams copyParams;
25 
26     sk_sp<GrTextureProxy> original(this->refOriginalTextureProxy(willBeMipped,
27                                                                  AllowedTexGenType::kCheap));
28     bool needsCopyForMipsOnly = false;
29     if (original) {
30         if (!params.isRepeated() ||
31             !GrGpu::IsACopyNeededForRepeatWrapMode(fContext->contextPriv().caps(), original.get(),
32                                                    original->width(), original->height(),
33                                                    params.filter(), &copyParams, scaleAdjust)) {
34             needsCopyForMipsOnly = GrGpu::IsACopyNeededForMips(fContext->contextPriv().caps(),
35                                                                original.get(), params.filter(),
36                                                                &copyParams);
37             if (!needsCopyForMipsOnly) {
38                 return original;
39             }
40         }
41     } else {
42         if (!params.isRepeated() ||
43             !GrGpu::IsACopyNeededForRepeatWrapMode(fContext->contextPriv().caps(), nullptr,
44                                                    this->width(), this->height(),
45                                                    params.filter(), &copyParams, scaleAdjust)) {
46             return this->refOriginalTextureProxy(willBeMipped, AllowedTexGenType::kAny);
47         }
48     }
49 
50     GrProxyProvider* proxyProvider = fContext->contextPriv().proxyProvider();
51 
52     GrSurfaceOrigin origOrigin = original ? original->origin() : kTopLeft_GrSurfaceOrigin;
53     GrUniqueKey copyKey;
54     this->makeCopyKey(copyParams, &copyKey);
55     sk_sp<GrTextureProxy> cachedProxy;
56     if (copyKey.isValid()) {
57         cachedProxy = proxyProvider->findOrCreateProxyByUniqueKey(copyKey, origOrigin);
58         if (cachedProxy && (!willBeMipped || GrMipMapped::kYes == cachedProxy->mipMapped())) {
59             return cachedProxy;
60         }
61     }
62 
63     sk_sp<GrTextureProxy> source;
64     if (original) {
65         source = std::move(original);
66     } else if (cachedProxy) {
67         source = cachedProxy;
68     } else {
69         // Since we will be copying this texture there is no reason to make it mipped
70         source = this->refOriginalTextureProxy(false, AllowedTexGenType::kAny);
71     }
72 
73     if (!source) {
74         return nullptr;
75     }
76 
77     sk_sp<GrTextureProxy> result = CopyOnGpu(fContext, source, copyParams, willBeMipped);
78 
79     if (!result) {
80         // If we were unable to make a copy and we only needed a copy for mips, then we will return
81         // the source texture here and require that the GPU backend is able to fall back to using
82         // bilerp if mips are required.
83         if (needsCopyForMipsOnly) {
84             return source;
85         }
86         return nullptr;
87     }
88 
89     if (copyKey.isValid()) {
90         SkASSERT(result->origin() == origOrigin);
91         if (cachedProxy) {
92             SkASSERT(GrMipMapped::kYes == result->mipMapped() &&
93                      GrMipMapped::kNo == cachedProxy->mipMapped());
94             // If we had a cachedProxy, that means there already is a proxy in the cache which
95             // matches the key, but it does not have mip levels and we require them. Thus we must
96             // remove the unique key from that proxy.
97             SkASSERT(cachedProxy->getUniqueKey() == copyKey);
98             proxyProvider->removeUniqueKeyFromProxy(cachedProxy.get());
99         }
100         proxyProvider->assignUniqueKeyToProxy(copyKey, result.get());
101         this->didCacheCopy(copyKey, proxyProvider->contextUniqueID());
102     }
103     return result;
104 }
105 
106 std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
107         const SkMatrix& textureMatrix,
108         const SkRect& constraintRect,
109         FilterConstraint filterConstraint,
110         bool coordsLimitedToConstraintRect,
111         const GrSamplerState::Filter* filterOrNullForBicubic) {
112     const GrSamplerState::Filter* fmForDetermineDomain = filterOrNullForBicubic;
113     if (filterOrNullForBicubic && GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic &&
114         kYes_FilterConstraint == filterConstraint) {
115         // TODo: Here we should force a copy restricted to the constraintRect since MIP maps will
116         // read outside the constraint rect. However, as in the adjuster case, we aren't currently
117         // doing that.
118         // We instead we compute the domain as though were bilerping which is only correct if we
119         // only sample level 0.
120         static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
121         fmForDetermineDomain = &kBilerp;
122     }
123 
124     GrSamplerState samplerState;
125     if (filterOrNullForBicubic) {
126         samplerState = GrSamplerState(GrSamplerState::WrapMode::kClamp, *filterOrNullForBicubic);
127     } else {
128         // Bicubic doesn't use filtering for it's texture accesses.
129         samplerState = GrSamplerState::ClampNearest();
130     }
131     SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
132     sk_sp<GrTextureProxy> proxy(this->refTextureProxyForParams(samplerState, scaleAdjust));
133     if (!proxy) {
134         return nullptr;
135     }
136     SkMatrix adjustedMatrix = textureMatrix;
137     adjustedMatrix.postScale(scaleAdjust[0], scaleAdjust[1]);
138     SkRect domain;
139     DomainMode domainMode =
140         DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
141                             proxy.get(), fmForDetermineDomain, &domain);
142     SkASSERT(kTightCopy_DomainMode != domainMode);
143     return CreateFragmentProcessorForDomainAndFilter(std::move(proxy), adjustedMatrix, domainMode,
144                                                      domain, filterOrNullForBicubic);
145 }
146