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