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
onRefTextureProxyForParams(const GrSamplerState & params,bool willBeMipped,SkScalar scaleAdjust[2])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(), ©Params, scaleAdjust)) {
34 needsCopyForMipsOnly = GrGpu::IsACopyNeededForMips(fContext->contextPriv().caps(),
35 original.get(), params.filter(),
36 ©Params);
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(), ©Params, 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, ©Key);
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
createFragmentProcessor(const SkMatrix & textureMatrix,const SkRect & constraintRect,FilterConstraint filterConstraint,bool coordsLimitedToConstraintRect,const GrSamplerState::Filter * filterOrNullForBicubic)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