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() : 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
109private:
110 SkPMColor4f fColor;
111 UniformHandle fColorUniform;
112
113 SkISize fAtlasDimensions;
114 UniformHandle fAtlasDimensionsInvUniform;
115
116 typedef GrGLSLGeometryProcessor INHERITED;
117};
118
119///////////////////////////////////////////////////////////////////////////////
120
121GrBitmapTextGeoProc::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
165void 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
188void GrBitmapTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
189 GrProcessorKeyBuilder* b) const {
190 GrGLBitmapTextGeoProc::GenKey(*this, caps, b);
191}
192
193GrGLSLPrimitiveProcessor* GrBitmapTextGeoProc::createGLSLInstance(const GrShaderCaps& caps) const {
194 return new GrGLBitmapTextGeoProc();
195}
196
197///////////////////////////////////////////////////////////////////////////////
198
199GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc);
200
201#if GR_TEST_UTILS
202
203GrGeometryProcessor* 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