blob: e12a9d69220d83dc39cb2e8b391156dd9dcce3d9 [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"
Brian Salomonb8f098d2020-01-07 11:15:44 -050021#include "src/gpu/effects/GrTextureEffect.h"
Brian Osmane8e54582016-11-28 10:06:27 -050022
Brian Osmane8e54582016-11-28 10:06:27 -050023/** Determines whether a texture domain is necessary and if so what domain to use. There are two
24 * rectangles to consider:
Robert Phillips3798c862017-03-27 11:08:16 -040025 * - The first is the content area specified by the texture adjuster (i.e., textureContentArea).
26 * We can *never* allow filtering to cause bleed of pixels outside this rectangle.
27 * - The second rectangle is the constraint rectangle (i.e., constraintRect), which is known to
28 * be contained by the content area. The filterConstraint specifies whether we are allowed to
29 * bleed across this rect.
Brian Osmane8e54582016-11-28 10:06:27 -050030 *
31 * We want to avoid using a domain if possible. We consider the above rectangles, the filter type,
32 * and whether the coords generated by the draw would all fall within the constraint rect. If the
33 * latter is true we only need to consider whether the filter would extend beyond the rects.
34 */
35GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode(
Brian Salomon2bbdcc42017-09-07 12:36:34 -040036 const SkRect& constraintRect,
37 FilterConstraint filterConstraint,
38 bool coordsLimitedToConstraintRect,
Greg Danielcc104db2020-02-03 14:17:08 -050039 GrSurfaceProxy* proxy,
Brian Salomon2bbdcc42017-09-07 12:36:34 -040040 const GrSamplerState::Filter* filterModeOrNullForBicubic,
41 SkRect* domainRect) {
Brian Salomon9f2b86c2019-10-22 10:37:46 -040042 const SkIRect proxyBounds = SkIRect::MakeSize(proxy->dimensions());
Robert Phillips51e7ca32017-03-27 10:14:08 -040043
44 SkASSERT(proxyBounds.contains(constraintRect));
Robert Phillips51e7ca32017-03-27 10:14:08 -040045
Brian Salomon5c60b752019-12-13 15:03:43 -050046 const bool proxyIsExact = proxy->isFunctionallyExact();
Brian Salomon4df00922017-09-07 16:34:11 +000047
Robert Phillips51e7ca32017-03-27 10:14:08 -040048 // If the constraint rectangle contains the whole proxy then no need for a domain.
49 if (constraintRect.contains(proxyBounds) && proxyIsExact) {
50 return kNoDomain_DomainMode;
51 }
52
Robert Phillips51e7ca32017-03-27 10:14:08 -040053 bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
54
55 // If we can filter outside the constraint rect, and there is no non-content area of the
56 // proxy, and we aren't going to generate sample coords outside the constraint rect then we
57 // don't need a domain.
Greg Danielc77085d2017-11-01 16:38:48 -040058 if (!restrictFilterToRect && proxyIsExact && coordsLimitedToConstraintRect) {
Robert Phillips51e7ca32017-03-27 10:14:08 -040059 return kNoDomain_DomainMode;
60 }
61
Brian Salomoned729f92020-02-05 12:15:18 -050062 // Get the domain inset based on sampling mode (or bail if mipped). This is used
63 // to evaluate whether we will read outside a non-exact proxy's dimensions.
64 // TODO: Let GrTextureEffect handle this.
Brian Salomon4df00922017-09-07 16:34:11 +000065 SkScalar filterHalfWidth = 0.f;
Robert Phillips51e7ca32017-03-27 10:14:08 -040066 if (filterModeOrNullForBicubic) {
67 switch (*filterModeOrNullForBicubic) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -040068 case GrSamplerState::Filter::kNearest:
Robert Phillips51e7ca32017-03-27 10:14:08 -040069 if (coordsLimitedToConstraintRect) {
70 return kNoDomain_DomainMode;
Brian Salomon4df00922017-09-07 16:34:11 +000071 } else {
72 filterHalfWidth = 0.f;
Robert Phillips51e7ca32017-03-27 10:14:08 -040073 }
74 break;
Brian Salomon2bbdcc42017-09-07 12:36:34 -040075 case GrSamplerState::Filter::kBilerp:
Brian Salomon4df00922017-09-07 16:34:11 +000076 filterHalfWidth = .5f;
Robert Phillips51e7ca32017-03-27 10:14:08 -040077 break;
Brian Salomon2bbdcc42017-09-07 12:36:34 -040078 case GrSamplerState::Filter::kMipMap:
Greg Danielc77085d2017-11-01 16:38:48 -040079 if (restrictFilterToRect || !proxyIsExact) {
Brian Salomon4df00922017-09-07 16:34:11 +000080 // No domain can save us here.
81 return kTightCopy_DomainMode;
82 }
83 return kNoDomain_DomainMode;
Robert Phillips51e7ca32017-03-27 10:14:08 -040084 }
Brian Salomon4df00922017-09-07 16:34:11 +000085 } else {
86 // bicubic does nearest filtering internally.
87 filterHalfWidth = 1.5f;
Robert Phillips51e7ca32017-03-27 10:14:08 -040088 }
89
Robert Phillips51e7ca32017-03-27 10:14:08 -040090 if (restrictFilterToRect) {
Brian Salomoned729f92020-02-05 12:15:18 -050091 *domainRect = constraintRect;
Greg Danielc77085d2017-11-01 16:38:48 -040092 } else if (!proxyIsExact) {
93 // If we got here then: proxy is not exact, the coords are limited to the
Brian Salomon4df00922017-09-07 16:34:11 +000094 // constraint rect, and we're allowed to filter across the constraint rect boundary. So
Greg Danielc77085d2017-11-01 16:38:48 -040095 // we check whether the filter would reach across the edge of the proxy.
Brian Salomon4df00922017-09-07 16:34:11 +000096 // We will only set the sides that are required.
97
Mike Reed274218e2018-01-08 15:05:02 -050098 *domainRect = SkRectPriv::MakeLargest();
Brian Salomon4df00922017-09-07 16:34:11 +000099 if (coordsLimitedToConstraintRect) {
100 // We may be able to use the fact that the texture coords are limited to the constraint
101 // rect in order to avoid having to add a domain.
102 bool needContentAreaConstraint = false;
Greg Danielc77085d2017-11-01 16:38:48 -0400103 if (proxyBounds.fRight - filterHalfWidth < constraintRect.fRight) {
Brian Salomoned729f92020-02-05 12:15:18 -0500104 domainRect->fRight = proxyBounds.fRight;
Brian Salomon4df00922017-09-07 16:34:11 +0000105 needContentAreaConstraint = true;
106 }
Greg Danielc77085d2017-11-01 16:38:48 -0400107 if (proxyBounds.fBottom - filterHalfWidth < constraintRect.fBottom) {
Brian Salomoned729f92020-02-05 12:15:18 -0500108 domainRect->fBottom = proxyBounds.fBottom;
Brian Salomon4df00922017-09-07 16:34:11 +0000109 needContentAreaConstraint = true;
110 }
111 if (!needContentAreaConstraint) {
112 return kNoDomain_DomainMode;
113 }
Robert Phillips51e7ca32017-03-27 10:14:08 -0400114 }
Brian Salomon4df00922017-09-07 16:34:11 +0000115 } else {
116 return kNoDomain_DomainMode;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400117 }
Brian Salomon4df00922017-09-07 16:34:11 +0000118
Brian Salomoned729f92020-02-05 12:15:18 -0500119 if (!filterModeOrNullForBicubic) {
120 // Bicubic doesn't yet rely on GrTextureEffect to do this insetting.
121 domainRect->inset(0.5f, 0.5f);
122 if (domainRect->fLeft > domainRect->fRight) {
123 domainRect->fLeft = domainRect->fRight =
124 SkScalarAve(domainRect->fLeft, domainRect->fRight);
125 }
126 if (domainRect->fTop > domainRect->fBottom) {
127 domainRect->fTop = domainRect->fBottom =
128 SkScalarAve(domainRect->fTop, domainRect->fBottom);
129 }
Brian Salomon4df00922017-09-07 16:34:11 +0000130 }
Brian Salomoned729f92020-02-05 12:15:18 -0500131
Brian Salomon4df00922017-09-07 16:34:11 +0000132 return kDomain_DomainMode;
Robert Phillips51e7ca32017-03-27 10:14:08 -0400133}
134
Brian Salomon777e1462020-02-28 21:10:31 -0500135std::unique_ptr<GrFragmentProcessor> GrTextureProducer::createFragmentProcessorForSubsetAndFilter(
Greg Danielcc104db2020-02-03 14:17:08 -0500136 GrSurfaceProxyView view,
Brian Salomonaff329b2017-08-11 09:40:37 -0400137 const SkMatrix& textureMatrix,
138 DomainMode domainMode,
139 const SkRect& domain,
Brian Salomon777e1462020-02-28 21:10:31 -0500140 GrSamplerState::WrapMode wrapX,
141 GrSamplerState::WrapMode wrapY,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400142 const GrSamplerState::Filter* filterOrNullForBicubic) {
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400143 SkASSERT(kTightCopy_DomainMode != domainMode);
Greg Danielcc104db2020-02-03 14:17:08 -0500144 SkASSERT(view.asTextureProxy());
Brian Salomonca6b2f42020-01-24 11:31:21 -0500145 const auto& caps = *fContext->priv().caps();
Brian Salomonfc118442019-11-22 19:09:27 -0500146 SkAlphaType srcAlphaType = this->alphaType();
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400147 if (filterOrNullForBicubic) {
Brian Salomon777e1462020-02-28 21:10:31 -0500148 GrSamplerState samplerState(wrapX, wrapY, *filterOrNullForBicubic);
Brian Salomonca6b2f42020-01-24 11:31:21 -0500149 if (kNoDomain_DomainMode == domainMode) {
Greg Danield2ccbb52020-02-05 10:45:39 -0500150 return GrTextureEffect::Make(std::move(view), srcAlphaType, textureMatrix, samplerState,
151 caps);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400152 }
Greg Danield2ccbb52020-02-05 10:45:39 -0500153 return GrTextureEffect::MakeSubset(std::move(view), srcAlphaType, textureMatrix,
Brian Salomonca6b2f42020-01-24 11:31:21 -0500154 samplerState, domain, caps);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400155 } else {
Brian Salomon1af72d12020-06-25 10:47:26 -0400156 static constexpr auto kDir = GrBicubicEffect::Direction::kXY;
157 static constexpr auto kKernel = GrBicubicEffect::Kernel::kMitchell;
Brian Salomond0d033a2020-02-18 16:59:28 -0500158 const auto& caps = *fContext->priv().caps();
159 if (kDomain_DomainMode == domainMode) {
Brian Salomon777e1462020-02-28 21:10:31 -0500160 return GrBicubicEffect::MakeSubset(std::move(view), srcAlphaType, textureMatrix, wrapX,
Brian Salomon1af72d12020-06-25 10:47:26 -0400161 wrapY, domain, kKernel, kDir, caps);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400162 } else {
Brian Salomon777e1462020-02-28 21:10:31 -0500163 return GrBicubicEffect::Make(std::move(view), srcAlphaType, textureMatrix, wrapX, wrapY,
Brian Salomon1af72d12020-06-25 10:47:26 -0400164 kKernel, kDir, caps);
Robert Phillipsb66b42f2017-03-14 08:53:02 -0400165 }
166 }
167}
Brian Salomon2a943df2018-05-04 13:43:19 -0400168
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500169GrSurfaceProxyView GrTextureProducer::view(GrMipMapped mipMapped) {
170 const GrCaps* caps = this->context()->priv().caps();
171 // Sanitize the MIP map request.
172 if (mipMapped == GrMipMapped::kYes) {
173 if ((this->width() == 1 && this->height() == 1) || !caps->mipMapSupport()) {
174 mipMapped = GrMipMapped::kNo;
Michael Ludwigddeed372019-02-20 16:50:10 -0500175 }
176 }
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500177 auto result = this->onView(mipMapped);
178 // Check to make sure if we requested MIPs that the returned texture has MIP maps or the format
179 // is not copyable.
180 SkASSERT(!result || mipMapped == GrMipMapped::kNo ||
181 result.asTextureProxy()->mipMapped() == GrMipMapped::kYes ||
Greg Danielcc104db2020-02-03 14:17:08 -0500182 !caps->isFormatCopyable(result.proxy()->backendFormat()));
Brian Salomon2a943df2018-05-04 13:43:19 -0400183 return result;
184}
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400185
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500186GrSurfaceProxyView GrTextureProducer::view(GrSamplerState::Filter filter) {
187 auto mipMapped = filter == GrSamplerState::Filter::kMipMap ? GrMipMapped::kYes
188 : GrMipMapped::kNo;
189 return this->view(mipMapped);
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400190}