blob: 1be75f96494ac7e83eaee828aa2434d98cf5d1b8 [file] [log] [blame]
Brian Osmane8e54582016-11-28 10:06:27 -05001/*
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 "GrTextureProducer.h"
Brian Salomonc65aec92017-03-09 09:03:58 -05009#include "GrClip.h"
Brian Osmane8e54582016-11-28 10:06:27 -050010#include "GrRenderTargetContext.h"
Robert Phillipsb66b42f2017-03-14 08:53:02 -040011#include "GrResourceProvider.h"
Robert Phillipsd9d84852017-06-09 10:48:29 -040012#include "GrTextureProxy.h"
Brian Osmane8e54582016-11-28 10:06:27 -050013#include "effects/GrBicubicEffect.h"
14#include "effects/GrSimpleTextureEffect.h"
15#include "effects/GrTextureDomain.h"
16
Robert Phillipsb66b42f2017-03-14 08:53:02 -040017sk_sp<GrTextureProxy> GrTextureProducer::CopyOnGpu(GrContext* context,
18 sk_sp<GrTextureProxy> inputProxy,
Greg Daniele1da1d92017-10-06 15:59:27 -040019 const CopyParams& copyParams,
20 bool dstWillRequireMipMaps) {
Robert Phillipsb66b42f2017-03-14 08:53:02 -040021 SkASSERT(context);
22
Robert Phillipsb66b42f2017-03-14 08:53:02 -040023 const SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
Greg Daniel45d63032017-10-30 13:41:26 -040024 GrMipMapped mipMapped = dstWillRequireMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo;
Robert Phillipsb66b42f2017-03-14 08:53:02 -040025
Robert Phillipsdd3b3f42017-04-24 10:57:28 -040026 sk_sp<GrRenderTargetContext> copyRTC = context->makeDeferredRenderTargetContextWithFallback(
Robert Phillipse44ef102017-07-21 15:37:19 -040027 SkBackingFit::kExact, dstRect.width(), dstRect.height(), inputProxy->config(), nullptr,
Greg Daniel45d63032017-10-30 13:41:26 -040028 0, mipMapped, inputProxy->origin());
Robert Phillipsb66b42f2017-03-14 08:53:02 -040029 if (!copyRTC) {
30 return nullptr;
31 }
32
33 GrPaint paint;
34 paint.setGammaCorrect(true);
35
Greg Danielc77085d2017-11-01 16:38:48 -040036 SkRect localRect = SkRect::MakeWH(inputProxy->width(), inputProxy->height());
Robert Phillipsb66b42f2017-03-14 08:53:02 -040037
38 bool needsDomain = false;
Brian Salomon2bbdcc42017-09-07 12:36:34 -040039 if (copyParams.fFilter != GrSamplerState::Filter::kNearest) {
Robert Phillips4f358be2017-03-23 08:21:00 -040040 bool resizing = localRect.width() != dstRect.width() ||
41 localRect.height() != dstRect.height();
Greg Danielc77085d2017-11-01 16:38:48 -040042 needsDomain = resizing && !GrResourceProvider::IsFunctionallyExact(inputProxy.get());
Robert Phillipsb66b42f2017-03-14 08:53:02 -040043 }
44
45 if (needsDomain) {
46 const SkRect domain = localRect.makeInset(0.5f, 0.5f);
47 // This would cause us to read values from outside the subset. Surely, the caller knows
48 // better!
Brian Salomon2bbdcc42017-09-07 12:36:34 -040049 SkASSERT(copyParams.fFilter != GrSamplerState::Filter::kMipMap);
Robert Phillipsb66b42f2017-03-14 08:53:02 -040050 paint.addColorFragmentProcessor(
Brian Osman2240be92017-10-18 13:15:13 -040051 GrTextureDomainEffect::Make(std::move(inputProxy), SkMatrix::I(), domain,
52 GrTextureDomain::kClamp_Mode, copyParams.fFilter));
Robert Phillipsb66b42f2017-03-14 08:53:02 -040053 } else {
Brian Salomon2bbdcc42017-09-07 12:36:34 -040054 GrSamplerState samplerState(GrSamplerState::WrapMode::kClamp, copyParams.fFilter);
Brian Osman2240be92017-10-18 13:15:13 -040055 paint.addColorTextureProcessor(std::move(inputProxy), SkMatrix::I(), samplerState);
Robert Phillipsb66b42f2017-03-14 08:53:02 -040056 }
57 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
58
59 copyRTC->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect,
60 localRect);
61 return copyRTC->asTextureProxyRef();
62}
63
Brian Osmane8e54582016-11-28 10:06:27 -050064/** Determines whether a texture domain is necessary and if so what domain to use. There are two
65 * rectangles to consider:
Robert Phillips3798c862017-03-27 11:08:16 -040066 * - The first is the content area specified by the texture adjuster (i.e., textureContentArea).
67 * We can *never* allow filtering to cause bleed of pixels outside this rectangle.
68 * - The second rectangle is the constraint rectangle (i.e., constraintRect), which is known to
69 * be contained by the content area. The filterConstraint specifies whether we are allowed to
70 * bleed across this rect.
Brian Osmane8e54582016-11-28 10:06:27 -050071 *
72 * We want to avoid using a domain if possible. We consider the above rectangles, the filter type,
73 * and whether the coords generated by the draw would all fall within the constraint rect. If the
74 * latter is true we only need to consider whether the filter would extend beyond the rects.
75 */
76GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode(
Brian Salomon2bbdcc42017-09-07 12:36:34 -040077 const SkRect& constraintRect,
78 FilterConstraint filterConstraint,
79 bool coordsLimitedToConstraintRect,
80 GrTextureProxy* proxy,
Brian Salomon2bbdcc42017-09-07 12:36:34 -040081 const GrSamplerState::Filter* filterModeOrNullForBicubic,
82 SkRect* domainRect) {
Robert Phillips51e7ca32017-03-27 10:14:08 -040083 const SkIRect proxyBounds = SkIRect::MakeWH(proxy->width(), proxy->height());
84
85 SkASSERT(proxyBounds.contains(constraintRect));
Robert Phillips51e7ca32017-03-27 10:14:08 -040086
87 const bool proxyIsExact = GrResourceProvider::IsFunctionallyExact(proxy);
Brian Salomon4df00922017-09-07 16:34:11 +000088
Robert Phillips51e7ca32017-03-27 10:14:08 -040089 // If the constraint rectangle contains the whole proxy then no need for a domain.
90 if (constraintRect.contains(proxyBounds) && proxyIsExact) {
91 return kNoDomain_DomainMode;
92 }
93
Robert Phillips51e7ca32017-03-27 10:14:08 -040094 bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
95
96 // If we can filter outside the constraint rect, and there is no non-content area of the
97 // proxy, and we aren't going to generate sample coords outside the constraint rect then we
98 // don't need a domain.
Greg Danielc77085d2017-11-01 16:38:48 -040099 if (!restrictFilterToRect && proxyIsExact && coordsLimitedToConstraintRect) {
Robert Phillips51e7ca32017-03-27 10:14:08 -0400100 return kNoDomain_DomainMode;
101 }
102
103 // Get the domain inset based on sampling mode (or bail if mipped)
Brian Salomon4df00922017-09-07 16:34:11 +0000104 SkScalar filterHalfWidth = 0.f;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400105 if (filterModeOrNullForBicubic) {
106 switch (*filterModeOrNullForBicubic) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400107 case GrSamplerState::Filter::kNearest:
Robert Phillips51e7ca32017-03-27 10:14:08 -0400108 if (coordsLimitedToConstraintRect) {
109 return kNoDomain_DomainMode;
Brian Salomon4df00922017-09-07 16:34:11 +0000110 } else {
111 filterHalfWidth = 0.f;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400112 }
113 break;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400114 case GrSamplerState::Filter::kBilerp:
Brian Salomon4df00922017-09-07 16:34:11 +0000115 filterHalfWidth = .5f;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400116 break;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400117 case GrSamplerState::Filter::kMipMap:
Greg Danielc77085d2017-11-01 16:38:48 -0400118 if (restrictFilterToRect || !proxyIsExact) {
Brian Salomon4df00922017-09-07 16:34:11 +0000119 // No domain can save us here.
120 return kTightCopy_DomainMode;
121 }
122 return kNoDomain_DomainMode;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400123 }
Brian Salomon4df00922017-09-07 16:34:11 +0000124 } else {
125 // bicubic does nearest filtering internally.
126 filterHalfWidth = 1.5f;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400127 }
128
129 // Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center
130 // of the edge texel. Pinning to the texel center has no impact on nearest mode and MIP-maps
131
132 static const SkScalar kDomainInset = 0.5f;
133 // Figure out the limits of pixels we're allowed to sample from.
134 // Unless we know the amount of outset and the texture matrix we have to conservatively enforce
135 // the domain.
136 if (restrictFilterToRect) {
137 *domainRect = constraintRect.makeInset(kDomainInset, kDomainInset);
Greg Danielc77085d2017-11-01 16:38:48 -0400138 } else if (!proxyIsExact) {
139 // If we got here then: proxy is not exact, the coords are limited to the
Brian Salomon4df00922017-09-07 16:34:11 +0000140 // constraint rect, and we're allowed to filter across the constraint rect boundary. So
Greg Danielc77085d2017-11-01 16:38:48 -0400141 // we check whether the filter would reach across the edge of the proxy.
Brian Salomon4df00922017-09-07 16:34:11 +0000142 // We will only set the sides that are required.
143
144 domainRect->setLargest();
145 if (coordsLimitedToConstraintRect) {
146 // We may be able to use the fact that the texture coords are limited to the constraint
147 // rect in order to avoid having to add a domain.
148 bool needContentAreaConstraint = false;
Greg Danielc77085d2017-11-01 16:38:48 -0400149 if (proxyBounds.fRight - filterHalfWidth < constraintRect.fRight) {
150 domainRect->fRight = proxyBounds.fRight - kDomainInset;
Brian Salomon4df00922017-09-07 16:34:11 +0000151 needContentAreaConstraint = true;
152 }
Greg Danielc77085d2017-11-01 16:38:48 -0400153 if (proxyBounds.fBottom - filterHalfWidth < constraintRect.fBottom) {
154 domainRect->fBottom = proxyBounds.fBottom - kDomainInset;
Brian Salomon4df00922017-09-07 16:34:11 +0000155 needContentAreaConstraint = true;
156 }
157 if (!needContentAreaConstraint) {
158 return kNoDomain_DomainMode;
159 }
160 } else {
161 // Our sample coords for the texture are allowed to be outside the constraintRect so we
162 // don't consider it when computing the domain.
Greg Danielc77085d2017-11-01 16:38:48 -0400163 domainRect->fRight = proxyBounds.fRight - kDomainInset;
164 domainRect->fBottom = proxyBounds.fBottom - kDomainInset;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400165 }
Brian Salomon4df00922017-09-07 16:34:11 +0000166 } else {
167 return kNoDomain_DomainMode;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400168 }
Brian Salomon4df00922017-09-07 16:34:11 +0000169
170 if (domainRect->fLeft > domainRect->fRight) {
171 domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight);
172 }
173 if (domainRect->fTop > domainRect->fBottom) {
174 domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom);
175 }
176 return kDomain_DomainMode;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400177}
178
Brian Salomonaff329b2017-08-11 09:40:37 -0400179std::unique_ptr<GrFragmentProcessor> GrTextureProducer::CreateFragmentProcessorForDomainAndFilter(
180 sk_sp<GrTextureProxy> proxy,
Brian Salomonaff329b2017-08-11 09:40:37 -0400181 const SkMatrix& textureMatrix,
182 DomainMode domainMode,
183 const SkRect& domain,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400184 const GrSamplerState::Filter* filterOrNullForBicubic) {
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400185 SkASSERT(kTightCopy_DomainMode != domainMode);
186 if (filterOrNullForBicubic) {
187 if (kDomain_DomainMode == domainMode) {
Brian Osman2240be92017-10-18 13:15:13 -0400188 return GrTextureDomainEffect::Make(std::move(proxy), textureMatrix, domain,
Brian Osman5e341672017-10-18 10:23:18 -0400189 GrTextureDomain::kClamp_Mode,
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400190 *filterOrNullForBicubic);
191 } else {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400192 GrSamplerState samplerState(GrSamplerState::WrapMode::kClamp, *filterOrNullForBicubic);
Brian Osman2240be92017-10-18 13:15:13 -0400193 return GrSimpleTextureEffect::Make(std::move(proxy), textureMatrix, samplerState);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400194 }
195 } else {
196 if (kDomain_DomainMode == domainMode) {
Brian Osman5e341672017-10-18 10:23:18 -0400197 return GrBicubicEffect::Make(std::move(proxy), textureMatrix, domain);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400198 } else {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400199 static const GrSamplerState::WrapMode kClampClamp[] = {
200 GrSamplerState::WrapMode::kClamp, GrSamplerState::WrapMode::kClamp};
Brian Osman5e341672017-10-18 10:23:18 -0400201 return GrBicubicEffect::Make(std::move(proxy), textureMatrix, kClampClamp);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400202 }
203 }
204}