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 "src/gpu/GrTextureMaker.h"
9
10 #include "include/private/GrRecordingContext.h"
11 #include "src/gpu/GrColorSpaceXform.h"
12 #include "src/gpu/GrGpu.h"
13 #include "src/gpu/GrProxyProvider.h"
14 #include "src/gpu/GrRecordingContextPriv.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() > this->context()->priv().caps()->maxTextureSize() ||
20 this->height() > this->context()->priv().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(this->context()->priv().caps(), original.get(),
32 original->width(), original->height(),
33 params.filter(), ©Params, scaleAdjust)) {
34 needsCopyForMipsOnly = GrGpu::IsACopyNeededForMips(this->context()->priv().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(this->context()->priv().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 = this->context()->priv().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 =
58 proxyProvider->findOrCreateProxyByUniqueKey(copyKey, this->colorType(), origOrigin);
59 if (cachedProxy && (!willBeMipped || GrMipMapped::kYes == cachedProxy->mipMapped())) {
60 return cachedProxy;
61 }
62 }
63
64 sk_sp<GrTextureProxy> source;
65 if (original) {
66 source = std::move(original);
67 } else if (cachedProxy) {
68 source = cachedProxy;
69 } else {
70 // Since we will be copying this texture there is no reason to make it mipped
71 source = this->refOriginalTextureProxy(false, AllowedTexGenType::kAny);
72 }
73
74 if (!source) {
75 return nullptr;
76 }
77
78 sk_sp<GrTextureProxy> result =
79 CopyOnGpu(this->context(), source, this->colorType(), copyParams, willBeMipped);
80
81 if (!result) {
82 // If we were unable to make a copy and we only needed a copy for mips, then we will return
83 // the source texture here and require that the GPU backend is able to fall back to using
84 // bilerp if mips are required.
85 if (needsCopyForMipsOnly) {
86 return source;
87 }
88 return nullptr;
89 }
90
91 if (copyKey.isValid()) {
92 SkASSERT(result->origin() == origOrigin);
93 if (cachedProxy) {
94 SkASSERT(GrMipMapped::kYes == result->mipMapped() &&
95 GrMipMapped::kNo == cachedProxy->mipMapped());
96 // If we had a cachedProxy, that means there already is a proxy in the cache which
97 // matches the key, but it does not have mip levels and we require them. Thus we must
98 // remove the unique key from that proxy.
99 SkASSERT(cachedProxy->getUniqueKey() == copyKey);
100 proxyProvider->removeUniqueKeyFromProxy(cachedProxy.get());
101 }
102 proxyProvider->assignUniqueKeyToProxy(copyKey, result.get());
103 this->didCacheCopy(copyKey, proxyProvider->contextID());
104 }
105 return result;
106 }
107
createFragmentProcessor(const SkMatrix & textureMatrix,const SkRect & constraintRect,FilterConstraint filterConstraint,bool coordsLimitedToConstraintRect,const GrSamplerState::Filter * filterOrNullForBicubic)108 std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
109 const SkMatrix& textureMatrix,
110 const SkRect& constraintRect,
111 FilterConstraint filterConstraint,
112 bool coordsLimitedToConstraintRect,
113 const GrSamplerState::Filter* filterOrNullForBicubic) {
114 const GrSamplerState::Filter* fmForDetermineDomain = filterOrNullForBicubic;
115 if (filterOrNullForBicubic && GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic &&
116 kYes_FilterConstraint == filterConstraint) {
117 // TODO: Here we should force a copy restricted to the constraintRect since MIP maps will
118 // read outside the constraint rect. However, as in the adjuster case, we aren't currently
119 // doing that.
120 // We instead we compute the domain as though were bilerping which is only correct if we
121 // only sample level 0.
122 static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
123 fmForDetermineDomain = &kBilerp;
124 }
125
126 SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
127 sk_sp<GrTextureProxy> proxy(this->refTextureProxyForParams(filterOrNullForBicubic,
128 scaleAdjust));
129 if (!proxy) {
130 return nullptr;
131 }
132 SkMatrix adjustedMatrix = textureMatrix;
133 adjustedMatrix.postScale(scaleAdjust[0], scaleAdjust[1]);
134
135 SkRect domain;
136 DomainMode domainMode =
137 DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
138 proxy.get(), fmForDetermineDomain, &domain);
139 SkASSERT(kTightCopy_DomainMode != domainMode);
140 return this->createFragmentProcessorForDomainAndFilter(
141 std::move(proxy), adjustedMatrix, domainMode, domain, filterOrNullForBicubic);
142 }
143