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
21class GrGLBitmapTextGeoProc : public GrGLSLGeometryProcessor {
22public:
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
107private:
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
122GrBitmapTextGeoProc::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
166void 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
189void GrBitmapTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
190 GrProcessorKeyBuilder* b) const {
191 GrGLBitmapTextGeoProc::GenKey(*this, caps, b);
192}
193
194GrGLSLPrimitiveProcessor* GrBitmapTextGeoProc::createGLSLInstance(const GrShaderCaps& caps) const {
195 return new GrGLBitmapTextGeoProc();
196}
197
198///////////////////////////////////////////////////////////////////////////////
199
200GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc);
201
202#if GR_TEST_UTILS
203
204GrGeometryProcessor* 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