blob: 62c4e9c30aa9d532c68813993e4eb84506a3393b [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
Brian Salomonb8f098d2020-01-07 11:15:44 -05008#include "src/gpu/GrTextureProducer.h"
9
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/private/GrRecordingContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/core/SkMipMap.h"
12#include "src/core/SkRectPriv.h"
13#include "src/gpu/GrClip.h"
14#include "src/gpu/GrContextPriv.h"
15#include "src/gpu/GrProxyProvider.h"
16#include "src/gpu/GrRecordingContextPriv.h"
17#include "src/gpu/GrRenderTargetContext.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040018#include "src/gpu/GrTextureProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/SkGr.h"
20#include "src/gpu/effects/GrBicubicEffect.h"
21#include "src/gpu/effects/GrTextureDomain.h"
Brian Salomonb8f098d2020-01-07 11:15:44 -050022#include "src/gpu/effects/GrTextureEffect.h"
Brian Osmane8e54582016-11-28 10:06:27 -050023
Brian Osmane8e54582016-11-28 10:06:27 -050024/** Determines whether a texture domain is necessary and if so what domain to use. There are two
25 * rectangles to consider:
Robert Phillips3798c862017-03-27 11:08:16 -040026 * - The first is the content area specified by the texture adjuster (i.e., textureContentArea).
27 * We can *never* allow filtering to cause bleed of pixels outside this rectangle.
28 * - The second rectangle is the constraint rectangle (i.e., constraintRect), which is known to
29 * be contained by the content area. The filterConstraint specifies whether we are allowed to
30 * bleed across this rect.
Brian Osmane8e54582016-11-28 10:06:27 -050031 *
32 * We want to avoid using a domain if possible. We consider the above rectangles, the filter type,
33 * and whether the coords generated by the draw would all fall within the constraint rect. If the
34 * latter is true we only need to consider whether the filter would extend beyond the rects.
35 */
36GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode(
Brian Salomon2bbdcc42017-09-07 12:36:34 -040037 const SkRect& constraintRect,
38 FilterConstraint filterConstraint,
39 bool coordsLimitedToConstraintRect,
Greg Danielcc104db2020-02-03 14:17:08 -050040 GrSurfaceProxy* proxy,
Brian Salomon2bbdcc42017-09-07 12:36:34 -040041 const GrSamplerState::Filter* filterModeOrNullForBicubic,
42 SkRect* domainRect) {
Brian Salomon9f2b86c2019-10-22 10:37:46 -040043 const SkIRect proxyBounds = SkIRect::MakeSize(proxy->dimensions());
Robert Phillips51e7ca32017-03-27 10:14:08 -040044
45 SkASSERT(proxyBounds.contains(constraintRect));
Robert Phillips51e7ca32017-03-27 10:14:08 -040046
Brian Salomon5c60b752019-12-13 15:03:43 -050047 const bool proxyIsExact = proxy->isFunctionallyExact();
Brian Salomon4df00922017-09-07 16:34:11 +000048
Robert Phillips51e7ca32017-03-27 10:14:08 -040049 // If the constraint rectangle contains the whole proxy then no need for a domain.
50 if (constraintRect.contains(proxyBounds) && proxyIsExact) {
51 return kNoDomain_DomainMode;
52 }
53
Robert Phillips51e7ca32017-03-27 10:14:08 -040054 bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
55
56 // If we can filter outside the constraint rect, and there is no non-content area of the
57 // proxy, and we aren't going to generate sample coords outside the constraint rect then we
58 // don't need a domain.
Greg Danielc77085d2017-11-01 16:38:48 -040059 if (!restrictFilterToRect && proxyIsExact && coordsLimitedToConstraintRect) {
Robert Phillips51e7ca32017-03-27 10:14:08 -040060 return kNoDomain_DomainMode;
61 }
62
Brian Salomoned729f92020-02-05 12:15:18 -050063 // Get the domain inset based on sampling mode (or bail if mipped). This is used
64 // to evaluate whether we will read outside a non-exact proxy's dimensions.
65 // TODO: Let GrTextureEffect handle this.
Brian Salomon4df00922017-09-07 16:34:11 +000066 SkScalar filterHalfWidth = 0.f;
Robert Phillips51e7ca32017-03-27 10:14:08 -040067 if (filterModeOrNullForBicubic) {
68 switch (*filterModeOrNullForBicubic) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -040069 case GrSamplerState::Filter::kNearest:
Robert Phillips51e7ca32017-03-27 10:14:08 -040070 if (coordsLimitedToConstraintRect) {
71 return kNoDomain_DomainMode;
Brian Salomon4df00922017-09-07 16:34:11 +000072 } else {
73 filterHalfWidth = 0.f;
Robert Phillips51e7ca32017-03-27 10:14:08 -040074 }
75 break;
Brian Salomon2bbdcc42017-09-07 12:36:34 -040076 case GrSamplerState::Filter::kBilerp:
Brian Salomon4df00922017-09-07 16:34:11 +000077 filterHalfWidth = .5f;
Robert Phillips51e7ca32017-03-27 10:14:08 -040078 break;
Brian Salomon2bbdcc42017-09-07 12:36:34 -040079 case GrSamplerState::Filter::kMipMap:
Greg Danielc77085d2017-11-01 16:38:48 -040080 if (restrictFilterToRect || !proxyIsExact) {
Brian Salomon4df00922017-09-07 16:34:11 +000081 // No domain can save us here.
82 return kTightCopy_DomainMode;
83 }
84 return kNoDomain_DomainMode;
Robert Phillips51e7ca32017-03-27 10:14:08 -040085 }
Brian Salomon4df00922017-09-07 16:34:11 +000086 } else {
87 // bicubic does nearest filtering internally.
88 filterHalfWidth = 1.5f;
Robert Phillips51e7ca32017-03-27 10:14:08 -040089 }
90
Robert Phillips51e7ca32017-03-27 10:14:08 -040091 if (restrictFilterToRect) {
Brian Salomoned729f92020-02-05 12:15:18 -050092 *domainRect = constraintRect;
Greg Danielc77085d2017-11-01 16:38:48 -040093 } else if (!proxyIsExact) {
94 // If we got here then: proxy is not exact, the coords are limited to the
Brian Salomon4df00922017-09-07 16:34:11 +000095 // constraint rect, and we're allowed to filter across the constraint rect boundary. So
Greg Danielc77085d2017-11-01 16:38:48 -040096 // we check whether the filter would reach across the edge of the proxy.
Brian Salomon4df00922017-09-07 16:34:11 +000097 // We will only set the sides that are required.
98
Mike Reed274218e2018-01-08 15:05:02 -050099 *domainRect = SkRectPriv::MakeLargest();
Brian Salomon4df00922017-09-07 16:34:11 +0000100 if (coordsLimitedToConstraintRect) {
101 // We may be able to use the fact that the texture coords are limited to the constraint
102 // rect in order to avoid having to add a domain.
103 bool needContentAreaConstraint = false;
Greg Danielc77085d2017-11-01 16:38:48 -0400104 if (proxyBounds.fRight - filterHalfWidth < constraintRect.fRight) {
Brian Salomoned729f92020-02-05 12:15:18 -0500105 domainRect->fRight = proxyBounds.fRight;
Brian Salomon4df00922017-09-07 16:34:11 +0000106 needContentAreaConstraint = true;
107 }
Greg Danielc77085d2017-11-01 16:38:48 -0400108 if (proxyBounds.fBottom - filterHalfWidth < constraintRect.fBottom) {
Brian Salomoned729f92020-02-05 12:15:18 -0500109 domainRect->fBottom = proxyBounds.fBottom;
Brian Salomon4df00922017-09-07 16:34:11 +0000110 needContentAreaConstraint = true;
111 }
112 if (!needContentAreaConstraint) {
113 return kNoDomain_DomainMode;
114 }
Robert Phillips51e7ca32017-03-27 10:14:08 -0400115 }
Brian Salomon4df00922017-09-07 16:34:11 +0000116 } else {
117 return kNoDomain_DomainMode;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400118 }
Brian Salomon4df00922017-09-07 16:34:11 +0000119
Brian Salomoned729f92020-02-05 12:15:18 -0500120 if (!filterModeOrNullForBicubic) {
121 // Bicubic doesn't yet rely on GrTextureEffect to do this insetting.
122 domainRect->inset(0.5f, 0.5f);
123 if (domainRect->fLeft > domainRect->fRight) {
124 domainRect->fLeft = domainRect->fRight =
125 SkScalarAve(domainRect->fLeft, domainRect->fRight);
126 }
127 if (domainRect->fTop > domainRect->fBottom) {
128 domainRect->fTop = domainRect->fBottom =
129 SkScalarAve(domainRect->fTop, domainRect->fBottom);
130 }
Brian Salomon4df00922017-09-07 16:34:11 +0000131 }
Brian Salomoned729f92020-02-05 12:15:18 -0500132
Brian Salomon4df00922017-09-07 16:34:11 +0000133 return kDomain_DomainMode;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400134}
135
Michael Ludwigddeed372019-02-20 16:50:10 -0500136std::unique_ptr<GrFragmentProcessor> GrTextureProducer::createFragmentProcessorForDomainAndFilter(
Greg Danielcc104db2020-02-03 14:17:08 -0500137 GrSurfaceProxyView view,
Brian Salomonaff329b2017-08-11 09:40:37 -0400138 const SkMatrix& textureMatrix,
139 DomainMode domainMode,
140 const SkRect& domain,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400141 const GrSamplerState::Filter* filterOrNullForBicubic) {
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400142 SkASSERT(kTightCopy_DomainMode != domainMode);
Greg Danielcc104db2020-02-03 14:17:08 -0500143 SkASSERT(view.asTextureProxy());
Brian Salomonca6b2f42020-01-24 11:31:21 -0500144 const auto& caps = *fContext->priv().caps();
Brian Salomonfc118442019-11-22 19:09:27 -0500145 SkAlphaType srcAlphaType = this->alphaType();
Brian Salomond0d033a2020-02-18 16:59:28 -0500146 auto wm = fDomainNeedsDecal ? GrSamplerState::WrapMode::kClampToBorder
147 : GrSamplerState::WrapMode::kClamp;
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400148 if (filterOrNullForBicubic) {
Brian Salomond0d033a2020-02-18 16:59:28 -0500149 GrSamplerState samplerState(wm, *filterOrNullForBicubic);
Brian Salomonca6b2f42020-01-24 11:31:21 -0500150 if (kNoDomain_DomainMode == domainMode) {
Greg Danield2ccbb52020-02-05 10:45:39 -0500151 return GrTextureEffect::Make(std::move(view), srcAlphaType, textureMatrix, samplerState,
152 caps);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400153 }
Greg Danield2ccbb52020-02-05 10:45:39 -0500154 return GrTextureEffect::MakeSubset(std::move(view), srcAlphaType, textureMatrix,
Brian Salomonca6b2f42020-01-24 11:31:21 -0500155 samplerState, domain, caps);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400156 } else {
Michael Ludwigddeed372019-02-20 16:50:10 -0500157
Brian Salomona86fc7a2019-05-28 20:42:58 -0400158 static constexpr auto kDir = GrBicubicEffect::Direction::kXY;
Brian Salomond0d033a2020-02-18 16:59:28 -0500159 const auto& caps = *fContext->priv().caps();
160 if (kDomain_DomainMode == domainMode) {
161 return GrBicubicEffect::MakeSubset(std::move(view), srcAlphaType, textureMatrix, wm, wm,
162 domain, kDir, caps);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400163 } else {
Brian Salomond0d033a2020-02-18 16:59:28 -0500164 return GrBicubicEffect::Make(std::move(view), srcAlphaType, textureMatrix, wm, wm, kDir,
165 caps);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400166 }
167 }
168}
Brian Salomon2a943df2018-05-04 13:43:19 -0400169
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500170GrSurfaceProxyView GrTextureProducer::view(GrMipMapped mipMapped) {
171 const GrCaps* caps = this->context()->priv().caps();
172 // Sanitize the MIP map request.
173 if (mipMapped == GrMipMapped::kYes) {
174 if ((this->width() == 1 && this->height() == 1) || !caps->mipMapSupport()) {
175 mipMapped = GrMipMapped::kNo;
Michael Ludwigddeed372019-02-20 16:50:10 -0500176 }
177 }
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500178 auto result = this->onView(mipMapped);
179 // Check to make sure if we requested MIPs that the returned texture has MIP maps or the format
180 // is not copyable.
181 SkASSERT(!result || mipMapped == GrMipMapped::kNo ||
182 result.asTextureProxy()->mipMapped() == GrMipMapped::kYes ||
Greg Danielcc104db2020-02-03 14:17:08 -0500183 !caps->isFormatCopyable(result.proxy()->backendFormat()));
Brian Salomon2a943df2018-05-04 13:43:19 -0400184 return result;
185}
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400186
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500187GrSurfaceProxyView GrTextureProducer::view(GrSamplerState::Filter filter) {
188 auto mipMapped = filter == GrSamplerState::Filter::kMipMap ? GrMipMapped::kYes
189 : GrMipMapped::kNo;
190 return this->view(mipMapped);
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400191}