1 | /* |
2 | * Copyright 2013 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 "src/gpu/effects/GrBitmapTextGeoProc.h" |
9 | |
10 | #include "src/gpu/GrCaps.h" |
11 | #include "src/gpu/GrShaderCaps.h" |
12 | #include "src/gpu/GrTexture.h" |
13 | #include "src/gpu/effects/GrAtlasedShaderHelpers.h" |
14 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
15 | #include "src/gpu/glsl/GrGLSLGeometryProcessor.h" |
16 | #include "src/gpu/glsl/GrGLSLProgramDataManager.h" |
17 | #include "src/gpu/glsl/GrGLSLUniformHandler.h" |
18 | #include "src/gpu/glsl/GrGLSLVarying.h" |
19 | #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" |
20 | |
21 | class GrGLBitmapTextGeoProc : public GrGLSLGeometryProcessor { |
22 | public: |
23 | GrGLBitmapTextGeoProc() : fColor(SK_PMColor4fILLEGAL), fAtlasDimensions{0,0} {} |
24 | |
25 | void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { |
26 | const GrBitmapTextGeoProc& btgp = args.fGP.cast<GrBitmapTextGeoProc>(); |
27 | |
28 | GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; |
29 | GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; |
30 | GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
31 | |
32 | // emit attributes |
33 | varyingHandler->emitAttributes(btgp); |
34 | |
35 | const char* atlasDimensionsInvName; |
36 | fAtlasDimensionsInvUniform = uniformHandler->addUniform(nullptr, kVertex_GrShaderFlag, |
37 | kFloat2_GrSLType, "AtlasSizeInv" , &atlasDimensionsInvName); |
38 | |
39 | GrGLSLVarying uv(kFloat2_GrSLType); |
40 | GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType; |
41 | GrGLSLVarying texIdx(texIdxType); |
42 | append_index_uv_varyings(args, btgp.numTextureSamplers(), btgp.inTextureCoords().name(), |
43 | atlasDimensionsInvName, &uv, &texIdx, nullptr); |
44 | |
45 | GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; |
46 | // Setup pass through color |
47 | if (btgp.hasVertexColor()) { |
48 | varyingHandler->addPassThroughAttribute(btgp.inColor(), args.fOutputColor); |
49 | } else { |
50 | this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, |
51 | &fColorUniform); |
52 | } |
53 | |
54 | // Setup position |
55 | gpArgs->fPositionVar = btgp.inPosition().asShaderVar(); |
56 | |
57 | // emit transforms |
58 | this->emitTransforms(vertBuilder, |
59 | varyingHandler, |
60 | uniformHandler, |
61 | btgp.inPosition().asShaderVar(), |
62 | btgp.localMatrix(), |
63 | args.fFPCoordTransformHandler); |
64 | |
65 | fragBuilder->codeAppend("half4 texColor;" ); |
66 | append_multitexture_lookup(args, btgp.numTextureSamplers(), |
67 | texIdx, uv.fsIn(), "texColor" ); |
68 | |
69 | if (btgp.maskFormat() == kARGB_GrMaskFormat) { |
70 | // modulate by color |
71 | fragBuilder->codeAppendf("%s = %s * texColor;" , args.fOutputColor, args.fOutputColor); |
72 | fragBuilder->codeAppendf("%s = half4(1);" , args.fOutputCoverage); |
73 | } else { |
74 | fragBuilder->codeAppendf("%s = texColor;" , args.fOutputCoverage); |
75 | } |
76 | } |
77 | |
78 | void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp, |
79 | const CoordTransformRange& transformRange) override { |
80 | const GrBitmapTextGeoProc& btgp = gp.cast<GrBitmapTextGeoProc>(); |
81 | if (btgp.color() != fColor && !btgp.hasVertexColor()) { |
82 | pdman.set4fv(fColorUniform, 1, btgp.color().vec()); |
83 | fColor = btgp.color(); |
84 | } |
85 | |
86 | const SkISize& atlasDimensions = btgp.atlasDimensions(); |
87 | SkASSERT(SkIsPow2(atlasDimensions.fWidth) && SkIsPow2(atlasDimensions.fHeight)); |
88 | |
89 | if (fAtlasDimensions != atlasDimensions) { |
90 | pdman.set2f(fAtlasDimensionsInvUniform, |
91 | 1.0f / atlasDimensions.fWidth, |
92 | 1.0f / atlasDimensions.fHeight); |
93 | fAtlasDimensions = atlasDimensions; |
94 | } |
95 | this->setTransformDataHelper(btgp.localMatrix(), pdman, transformRange); |
96 | } |
97 | |
98 | static inline void GenKey(const GrGeometryProcessor& proc, |
99 | const GrShaderCaps&, |
100 | GrProcessorKeyBuilder* b) { |
101 | const GrBitmapTextGeoProc& btgp = proc.cast<GrBitmapTextGeoProc>(); |
102 | uint32_t key = 0; |
103 | key |= btgp.usesW() ? 0x1 : 0x0; |
104 | key |= btgp.maskFormat() << 1; |
105 | b->add32(key); |
106 | b->add32(btgp.numTextureSamplers()); |
107 | } |
108 | |
109 | private: |
110 | SkPMColor4f fColor; |
111 | UniformHandle fColorUniform; |
112 | |
113 | SkISize fAtlasDimensions; |
114 | UniformHandle fAtlasDimensionsInvUniform; |
115 | |
116 | typedef GrGLSLGeometryProcessor INHERITED; |
117 | }; |
118 | |
119 | /////////////////////////////////////////////////////////////////////////////// |
120 | |
121 | GrBitmapTextGeoProc::GrBitmapTextGeoProc(const GrShaderCaps& caps, |
122 | const SkPMColor4f& color, |
123 | bool wideColor, |
124 | const GrSurfaceProxyView* views, |
125 | int numActiveViews, |
126 | GrSamplerState params, |
127 | GrMaskFormat format, |
128 | const SkMatrix& localMatrix, |
129 | bool usesW) |
130 | : INHERITED(kGrBitmapTextGeoProc_ClassID) |
131 | , fColor(color) |
132 | , fLocalMatrix(localMatrix) |
133 | , fUsesW(usesW) |
134 | , fMaskFormat(format) { |
135 | SkASSERT(numActiveViews <= kMaxTextures); |
136 | |
137 | if (usesW) { |
138 | fInPosition = {"inPosition" , kFloat3_GrVertexAttribType, kFloat3_GrSLType}; |
139 | } else { |
140 | fInPosition = {"inPosition" , kFloat2_GrVertexAttribType, kFloat2_GrSLType}; |
141 | } |
142 | |
143 | bool hasVertexColor = kA8_GrMaskFormat == fMaskFormat || |
144 | kA565_GrMaskFormat == fMaskFormat; |
145 | if (hasVertexColor) { |
146 | fInColor = MakeColorAttribute("inColor" , wideColor); |
147 | } |
148 | |
149 | fInTextureCoords = {"inTextureCoords" , kUShort2_GrVertexAttribType, |
150 | caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType}; |
151 | this->setVertexAttributes(&fInPosition, 3); |
152 | |
153 | if (numActiveViews) { |
154 | fAtlasDimensions = views[0].proxy()->dimensions(); |
155 | } |
156 | for (int i = 0; i < numActiveViews; ++i) { |
157 | const GrSurfaceProxy* proxy = views[i].proxy(); |
158 | SkASSERT(proxy); |
159 | SkASSERT(proxy->dimensions() == fAtlasDimensions); |
160 | fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle()); |
161 | } |
162 | this->setTextureSamplerCnt(numActiveViews); |
163 | } |
164 | |
165 | void GrBitmapTextGeoProc::addNewViews(const GrSurfaceProxyView* views, |
166 | int numActiveViews, |
167 | GrSamplerState params) { |
168 | SkASSERT(numActiveViews <= kMaxTextures); |
169 | // Just to make sure we don't try to add too many proxies |
170 | numActiveViews = std::min(numActiveViews, kMaxTextures); |
171 | |
172 | if (!fTextureSamplers[0].isInitialized()) { |
173 | fAtlasDimensions = views[0].proxy()->dimensions(); |
174 | } |
175 | |
176 | for (int i = 0; i < numActiveViews; ++i) { |
177 | const GrSurfaceProxy* proxy = views[i].proxy(); |
178 | SkASSERT(proxy); |
179 | SkASSERT(proxy->dimensions() == fAtlasDimensions); |
180 | |
181 | if (!fTextureSamplers[i].isInitialized()) { |
182 | fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle()); |
183 | } |
184 | } |
185 | this->setTextureSamplerCnt(numActiveViews); |
186 | } |
187 | |
188 | void GrBitmapTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps, |
189 | GrProcessorKeyBuilder* b) const { |
190 | GrGLBitmapTextGeoProc::GenKey(*this, caps, b); |
191 | } |
192 | |
193 | GrGLSLPrimitiveProcessor* GrBitmapTextGeoProc::createGLSLInstance(const GrShaderCaps& caps) const { |
194 | return new GrGLBitmapTextGeoProc(); |
195 | } |
196 | |
197 | /////////////////////////////////////////////////////////////////////////////// |
198 | |
199 | GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc); |
200 | |
201 | #if GR_TEST_UTILS |
202 | |
203 | GrGeometryProcessor* GrBitmapTextGeoProc::TestCreate(GrProcessorTestData* d) { |
204 | auto [view, ct, at] = d->randomView(); |
205 | |
206 | GrSamplerState::WrapMode wrapModes[2]; |
207 | GrTest::TestWrapModes(d->fRandom, wrapModes); |
208 | GrSamplerState samplerState(wrapModes, d->fRandom->nextBool() |
209 | ? GrSamplerState::Filter::kBilerp |
210 | : GrSamplerState::Filter::kNearest); |
211 | |
212 | GrMaskFormat format; |
213 | switch (ct) { |
214 | case GrColorType::kAlpha_8: |
215 | format = kA8_GrMaskFormat; |
216 | break; |
217 | case GrColorType::kBGR_565: |
218 | format = kA565_GrMaskFormat; |
219 | break; |
220 | case GrColorType::kRGBA_8888: |
221 | default: // It doesn't really matter that color type and mask format agree. |
222 | format = kARGB_GrMaskFormat; |
223 | break; |
224 | } |
225 | |
226 | return GrBitmapTextGeoProc::Make(d->allocator(), *d->caps()->shaderCaps(), |
227 | SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)), |
228 | d->fRandom->nextBool(), |
229 | &view, 1, samplerState, format, |
230 | GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); |
231 | } |
232 | #endif |
233 | |