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 "include/private/GrRecordingContext.h"
9#include "src/gpu/GrColorSpaceXform.h"
10#include "src/gpu/GrGpu.h"
11#include "src/gpu/GrProxyProvider.h"
12#include "src/gpu/GrRecordingContextPriv.h"
13#include "src/gpu/GrTextureAdjuster.h"
14#include "src/gpu/SkGr.h"
15
16GrTextureAdjuster::GrTextureAdjuster(GrRecordingContext* context,
17 GrSurfaceProxyView original,
18 const GrColorInfo& colorInfo,
19 uint32_t uniqueID)
20 : INHERITED(context, {colorInfo, original.proxy()->dimensions()})
21 , fOriginal(std::move(original))
22 , fUniqueID(uniqueID) {}
23
24GrSurfaceProxyView GrTextureAdjuster::makeMippedCopy() {
25 GrProxyProvider* proxyProvider = this->context()->priv().proxyProvider();
26
27 GrUniqueKey baseKey, mipMappedKey;
28 GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeSize(this->dimensions()));
29 if (baseKey.isValid()) {
30 static const GrUniqueKey::Domain kMipMappedDomain = GrUniqueKey::GenerateDomain();
31 GrUniqueKey::Builder builder(&mipMappedKey, baseKey, kMipMappedDomain, 0);
32 }
33 sk_sp<GrTextureProxy> cachedCopy;
34 if (mipMappedKey.isValid()) {
35 cachedCopy = proxyProvider->findOrCreateProxyByUniqueKey(mipMappedKey);
36 if (cachedCopy) {
37 return {std::move(cachedCopy), fOriginal.origin(), fOriginal.swizzle()};
38 }
39 }
40
41 auto copy = GrCopyBaseMipMapToView(this->context(), fOriginal);
42 if (!copy) {
43 return {};
44 }
45 if (mipMappedKey.isValid()) {
46 // TODO: If we move listeners up from SkImage_Lazy to SkImage_Base then add one here.
47 proxyProvider->assignUniqueKeyToProxy(mipMappedKey, copy.asTextureProxy());
48 }
49 return copy;
50}
51
52GrSurfaceProxyView GrTextureAdjuster::onView(GrMipMapped mipMapped) {
53 if (this->context()->priv().abandoned()) {
54 // The texture was abandoned.
55 return {};
56 }
57
58 SkASSERT(this->width() <= this->context()->priv().caps()->maxTextureSize() &&
59 this->height() <= this->context()->priv().caps()->maxTextureSize());
60
61 GrTextureProxy* texProxy = fOriginal.asTextureProxy();
62 SkASSERT(texProxy);
63 if (mipMapped == GrMipMapped::kNo || texProxy->mipMapped() == GrMipMapped::kYes) {
64 return fOriginal;
65 }
66
67 GrSurfaceProxyView copy = this->makeMippedCopy();
68 if (!copy) {
69 // If we were unable to make a copy and we only needed a copy for mips, then we will return
70 // the source texture here and require that the GPU backend is able to fall back to using
71 // bilerp if mips are required.
72 return fOriginal;
73 }
74 SkASSERT(copy.asTextureProxy());
75 return copy;
76}
77
78std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
79 const SkMatrix& textureMatrix,
80 const SkRect& constraintRect,
81 FilterConstraint filterConstraint,
82 bool coordsLimitedToConstraintRect,
83 GrSamplerState::WrapMode wrapX,
84 GrSamplerState::WrapMode wrapY,
85 const GrSamplerState::Filter* filterOrNullForBicubic) {
86 GrSurfaceProxyView view;
87 if (filterOrNullForBicubic) {
88 view = this->view(*filterOrNullForBicubic);
89 } else {
90 view = this->view(GrMipMapped::kNo);
91 }
92 if (!view) {
93 return nullptr;
94 }
95 SkASSERT(view.asTextureProxy());
96
97 SkRect domain;
98 DomainMode domainMode =
99 DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
100 view.proxy(), filterOrNullForBicubic, &domain);
101 if (kTightCopy_DomainMode == domainMode) {
102 // TODO: Copy the texture and adjust the texture matrix (both parts need to consider
103 // non-int constraint rect)
104 // For now: treat as bilerp and ignore what goes on above level 0.
105
106 // We only expect MIP maps to require a tight copy.
107 SkASSERT(filterOrNullForBicubic &&
108 GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic);
109 static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
110 domainMode =
111 DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
112 view.proxy(), &kBilerp, &domain);
113 SkASSERT(kTightCopy_DomainMode != domainMode);
114 }
115 SkASSERT(kNoDomain_DomainMode == domainMode ||
116 (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
117 return this->createFragmentProcessorForSubsetAndFilter(std::move(view), textureMatrix,
118 domainMode, domain, wrapX, wrapY,
119 filterOrNullForBicubic);
120}
121