commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2012 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 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 8 | #include "src/gpu/effects/GrTextureDomain.h" |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 9 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 10 | #include "include/gpu/GrTexture.h" |
| 11 | #include "include/private/SkFloatingPoint.h" |
| 12 | #include "src/gpu/GrProxyProvider.h" |
| 13 | #include "src/gpu/GrShaderCaps.h" |
| 14 | #include "src/gpu/GrSurfaceProxyPriv.h" |
| 15 | #include "src/gpu/effects/generated/GrSimpleTextureEffect.h" |
| 16 | #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" |
| 17 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
| 18 | #include "src/gpu/glsl/GrGLSLProgramDataManager.h" |
| 19 | #include "src/gpu/glsl/GrGLSLShaderBuilder.h" |
| 20 | #include "src/gpu/glsl/GrGLSLUniformHandler.h" |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 21 | |
Ben Wagner | f08d1d0 | 2018-06-18 15:11:00 -0400 | [diff] [blame] | 22 | #include <utility> |
| 23 | |
Michael Ludwig | 8fa469d | 2019-11-25 16:08:44 -0500 | [diff] [blame] | 24 | GrTextureDomain::GrTextureDomain(GrSurfaceProxy* proxy, const SkRect& domain, Mode modeX, |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 25 | Mode modeY, int index) |
| 26 | : fModeX(modeX) |
| 27 | , fModeY(modeY) |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 28 | , fIndex(index) { |
| 29 | |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 30 | if (!proxy) { |
| 31 | SkASSERT(modeX == kIgnore_Mode && modeY == kIgnore_Mode); |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 32 | return; |
| 33 | } |
| 34 | |
Brian Salomon | 9f2b86c | 2019-10-22 10:37:46 -0400 | [diff] [blame] | 35 | const SkRect kFullRect = proxy->getBoundsRect(); |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 36 | |
| 37 | // We don't currently handle domains that are empty or don't intersect the texture. |
| 38 | // It is OK if the domain rect is a line or point, but it should not be inverted. We do not |
| 39 | // handle rects that do not intersect the [0..1]x[0..1] rect. |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 40 | SkASSERT(domain.isSorted()); |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 41 | fDomain.fLeft = SkScalarPin(domain.fLeft, 0.0f, kFullRect.fRight); |
| 42 | fDomain.fRight = SkScalarPin(domain.fRight, fDomain.fLeft, kFullRect.fRight); |
| 43 | fDomain.fTop = SkScalarPin(domain.fTop, 0.0f, kFullRect.fBottom); |
| 44 | fDomain.fBottom = SkScalarPin(domain.fBottom, fDomain.fTop, kFullRect.fBottom); |
| 45 | SkASSERT(fDomain.fLeft <= fDomain.fRight); |
| 46 | SkASSERT(fDomain.fTop <= fDomain.fBottom); |
| 47 | } |
| 48 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 49 | GrTextureDomain::GrTextureDomain(const SkRect& domain, Mode modeX, Mode modeY, int index) |
| 50 | : fDomain(domain), fModeX(modeX), fModeY(modeY), fIndex(index) { |
| 51 | // We don't currently handle domains that are empty or don't intersect the texture. |
| 52 | // It is OK if the domain rect is a line or point, but it should not be inverted. |
| 53 | SkASSERT(domain.isSorted()); |
| 54 | } |
| 55 | |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 56 | ////////////////////////////////////////////////////////////////////////////// |
| 57 | |
Brian Salomon | 7caa137 | 2019-12-09 10:40:56 -0500 | [diff] [blame] | 58 | static void append_wrap(GrGLSLShaderBuilder* builder, GrTextureDomain::Mode mode, |
| 59 | const char* inCoord, const char* domainStart, const char* domainEnd, |
Brian Salomon | 095d246 | 2019-12-09 15:22:33 -0500 | [diff] [blame] | 60 | bool is2D, const char* out) { |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 61 | switch(mode) { |
| 62 | case GrTextureDomain::kIgnore_Mode: |
Brian Salomon | 7caa137 | 2019-12-09 10:40:56 -0500 | [diff] [blame] | 63 | builder->codeAppendf("%s = %s;\n", out, inCoord); |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 64 | break; |
| 65 | case GrTextureDomain::kDecal_Mode: |
| 66 | // The lookup coordinate to use for decal will be clamped just like kClamp_Mode, |
| 67 | // it's just that the post-processing will be different, so fall through |
| 68 | case GrTextureDomain::kClamp_Mode: |
Brian Salomon | 7caa137 | 2019-12-09 10:40:56 -0500 | [diff] [blame] | 69 | builder->codeAppendf("%s = clamp(%s, %s, %s);", out, inCoord, domainStart, domainEnd); |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 70 | break; |
| 71 | case GrTextureDomain::kRepeat_Mode: |
Brian Salomon | 7caa137 | 2019-12-09 10:40:56 -0500 | [diff] [blame] | 72 | builder->codeAppendf("%s = mod(%s - %s, %s - %s) + %s;", out, inCoord, domainStart, |
| 73 | domainEnd, domainStart, domainStart); |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 74 | break; |
Brian Salomon | 7caa137 | 2019-12-09 10:40:56 -0500 | [diff] [blame] | 75 | case GrTextureDomain::kMirrorRepeat_Mode: { |
Brian Salomon | 095d246 | 2019-12-09 15:22:33 -0500 | [diff] [blame] | 76 | const char* type = is2D ? "float2" : "float"; |
Brian Salomon | 7caa137 | 2019-12-09 10:40:56 -0500 | [diff] [blame] | 77 | builder->codeAppend("{"); |
Brian Salomon | 095d246 | 2019-12-09 15:22:33 -0500 | [diff] [blame] | 78 | builder->codeAppendf("%s w = %s - %s;", type, domainEnd, domainStart); |
| 79 | builder->codeAppendf("%s w2 = 2 * w;", type); |
| 80 | builder->codeAppendf("%s m = mod(%s - %s, w2);", type, inCoord, domainStart); |
Brian Salomon | 7caa137 | 2019-12-09 10:40:56 -0500 | [diff] [blame] | 81 | builder->codeAppendf("%s = mix(m, w2 - m, step(w, m)) + %s;", out, domainStart); |
| 82 | builder->codeAppend("}"); |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 83 | break; |
Brian Salomon | 7caa137 | 2019-12-09 10:40:56 -0500 | [diff] [blame] | 84 | } |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 85 | } |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 86 | } |
| 87 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 88 | void GrTextureDomain::GLDomain::sampleProcessor(const GrTextureDomain& textureDomain, |
| 89 | const char* inColor, |
| 90 | const char* outColor, |
| 91 | const SkString& inCoords, |
| 92 | GrGLSLFragmentProcessor* parent, |
| 93 | GrGLSLFragmentProcessor::EmitArgs& args, |
| 94 | int childIndex) { |
| 95 | auto appendProcessorSample = [parent, &args, childIndex, inColor](const char* coord) { |
| 96 | SkString outColor("childColor"); |
| 97 | parent->invokeChild(childIndex, inColor, &outColor, args, coord); |
| 98 | return outColor; |
| 99 | }; |
| 100 | this->sample(args.fFragBuilder, args.fUniformHandler, textureDomain, outColor, inCoords, |
| 101 | appendProcessorSample); |
| 102 | } |
| 103 | |
egdaniel | 2d721d3 | 2015-11-11 13:06:05 -0800 | [diff] [blame] | 104 | void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, |
egdaniel | 7ea439b | 2015-12-03 09:20:44 -0800 | [diff] [blame] | 105 | GrGLSLUniformHandler* uniformHandler, |
Brian Salomon | 1edc5b9 | 2016-11-29 13:43:46 -0500 | [diff] [blame] | 106 | const GrShaderCaps* shaderCaps, |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 107 | const GrTextureDomain& textureDomain, |
| 108 | const char* outColor, |
| 109 | const SkString& inCoords, |
egdaniel | 09aa1fc | 2016-04-20 07:09:46 -0700 | [diff] [blame] | 110 | GrGLSLFragmentProcessor::SamplerHandle sampler, |
Brian Osman | 2240be9 | 2017-10-18 13:15:13 -0400 | [diff] [blame] | 111 | const char* inModulateColor) { |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 112 | auto appendTextureSample = [&sampler, inModulateColor, builder](const char* coord) { |
| 113 | builder->codeAppend("half4 textureColor = "); |
Brian Salomon | 87e9ddb | 2019-12-19 14:50:22 -0500 | [diff] [blame^] | 114 | builder->appendTextureLookupAndBlend(inModulateColor, SkBlendMode::kModulate, sampler, |
| 115 | coord); |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 116 | builder->codeAppend(";"); |
| 117 | return SkString("textureColor"); |
| 118 | }; |
| 119 | this->sample(builder, uniformHandler, textureDomain, outColor, inCoords, appendTextureSample); |
| 120 | } |
| 121 | |
| 122 | void GrTextureDomain::GLDomain::sample(GrGLSLShaderBuilder* builder, |
| 123 | GrGLSLUniformHandler* uniformHandler, |
| 124 | const GrTextureDomain& textureDomain, |
| 125 | const char* outColor, |
| 126 | const SkString& inCoords, |
| 127 | const std::function<AppendSample>& appendSample) { |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 128 | SkASSERT(!fHasMode || (textureDomain.modeX() == fModeX && textureDomain.modeY() == fModeY)); |
| 129 | SkDEBUGCODE(fModeX = textureDomain.modeX();) |
| 130 | SkDEBUGCODE(fModeY = textureDomain.modeY();) |
Hans Wennborg | c63ec5c | 2017-12-08 18:56:23 -0800 | [diff] [blame] | 131 | SkDEBUGCODE(fHasMode = true;) |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 132 | |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 133 | if ((textureDomain.modeX() != kIgnore_Mode || textureDomain.modeY() != kIgnore_Mode) && |
| 134 | !fDomainUni.isValid()) { |
| 135 | // Must include the domain uniform since at least one axis uses it |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 136 | const char* name; |
| 137 | SkString uniName("TexDom"); |
| 138 | if (textureDomain.fIndex >= 0) { |
| 139 | uniName.appendS32(textureDomain.fIndex); |
| 140 | } |
Ethan Nicholas | f7b8820 | 2017-09-18 14:10:39 -0400 | [diff] [blame] | 141 | fDomainUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, |
egdaniel | 7ea439b | 2015-12-03 09:20:44 -0800 | [diff] [blame] | 142 | uniName.c_str(), &name); |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 143 | fDomainName = name; |
| 144 | } |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 145 | |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 146 | bool decalX = textureDomain.modeX() == kDecal_Mode; |
| 147 | bool decalY = textureDomain.modeY() == kDecal_Mode; |
| 148 | if ((decalX || decalY) && !fDecalUni.isValid()) { |
| 149 | const char* name; |
| 150 | SkString uniName("DecalParams"); |
| 151 | if (textureDomain.fIndex >= 0) { |
| 152 | uniName.appendS32(textureDomain.fIndex); |
joshualitt | 5ae5fc5 | 2014-07-29 12:59:27 -0700 | [diff] [blame] | 153 | } |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 154 | // Half3 since this will hold texture width, height, and then a step function control param |
| 155 | fDecalUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf3_GrSLType, |
| 156 | uniName.c_str(), &name); |
| 157 | fDecalName = name; |
| 158 | } |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 159 | |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 160 | // Add a block so that we can declare variables |
| 161 | GrGLSLShaderBuilder::ShaderBlock block(builder); |
| 162 | // Always use a local variable for the input coordinates; often callers pass in an expression |
| 163 | // and we want to cache it across all of its references in the code below |
| 164 | builder->codeAppendf("float2 origCoord = %s;", inCoords.c_str()); |
Brian Salomon | 7caa137 | 2019-12-09 10:40:56 -0500 | [diff] [blame] | 165 | builder->codeAppend("float2 clampedCoord;"); |
| 166 | SkString start; |
| 167 | SkString end; |
Brian Salomon | 095d246 | 2019-12-09 15:22:33 -0500 | [diff] [blame] | 168 | bool is2D = textureDomain.modeX() == textureDomain.modeY(); |
| 169 | if (is2D) { |
| 170 | // Doing the domain setup using vectors seems to avoid shader compilation issues on |
| 171 | // Chromecast, possibly due to reducing shader length. |
| 172 | start.printf("%s.xy", fDomainName.c_str()); |
| 173 | end.printf("%s.zw", fDomainName.c_str()); |
| 174 | append_wrap(builder, textureDomain.modeX(), "origCoord", start.c_str(), end.c_str(), |
| 175 | true, "clampedCoord"); |
| 176 | } else { |
| 177 | // Apply x mode to the x coordinate using the left and right edges of the domain rect |
| 178 | // (stored as the x and z components of the domain uniform). |
| 179 | start.printf("%s.x", fDomainName.c_str()); |
| 180 | end.printf("%s.z", fDomainName.c_str()); |
| 181 | append_wrap(builder, textureDomain.modeX(), "origCoord.x", start.c_str(), end.c_str(), |
| 182 | false, "clampedCoord.x"); |
| 183 | // Repeat the same logic for y. |
| 184 | start.printf("%s.y", fDomainName.c_str()); |
| 185 | end.printf("%s.w", fDomainName.c_str()); |
| 186 | append_wrap(builder, textureDomain.modeY(), "origCoord.y", start.c_str(), end.c_str(), |
| 187 | false, "clampedCoord.y"); |
| 188 | } |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 189 | // Sample 'appendSample' at the clamped coordinate location. |
| 190 | SkString color = appendSample("clampedCoord"); |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 191 | |
| 192 | // Apply decal mode's transparency interpolation if needed |
| 193 | if (decalX || decalY) { |
| 194 | // The decal err is the max absoluate value between the clamped coordinate and the original |
| 195 | // pixel coordinate. This will then be clamped to 1.f if it's greater than the control |
| 196 | // parameter, which simulates kNearest and kBilerp behavior depending on if it's 0 or 1. |
| 197 | if (decalX && decalY) { |
Ethan Nicholas | e1f5502 | 2019-02-05 17:17:40 -0500 | [diff] [blame] | 198 | builder->codeAppendf("half err = max(half(abs(clampedCoord.x - origCoord.x) * %s.x), " |
| 199 | "half(abs(clampedCoord.y - origCoord.y) * %s.y));", |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 200 | fDecalName.c_str(), fDecalName.c_str()); |
| 201 | } else if (decalX) { |
Ethan Nicholas | e1f5502 | 2019-02-05 17:17:40 -0500 | [diff] [blame] | 202 | builder->codeAppendf("half err = half(abs(clampedCoord.x - origCoord.x) * %s.x);", |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 203 | fDecalName.c_str()); |
| 204 | } else { |
| 205 | SkASSERT(decalY); |
Ethan Nicholas | e1f5502 | 2019-02-05 17:17:40 -0500 | [diff] [blame] | 206 | builder->codeAppendf("half err = half(abs(clampedCoord.y - origCoord.y) * %s.y);", |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 207 | fDecalName.c_str()); |
joshualitt | 5ae5fc5 | 2014-07-29 12:59:27 -0700 | [diff] [blame] | 208 | } |
joshualitt | 5ae5fc5 | 2014-07-29 12:59:27 -0700 | [diff] [blame] | 209 | |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 210 | // Apply a transform to the error rate, which let's us simulate nearest or bilerp filtering |
| 211 | // in the same shader. When the texture is nearest filtered, fSizeName.z is set to 1/2 so |
| 212 | // this becomes a step function centered at .5 away from the clamped coordinate (but the |
| 213 | // domain for decal is inset by .5 so the edge lines up properly). When bilerp, fSizeName.z |
| 214 | // is set to 1 and it becomes a simple linear blend between texture and transparent. |
| 215 | builder->codeAppendf("if (err > %s.z) { err = 1.0; } else if (%s.z < 1) { err = 0.0; }", |
| 216 | fDecalName.c_str(), fDecalName.c_str()); |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 217 | builder->codeAppendf("%s = mix(%s, half4(0, 0, 0, 0), err);", outColor, color.c_str()); |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 218 | } else { |
| 219 | // A simple look up |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 220 | builder->codeAppendf("%s = %s;", outColor, color.c_str()); |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 221 | } |
| 222 | } |
| 223 | |
egdaniel | 018fb62 | 2015-10-28 07:26:40 -0700 | [diff] [blame] | 224 | void GrTextureDomain::GLDomain::setData(const GrGLSLProgramDataManager& pdman, |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 225 | const GrTextureDomain& textureDomain, |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 226 | const GrSurfaceProxyView& view, |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 227 | const GrSamplerState& state) { |
| 228 | // We want a hard transition from texture content to trans-black in nearest mode. |
| 229 | bool filterDecal = state.filter() != GrSamplerState::Filter::kNearest; |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 230 | this->setData(pdman, textureDomain, view.proxy(), view.origin(), filterDecal); |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 231 | } |
Michael Ludwig | 170de01 | 2019-11-15 21:55:18 +0000 | [diff] [blame] | 232 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 233 | void GrTextureDomain::GLDomain::setData(const GrGLSLProgramDataManager& pdman, |
| 234 | const GrTextureDomain& textureDomain, |
| 235 | bool filterIfDecal) { |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 236 | // The origin we pass here doesn't matter |
| 237 | this->setData(pdman, textureDomain, nullptr, kTopLeft_GrSurfaceOrigin, filterIfDecal); |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 238 | } |
| 239 | |
| 240 | void GrTextureDomain::GLDomain::setData(const GrGLSLProgramDataManager& pdman, |
| 241 | const GrTextureDomain& textureDomain, |
| 242 | const GrSurfaceProxy* proxy, |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 243 | GrSurfaceOrigin origin, |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 244 | bool filterIfDecal) { |
| 245 | SkASSERT(fHasMode && textureDomain.modeX() == fModeX && textureDomain.modeY() == fModeY); |
| 246 | if (kIgnore_Mode == textureDomain.modeX() && kIgnore_Mode == textureDomain.modeY()) { |
| 247 | return; |
| 248 | } |
| 249 | // If the texture is using nearest filtering, then the decal filter weight should step from |
| 250 | // 0 (texture) to 1 (transparent) one half pixel away from the domain. When doing any other |
| 251 | // form of filtering, the weight should be 1.0 so that it smoothly interpolates between the |
| 252 | // texture and transparent. |
| 253 | // Start off assuming we're in pixel units and later adjust if we have to deal with normalized |
| 254 | // texture coords. |
| 255 | float decalFilterWeights[3] = {1.f, 1.f, filterIfDecal ? 1.f : 0.5f}; |
| 256 | bool sendDecalData = textureDomain.modeX() == kDecal_Mode || |
| 257 | textureDomain.modeY() == kDecal_Mode; |
| 258 | float tempDomainValues[4]; |
| 259 | const float* values; |
| 260 | if (proxy) { |
Brian Salomon | 246bc3d | 2018-12-06 15:33:02 -0500 | [diff] [blame] | 261 | SkScalar wInv, hInv, h; |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 262 | GrTexture* tex = proxy->peekTexture(); |
Michael Ludwig | 8fa469d | 2019-11-25 16:08:44 -0500 | [diff] [blame] | 263 | if (proxy->backendFormat().textureType() == GrTextureType::kRectangle) { |
Brian Salomon | 246bc3d | 2018-12-06 15:33:02 -0500 | [diff] [blame] | 264 | wInv = hInv = 1.f; |
| 265 | h = tex->height(); |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 266 | // Don't do any scaling by texture size for decal filter rate, it's already in |
| 267 | // pixels |
Brian Salomon | 246bc3d | 2018-12-06 15:33:02 -0500 | [diff] [blame] | 268 | } else { |
| 269 | wInv = SK_Scalar1 / tex->width(); |
| 270 | hInv = SK_Scalar1 / tex->height(); |
| 271 | h = 1.f; |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 272 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 273 | // Account for texture coord normalization in decal filter weights. |
| 274 | decalFilterWeights[0] = tex->width(); |
| 275 | decalFilterWeights[1] = tex->height(); |
Brian Salomon | 246bc3d | 2018-12-06 15:33:02 -0500 | [diff] [blame] | 276 | } |
Robert Phillips | e98234f | 2017-01-09 14:23:59 -0500 | [diff] [blame] | 277 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 278 | tempDomainValues[0] = SkScalarToFloat(textureDomain.domain().fLeft * wInv); |
| 279 | tempDomainValues[1] = SkScalarToFloat(textureDomain.domain().fTop * hInv); |
| 280 | tempDomainValues[2] = SkScalarToFloat(textureDomain.domain().fRight * wInv); |
| 281 | tempDomainValues[3] = SkScalarToFloat(textureDomain.domain().fBottom * hInv); |
Robert Phillips | e98234f | 2017-01-09 14:23:59 -0500 | [diff] [blame] | 282 | |
Michael Ludwig | 8fa469d | 2019-11-25 16:08:44 -0500 | [diff] [blame] | 283 | if (proxy->backendFormat().textureType() == GrTextureType::kRectangle) { |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 284 | SkASSERT(tempDomainValues[0] >= 0.0f && tempDomainValues[0] <= proxy->width()); |
| 285 | SkASSERT(tempDomainValues[1] >= 0.0f && tempDomainValues[1] <= proxy->height()); |
| 286 | SkASSERT(tempDomainValues[2] >= 0.0f && tempDomainValues[2] <= proxy->width()); |
| 287 | SkASSERT(tempDomainValues[3] >= 0.0f && tempDomainValues[3] <= proxy->height()); |
Brian Salomon | 246bc3d | 2018-12-06 15:33:02 -0500 | [diff] [blame] | 288 | } else { |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 289 | SkASSERT(tempDomainValues[0] >= 0.0f && tempDomainValues[0] <= 1.0f); |
| 290 | SkASSERT(tempDomainValues[1] >= 0.0f && tempDomainValues[1] <= 1.0f); |
| 291 | SkASSERT(tempDomainValues[2] >= 0.0f && tempDomainValues[2] <= 1.0f); |
| 292 | SkASSERT(tempDomainValues[3] >= 0.0f && tempDomainValues[3] <= 1.0f); |
Brian Salomon | 246bc3d | 2018-12-06 15:33:02 -0500 | [diff] [blame] | 293 | } |
Robert Phillips | e98234f | 2017-01-09 14:23:59 -0500 | [diff] [blame] | 294 | |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 295 | // vertical flip if necessary |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 296 | if (kBottomLeft_GrSurfaceOrigin == origin) { |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 297 | tempDomainValues[1] = h - tempDomainValues[1]; |
| 298 | tempDomainValues[3] = h - tempDomainValues[3]; |
Brian Salomon | 246bc3d | 2018-12-06 15:33:02 -0500 | [diff] [blame] | 299 | |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 300 | // The top and bottom were just flipped, so correct the ordering |
| 301 | // of elements so that values = (l, t, r, b). |
Ben Wagner | f08d1d0 | 2018-06-18 15:11:00 -0400 | [diff] [blame] | 302 | using std::swap; |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 303 | swap(tempDomainValues[1], tempDomainValues[3]); |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 304 | } |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 305 | values = tempDomainValues; |
| 306 | } else { |
| 307 | values = textureDomain.domain().asScalars(); |
| 308 | } |
| 309 | if (!std::equal(values, values + 4, fPrevDomain)) { |
| 310 | pdman.set4fv(fDomainUni, 1, values); |
| 311 | std::copy_n(values, 4, fPrevDomain); |
| 312 | } |
| 313 | if (sendDecalData && |
| 314 | !std::equal(decalFilterWeights, decalFilterWeights + 3, fPrevDeclFilterWeights)) { |
| 315 | pdman.set3fv(fDecalUni, 1, decalFilterWeights); |
| 316 | std::copy_n(decalFilterWeights, 3, fPrevDeclFilterWeights); |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 317 | } |
| 318 | } |
| 319 | |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 320 | /////////////////////////////////////////////////////////////////////////////// |
Brian Salomon | 587e08f | 2017-01-27 10:59:27 -0500 | [diff] [blame] | 321 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 322 | std::unique_ptr<GrFragmentProcessor> GrDomainEffect::Make(std::unique_ptr<GrFragmentProcessor> fp, |
| 323 | const SkRect& domain, |
| 324 | GrTextureDomain::Mode mode, |
| 325 | bool decalIsFiltered) { |
| 326 | return Make(std::move(fp), domain, mode, mode, decalIsFiltered); |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 327 | } |
| 328 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 329 | std::unique_ptr<GrFragmentProcessor> GrDomainEffect::Make(std::unique_ptr<GrFragmentProcessor> fp, |
| 330 | const SkRect& domain, |
| 331 | GrTextureDomain::Mode modeX, |
| 332 | GrTextureDomain::Mode modeY, |
| 333 | bool decalIsFiltered) { |
| 334 | if (modeX == GrTextureDomain::kIgnore_Mode && modeY == GrTextureDomain::kIgnore_Mode) { |
| 335 | return fp; |
| 336 | } |
| 337 | int count = 0; |
| 338 | GrCoordTransform* coordTransform = nullptr; |
| 339 | for (auto [transform, ignored] : GrFragmentProcessor::FPCoordTransformRange(*fp)) { |
| 340 | ++count; |
| 341 | coordTransform = &transform; |
| 342 | } |
| 343 | // If there are no coord transforms on the passed FP or it's children then there's no need to |
| 344 | // enforce a domain. |
| 345 | // We have a limitation that only one coord transform is support when overriding local coords. |
| 346 | // If that limit were relaxed we would need to add a coord transform for each descendent FP |
| 347 | // transform and possibly have multiple domain rects to account for different proxy |
| 348 | // normalization and y-reversals. |
| 349 | if (count != 1) { |
| 350 | return fp; |
| 351 | } |
| 352 | GrCoordTransform transformCopy = *coordTransform; |
| 353 | // Reset the child FP's coord transform. |
| 354 | *coordTransform = {}; |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 355 | // If both domain modes happen to be ignore, it would be faster to just drop the domain logic |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 356 | // entirely and return the original FP. We'd need a GrMatrixProcessor if the matrix is not |
| 357 | // identity, though. |
| 358 | return std::unique_ptr<GrFragmentProcessor>(new GrDomainEffect( |
| 359 | std::move(fp), transformCopy, domain, modeX, modeY, decalIsFiltered)); |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 360 | } |
| 361 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 362 | std::unique_ptr<GrFragmentProcessor> GrDomainEffect::Make(std::unique_ptr<GrFragmentProcessor> fp, |
| 363 | const SkRect& domain, |
| 364 | GrTextureDomain::Mode mode, |
| 365 | GrSamplerState::Filter filter) { |
| 366 | bool filterIfDecal = filter != GrSamplerState::Filter::kNearest; |
| 367 | return Make(std::move(fp), domain, mode, filterIfDecal); |
| 368 | } |
| 369 | |
| 370 | std::unique_ptr<GrFragmentProcessor> GrDomainEffect::Make(std::unique_ptr<GrFragmentProcessor> fp, |
| 371 | const SkRect& domain, |
| 372 | GrTextureDomain::Mode modeX, |
| 373 | GrTextureDomain::Mode modeY, |
| 374 | GrSamplerState::Filter filter) { |
| 375 | bool filterIfDecal = filter != GrSamplerState::Filter::kNearest; |
| 376 | return Make(std::move(fp), domain, modeX, modeY, filterIfDecal); |
| 377 | } |
| 378 | GrFragmentProcessor::OptimizationFlags GrDomainEffect::Flags(GrFragmentProcessor* fp, |
| 379 | GrTextureDomain::Mode modeX, |
| 380 | GrTextureDomain::Mode modeY) { |
| 381 | auto fpFlags = GrFragmentProcessor::ProcessorOptimizationFlags(fp); |
| 382 | if (modeX == GrTextureDomain::kDecal_Mode || modeY == GrTextureDomain::kDecal_Mode) { |
| 383 | return fpFlags & ~kPreservesOpaqueInput_OptimizationFlag; |
| 384 | } |
| 385 | return fpFlags; |
| 386 | } |
| 387 | |
| 388 | GrDomainEffect::GrDomainEffect(std::unique_ptr<GrFragmentProcessor> fp, |
| 389 | const GrCoordTransform& coordTransform, |
| 390 | const SkRect& domain, |
| 391 | GrTextureDomain::Mode modeX, |
| 392 | GrTextureDomain::Mode modeY, |
| 393 | bool decalIsFiltered) |
| 394 | : INHERITED(kGrDomainEffect_ClassID, Flags(fp.get(), modeX, modeY)) |
| 395 | , fCoordTransform(coordTransform) |
| 396 | , fDomain(domain, modeX, modeY) |
| 397 | , fDecalIsFiltered(decalIsFiltered) { |
| 398 | SkASSERT(fp); |
| 399 | fp->setSampledWithExplicitCoords(true); |
| 400 | this->registerChildProcessor(std::move(fp)); |
Brian Salomon | 6cd51b5 | 2017-07-26 19:07:15 -0400 | [diff] [blame] | 401 | this->addCoordTransform(&fCoordTransform); |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 402 | if (fDomain.modeX() != GrTextureDomain::kDecal_Mode && |
| 403 | fDomain.modeY() != GrTextureDomain::kDecal_Mode) { |
| 404 | // Canonicalize this don't care value so we don't have to worry about it elsewhere. |
| 405 | fDecalIsFiltered = false; |
| 406 | } |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 407 | } |
| 408 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 409 | GrDomainEffect::GrDomainEffect(const GrDomainEffect& that) |
| 410 | : INHERITED(kGrDomainEffect_ClassID, that.optimizationFlags()) |
Brian Salomon | 3f6f965 | 2017-07-28 07:34:05 -0400 | [diff] [blame] | 411 | , fCoordTransform(that.fCoordTransform) |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 412 | , fDomain(that.fDomain) |
| 413 | , fDecalIsFiltered(that.fDecalIsFiltered) { |
| 414 | auto child = that.childProcessor(0).clone(); |
| 415 | child->setSampledWithExplicitCoords(true); |
| 416 | this->registerChildProcessor(std::move(child)); |
Brian Salomon | 3f6f965 | 2017-07-28 07:34:05 -0400 | [diff] [blame] | 417 | this->addCoordTransform(&fCoordTransform); |
Brian Salomon | 3f6f965 | 2017-07-28 07:34:05 -0400 | [diff] [blame] | 418 | } |
| 419 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 420 | void GrDomainEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, |
| 421 | GrProcessorKeyBuilder* b) const { |
| 422 | b->add32(GrTextureDomain::GLDomain::DomainKey(fDomain)); |
joshualitt | eb2a676 | 2014-12-04 11:35:33 -0800 | [diff] [blame] | 423 | } |
| 424 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 425 | GrGLSLFragmentProcessor* GrDomainEffect::onCreateGLSLInstance() const { |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 426 | class GLSLProcessor : public GrGLSLFragmentProcessor { |
| 427 | public: |
| 428 | void emitCode(EmitArgs& args) override { |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 429 | const GrDomainEffect& de = args.fFp.cast<GrDomainEffect>(); |
| 430 | const GrTextureDomain& domain = de.fDomain; |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 431 | |
Ethan Nicholas | d4efe68 | 2019-08-29 16:10:13 -0400 | [diff] [blame] | 432 | SkString coords2D = |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 433 | args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint); |
Brian Osman | c468963 | 2016-12-19 17:04:59 -0500 | [diff] [blame] | 434 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 435 | fGLDomain.sampleProcessor(domain, args.fInputColor, args.fOutputColor, coords2D, this, |
| 436 | args, 0); |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 437 | } |
| 438 | |
| 439 | protected: |
Brian Salomon | ab015ef | 2017-04-04 10:15:51 -0400 | [diff] [blame] | 440 | void onSetData(const GrGLSLProgramDataManager& pdman, |
| 441 | const GrFragmentProcessor& fp) override { |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 442 | const GrDomainEffect& de = fp.cast<GrDomainEffect>(); |
| 443 | const GrTextureDomain& domain = de.fDomain; |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 444 | // TODO: Update GrCoordTransform to return a view instead of proxy |
| 445 | const GrSurfaceProxy* proxy = de.fCoordTransform.proxy(); |
| 446 | // If we don't have a proxy the value of the origin doesn't matter |
| 447 | GrSurfaceOrigin origin = proxy ? proxy->origin() : kTopLeft_GrSurfaceOrigin; |
| 448 | fGLDomain.setData(pdman, domain, proxy, origin, de.fDecalIsFiltered); |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 449 | } |
| 450 | |
| 451 | private: |
| 452 | GrTextureDomain::GLDomain fGLDomain; |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 453 | }; |
| 454 | |
| 455 | return new GLSLProcessor; |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 456 | } |
| 457 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 458 | bool GrDomainEffect::onIsEqual(const GrFragmentProcessor& sBase) const { |
| 459 | auto& td = sBase.cast<GrDomainEffect>(); |
| 460 | return fDomain == td.fDomain && fDecalIsFiltered == td.fDecalIsFiltered; |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 461 | } |
| 462 | |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 463 | /////////////////////////////////////////////////////////////////////////////// |
| 464 | |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 465 | GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDomainEffect); |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 466 | |
Hal Canary | 6f6961e | 2017-01-31 13:50:44 -0500 | [diff] [blame] | 467 | #if GR_TEST_UTILS |
Brian Salomon | 7eabfe8 | 2019-12-02 14:20:20 -0500 | [diff] [blame] | 468 | std::unique_ptr<GrFragmentProcessor> GrDomainEffect::TestCreate(GrProcessorTestData* d) { |
| 469 | do { |
| 470 | GrTextureDomain::Mode modeX = |
| 471 | (GrTextureDomain::Mode)d->fRandom->nextULessThan(GrTextureDomain::kModeCount); |
| 472 | GrTextureDomain::Mode modeY = |
| 473 | (GrTextureDomain::Mode)d->fRandom->nextULessThan(GrTextureDomain::kModeCount); |
| 474 | auto child = GrProcessorUnitTest::MakeChildFP(d); |
| 475 | const auto* childPtr = child.get(); |
| 476 | SkRect domain; |
| 477 | // We assert if the child's coord transform has a proxy and the domain rect is outside its |
| 478 | // bounds. |
| 479 | GrFragmentProcessor::CoordTransformIter ctIter(*child); |
| 480 | if (!ctIter) { |
| 481 | continue; |
| 482 | } |
| 483 | auto [transform, fp] = *ctIter; |
| 484 | if (auto proxy = transform.proxy()) { |
| 485 | auto [w, h] = proxy->backingStoreDimensions(); |
| 486 | domain.fLeft = d->fRandom->nextRangeScalar(0, w); |
| 487 | domain.fRight = d->fRandom->nextRangeScalar(0, w); |
| 488 | domain.fTop = d->fRandom->nextRangeScalar(0, h); |
| 489 | domain.fBottom = d->fRandom->nextRangeScalar(0, h); |
| 490 | } else { |
| 491 | domain.fLeft = d->fRandom->nextRangeScalar(-100.f, 100.f); |
| 492 | domain.fRight = d->fRandom->nextRangeScalar(-100.f, 100.f); |
| 493 | domain.fTop = d->fRandom->nextRangeScalar(-100.f, 100.f); |
| 494 | domain.fBottom = d->fRandom->nextRangeScalar(-100.f, 100.f); |
| 495 | } |
| 496 | domain.sort(); |
| 497 | bool filterIfDecal = d->fRandom->nextBool(); |
| 498 | auto result = GrDomainEffect::Make(std::move(child), domain, modeX, modeY, filterIfDecal); |
| 499 | if (result && result.get() != childPtr) { |
| 500 | return result; |
| 501 | } |
| 502 | } while (true); |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 503 | } |
Hal Canary | 6f6961e | 2017-01-31 13:50:44 -0500 | [diff] [blame] | 504 | #endif |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 505 | |
| 506 | /////////////////////////////////////////////////////////////////////////////// |
Brian Salomon | aff329b | 2017-08-11 09:40:37 -0400 | [diff] [blame] | 507 | std::unique_ptr<GrFragmentProcessor> GrDeviceSpaceTextureDecalFragmentProcessor::Make( |
Michael Ludwig | 8fa469d | 2019-11-25 16:08:44 -0500 | [diff] [blame] | 508 | sk_sp<GrSurfaceProxy> proxy, const SkIRect& subset, const SkIPoint& deviceSpaceOffset) { |
Brian Salomon | aff329b | 2017-08-11 09:40:37 -0400 | [diff] [blame] | 509 | return std::unique_ptr<GrFragmentProcessor>(new GrDeviceSpaceTextureDecalFragmentProcessor( |
Robert Phillips | fbcef6e | 2017-06-15 12:07:18 -0400 | [diff] [blame] | 510 | std::move(proxy), subset, deviceSpaceOffset)); |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 511 | } |
| 512 | |
| 513 | GrDeviceSpaceTextureDecalFragmentProcessor::GrDeviceSpaceTextureDecalFragmentProcessor( |
Michael Ludwig | 8fa469d | 2019-11-25 16:08:44 -0500 | [diff] [blame] | 514 | sk_sp<GrSurfaceProxy> proxy, const SkIRect& subset, const SkIPoint& deviceSpaceOffset) |
Ethan Nicholas | abff956 | 2017-10-09 10:54:08 -0400 | [diff] [blame] | 515 | : INHERITED(kGrDeviceSpaceTextureDecalFragmentProcessor_ClassID, |
| 516 | kCompatibleWithCoverageAsAlpha_OptimizationFlag) |
Brian Salomon | 2bbdcc4 | 2017-09-07 12:36:34 -0400 | [diff] [blame] | 517 | , fTextureSampler(proxy, GrSamplerState::ClampNearest()) |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 518 | , fTextureDomain(proxy.get(), |
| 519 | GrTextureDomain::MakeTexelDomain(subset, GrTextureDomain::kDecal_Mode), |
| 520 | GrTextureDomain::kDecal_Mode, GrTextureDomain::kDecal_Mode) { |
Brian Salomon | f7dcd76 | 2018-07-30 14:48:15 -0400 | [diff] [blame] | 521 | this->setTextureSamplerCnt(1); |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 522 | fDeviceSpaceOffset.fX = deviceSpaceOffset.fX - subset.fLeft; |
| 523 | fDeviceSpaceOffset.fY = deviceSpaceOffset.fY - subset.fTop; |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 524 | } |
| 525 | |
Brian Salomon | 1a2a7ab | 2017-07-26 13:11:51 -0400 | [diff] [blame] | 526 | GrDeviceSpaceTextureDecalFragmentProcessor::GrDeviceSpaceTextureDecalFragmentProcessor( |
| 527 | const GrDeviceSpaceTextureDecalFragmentProcessor& that) |
Ethan Nicholas | abff956 | 2017-10-09 10:54:08 -0400 | [diff] [blame] | 528 | : INHERITED(kGrDeviceSpaceTextureDecalFragmentProcessor_ClassID, |
| 529 | kCompatibleWithCoverageAsAlpha_OptimizationFlag) |
Brian Salomon | 1a2a7ab | 2017-07-26 13:11:51 -0400 | [diff] [blame] | 530 | , fTextureSampler(that.fTextureSampler) |
| 531 | , fTextureDomain(that.fTextureDomain) |
| 532 | , fDeviceSpaceOffset(that.fDeviceSpaceOffset) { |
Brian Salomon | f7dcd76 | 2018-07-30 14:48:15 -0400 | [diff] [blame] | 533 | this->setTextureSamplerCnt(1); |
Brian Salomon | 1a2a7ab | 2017-07-26 13:11:51 -0400 | [diff] [blame] | 534 | } |
| 535 | |
Brian Salomon | aff329b | 2017-08-11 09:40:37 -0400 | [diff] [blame] | 536 | std::unique_ptr<GrFragmentProcessor> GrDeviceSpaceTextureDecalFragmentProcessor::clone() const { |
| 537 | return std::unique_ptr<GrFragmentProcessor>( |
| 538 | new GrDeviceSpaceTextureDecalFragmentProcessor(*this)); |
Brian Salomon | 1a2a7ab | 2017-07-26 13:11:51 -0400 | [diff] [blame] | 539 | } |
| 540 | |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 541 | GrGLSLFragmentProcessor* GrDeviceSpaceTextureDecalFragmentProcessor::onCreateGLSLInstance() const { |
| 542 | class GLSLProcessor : public GrGLSLFragmentProcessor { |
| 543 | public: |
| 544 | void emitCode(EmitArgs& args) override { |
| 545 | const GrDeviceSpaceTextureDecalFragmentProcessor& dstdfp = |
| 546 | args.fFp.cast<GrDeviceSpaceTextureDecalFragmentProcessor>(); |
| 547 | const char* scaleAndTranslateName; |
| 548 | fScaleAndTranslateUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, |
Ethan Nicholas | f7b8820 | 2017-09-18 14:10:39 -0400 | [diff] [blame] | 549 | kHalf4_GrSLType, |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 550 | "scaleAndTranslate", |
| 551 | &scaleAndTranslateName); |
Ethan Nicholas | e1f5502 | 2019-02-05 17:17:40 -0500 | [diff] [blame] | 552 | args.fFragBuilder->codeAppendf("half2 coords = half2(sk_FragCoord.xy * %s.xy + %s.zw);", |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 553 | scaleAndTranslateName, scaleAndTranslateName); |
| 554 | fGLDomain.sampleTexture(args.fFragBuilder, |
| 555 | args.fUniformHandler, |
Brian Salomon | 1edc5b9 | 2016-11-29 13:43:46 -0500 | [diff] [blame] | 556 | args.fShaderCaps, |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 557 | dstdfp.fTextureDomain, |
| 558 | args.fOutputColor, |
| 559 | SkString("coords"), |
| 560 | args.fTexSamplers[0], |
| 561 | args.fInputColor); |
| 562 | } |
| 563 | |
| 564 | protected: |
Brian Salomon | ab015ef | 2017-04-04 10:15:51 -0400 | [diff] [blame] | 565 | void onSetData(const GrGLSLProgramDataManager& pdman, |
| 566 | const GrFragmentProcessor& fp) override { |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 567 | const GrDeviceSpaceTextureDecalFragmentProcessor& dstdfp = |
| 568 | fp.cast<GrDeviceSpaceTextureDecalFragmentProcessor>(); |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 569 | const auto& view = dstdfp.textureSampler(0).view(); |
| 570 | SkISize textureDims = view.proxy()->backingStoreDimensions(); |
Robert Phillips | 9bee2e5 | 2017-05-29 12:37:20 -0400 | [diff] [blame] | 571 | |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 572 | fGLDomain.setData(pdman, dstdfp.fTextureDomain, view, |
Michael Ludwig | be315a2 | 2018-12-17 09:50:51 -0500 | [diff] [blame] | 573 | dstdfp.textureSampler(0).samplerState()); |
Michael Ludwig | 8fa469d | 2019-11-25 16:08:44 -0500 | [diff] [blame] | 574 | float iw = 1.f / textureDims.width(); |
| 575 | float ih = 1.f / textureDims.height(); |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 576 | float scaleAndTransData[4] = { |
| 577 | iw, ih, |
| 578 | -dstdfp.fDeviceSpaceOffset.fX * iw, -dstdfp.fDeviceSpaceOffset.fY * ih |
| 579 | }; |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 580 | if (view.origin() == kBottomLeft_GrSurfaceOrigin) { |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 581 | scaleAndTransData[1] = -scaleAndTransData[1]; |
| 582 | scaleAndTransData[3] = 1 - scaleAndTransData[3]; |
| 583 | } |
| 584 | pdman.set4fv(fScaleAndTranslateUni, 1, scaleAndTransData); |
| 585 | } |
| 586 | |
| 587 | private: |
| 588 | GrTextureDomain::GLDomain fGLDomain; |
| 589 | UniformHandle fScaleAndTranslateUni; |
| 590 | }; |
| 591 | |
| 592 | return new GLSLProcessor; |
| 593 | } |
| 594 | |
| 595 | bool GrDeviceSpaceTextureDecalFragmentProcessor::onIsEqual(const GrFragmentProcessor& fp) const { |
| 596 | const GrDeviceSpaceTextureDecalFragmentProcessor& dstdfp = |
| 597 | fp.cast<GrDeviceSpaceTextureDecalFragmentProcessor>(); |
Robert Phillips | bd99c0c | 2019-12-12 13:26:58 +0000 | [diff] [blame] | 598 | return dstdfp.fTextureSampler.view().proxy()->underlyingUniqueID() == |
| 599 | fTextureSampler.view().proxy()->underlyingUniqueID() && |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 600 | dstdfp.fDeviceSpaceOffset == fDeviceSpaceOffset && |
| 601 | dstdfp.fTextureDomain == fTextureDomain; |
| 602 | } |
| 603 | |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 604 | /////////////////////////////////////////////////////////////////////////////// |
| 605 | |
| 606 | GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDeviceSpaceTextureDecalFragmentProcessor); |
| 607 | |
Hal Canary | 6f6961e | 2017-01-31 13:50:44 -0500 | [diff] [blame] | 608 | #if GR_TEST_UTILS |
Brian Salomon | aff329b | 2017-08-11 09:40:37 -0400 | [diff] [blame] | 609 | std::unique_ptr<GrFragmentProcessor> GrDeviceSpaceTextureDecalFragmentProcessor::TestCreate( |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 610 | GrProcessorTestData* d) { |
Brian Salomon | 766098d | 2019-12-18 10:41:58 -0500 | [diff] [blame] | 611 | auto [proxy, at, ct] = d->randomProxy(); |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 612 | SkIRect subset; |
Robert Phillips | 40fd7c9 | 2017-01-30 08:06:27 -0500 | [diff] [blame] | 613 | subset.fLeft = d->fRandom->nextULessThan(proxy->width() - 1); |
| 614 | subset.fRight = d->fRandom->nextRangeU(subset.fLeft, proxy->width()); |
| 615 | subset.fTop = d->fRandom->nextULessThan(proxy->height() - 1); |
| 616 | subset.fBottom = d->fRandom->nextRangeU(subset.fTop, proxy->height()); |
Brian Salomon | 2ebd0c8 | 2016-10-03 17:15:28 -0400 | [diff] [blame] | 617 | SkIPoint pt; |
| 618 | pt.fX = d->fRandom->nextULessThan(2048); |
| 619 | pt.fY = d->fRandom->nextULessThan(2048); |
Robert Phillips | fbcef6e | 2017-06-15 12:07:18 -0400 | [diff] [blame] | 620 | return GrDeviceSpaceTextureDecalFragmentProcessor::Make(std::move(proxy), subset, pt); |
commit-bot@chromium.org | 907fbd5 | 2013-12-09 17:03:02 +0000 | [diff] [blame] | 621 | } |
Hal Canary | 6f6961e | 2017-01-31 13:50:44 -0500 | [diff] [blame] | 622 | #endif |